4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
144 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
147 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
149 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
150 static void __mmplayer_release_misc(mmplayer_t *player);
151 static void __mmplayer_release_misc_post(mmplayer_t *player);
152 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
153 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
156 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
158 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
159 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
160 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
161 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
163 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
164 static gpointer __mmplayer_gapless_play_thread(gpointer data);
165 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
166 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
167 static void __mmplayer_release_dump_list(GList *dump_list);
168 static int __mmplayer_gst_realize(mmplayer_t *player);
169 static int __mmplayer_gst_unrealize(mmplayer_t *player);
170 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
171 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
174 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
175 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
176 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 /*===========================================================================================
201 | FUNCTION DEFINITIONS |
203 ========================================================================================== */
205 /* This function should be called after the pipeline goes PAUSED or higher
208 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
210 static gboolean has_duration = FALSE;
211 static gboolean has_video_attrs = FALSE;
212 static gboolean has_audio_attrs = FALSE;
213 static gboolean has_bitrate = FALSE;
214 gboolean missing_only = FALSE;
215 gboolean all = FALSE;
216 MMHandleType attrs = 0;
220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
222 /* check player state here */
223 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
224 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
225 /* give warning now only */
226 LOGW("be careful. content attributes may not available in this state ");
229 /* get content attribute first */
230 attrs = MMPLAYER_GET_ATTRS(player);
232 LOGE("cannot get content attribute");
236 /* get update flag */
238 if (flag & ATTR_MISSING_ONLY) {
240 LOGD("updating missed attr only");
243 if (flag & ATTR_ALL) {
245 has_duration = FALSE;
246 has_video_attrs = FALSE;
247 has_audio_attrs = FALSE;
250 LOGD("updating all attrs");
253 if (missing_only && all) {
254 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
255 missing_only = FALSE;
258 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
259 has_duration = __mmplayer_update_duration_value(player);
261 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
262 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
264 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
265 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
267 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
268 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
276 _mmplayer_get_stream_service_type(mmplayer_t *player)
278 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
282 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
284 player->pipeline->mainbin &&
285 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
286 STREAMING_SERVICE_NONE);
288 /* streaming service type if streaming */
289 if (!MMPLAYER_IS_STREAMING(player))
290 return STREAMING_SERVICE_NONE;
292 streaming_type = (player->duration == 0) ?
293 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
295 switch (streaming_type) {
296 case STREAMING_SERVICE_LIVE:
297 LOGD("it's live streaming");
299 case STREAMING_SERVICE_VOD:
300 LOGD("it's vod streaming");
303 LOGE("should not get here");
309 return streaming_type;
312 /* this function sets the player state and also report
313 * it to applicaton by calling callback function
316 _mmplayer_set_state(mmplayer_t *player, int state)
318 MMMessageParamType msg = {0, };
320 MMPLAYER_RETURN_IF_FAIL(player);
322 if (MMPLAYER_CURRENT_STATE(player) == state) {
323 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
328 /* update player states */
329 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
330 MMPLAYER_CURRENT_STATE(player) = state;
332 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
333 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336 MMPLAYER_PRINT_STATE(player);
338 switch (MMPLAYER_CURRENT_STATE(player)) {
339 case MM_PLAYER_STATE_NULL:
340 case MM_PLAYER_STATE_READY:
342 case MM_PLAYER_STATE_PAUSED:
343 __mmplayer_set_pause_state(player);
345 case MM_PLAYER_STATE_PLAYING:
346 __mmplayer_set_playing_state(player);
348 case MM_PLAYER_STATE_NONE:
350 LOGW("invalid target state, there is nothing to do.");
355 /* post message to application */
356 if (MMPLAYER_TARGET_STATE(player) == state) {
357 /* fill the message with state of player */
358 msg.union_type = MM_MSG_UNION_STATE;
359 msg.state.previous = MMPLAYER_PREV_STATE(player);
360 msg.state.current = MMPLAYER_CURRENT_STATE(player);
362 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
364 /* state changed by resource callback */
365 if (player->interrupted_by_resource)
366 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
367 else /* state changed by usecase */
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371 LOGD("intermediate state, do nothing.");
372 MMPLAYER_PRINT_STATE(player);
376 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
377 && !player->sent_bos) {
378 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
379 player->sent_bos = TRUE;
386 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
388 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
389 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
393 LOGD("incomming command : %d ", command);
395 current_state = MMPLAYER_CURRENT_STATE(player);
396 pending_state = MMPLAYER_PENDING_STATE(player);
398 MMPLAYER_PRINT_STATE(player);
401 case MMPLAYER_COMMAND_CREATE:
403 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
405 if (current_state == MM_PLAYER_STATE_NULL ||
406 current_state == MM_PLAYER_STATE_READY ||
407 current_state == MM_PLAYER_STATE_PAUSED ||
408 current_state == MM_PLAYER_STATE_PLAYING)
413 case MMPLAYER_COMMAND_DESTROY:
415 /* destroy can called anytime */
417 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
421 case MMPLAYER_COMMAND_REALIZE:
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
425 if (pending_state != MM_PLAYER_STATE_NONE) {
428 /* need ready state to realize */
429 if (current_state == MM_PLAYER_STATE_READY)
432 if (current_state != MM_PLAYER_STATE_NULL)
438 case MMPLAYER_COMMAND_UNREALIZE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL)
447 case MMPLAYER_COMMAND_START:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
451 if (pending_state == MM_PLAYER_STATE_NONE) {
452 if (current_state == MM_PLAYER_STATE_PLAYING)
454 else if (current_state != MM_PLAYER_STATE_READY &&
455 current_state != MM_PLAYER_STATE_PAUSED)
457 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
459 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
460 LOGD("player is going to paused state, just change the pending state as playing");
467 case MMPLAYER_COMMAND_STOP:
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
471 if (current_state == MM_PLAYER_STATE_READY)
474 /* need playing/paused state to stop */
475 if (current_state != MM_PLAYER_STATE_PLAYING &&
476 current_state != MM_PLAYER_STATE_PAUSED)
481 case MMPLAYER_COMMAND_PAUSE:
483 if (MMPLAYER_IS_LIVE_STREAMING(player))
486 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
487 goto NOT_COMPLETED_SEEK;
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PAUSED)
494 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
500 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
507 case MMPLAYER_COMMAND_RESUME:
509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
510 goto NOT_COMPLETED_SEEK;
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
514 if (pending_state == MM_PLAYER_STATE_NONE) {
515 if (current_state == MM_PLAYER_STATE_PLAYING)
517 else if (current_state != MM_PLAYER_STATE_PAUSED)
519 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
521 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
522 LOGD("player is going to paused state, just change the pending state as playing");
532 player->cmd = command;
534 return MM_ERROR_NONE;
537 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
538 MMPLAYER_STATE_GET_NAME(current_state), command);
539 return MM_ERROR_PLAYER_INVALID_STATE;
542 LOGW("not completed seek");
543 return MM_ERROR_PLAYER_DOING_SEEK;
546 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
547 return MM_ERROR_PLAYER_NO_OP;
550 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
551 return MM_ERROR_PLAYER_NO_OP;
554 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
556 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
557 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
561 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
563 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
564 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
566 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570 LOGE("invalid mmplayer resource type %d", type);
571 return MM_ERROR_PLAYER_INTERNAL;
574 if (player->hw_resource[type] != NULL) {
575 LOGD("[%d type] resource was already acquired", type);
576 return MM_ERROR_NONE;
579 LOGD("mark for acquire [%d type] resource", type);
580 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
581 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
582 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
583 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
584 return MM_ERROR_PLAYER_INTERNAL;
587 rm_ret = mm_resource_manager_commit(player->resource_manager);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
594 return MM_ERROR_NONE;
597 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 if (player->hw_resource[type] == NULL) {
604 LOGD("there is no acquired [%d type] resource", type);
605 return MM_ERROR_NONE;
608 LOGD("mark for release [%d type] resource", type);
609 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
610 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
611 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
612 return MM_ERROR_PLAYER_INTERNAL;
615 player->hw_resource[type] = NULL;
617 rm_ret = mm_resource_manager_commit(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
620 return MM_ERROR_PLAYER_INTERNAL;
624 return MM_ERROR_NONE;
628 __mmplayer_initialize_gapless_play(mmplayer_t *player)
634 player->smooth_streaming = FALSE;
635 player->videodec_linked = 0;
636 player->audiodec_linked = 0;
637 player->textsink_linked = 0;
638 player->is_external_subtitle_present = FALSE;
639 player->is_external_subtitle_added_now = FALSE;
640 player->not_supported_codec = MISSING_PLUGIN_NONE;
641 player->can_support_codec = FOUND_PLUGIN_NONE;
642 player->pending_seek.is_pending = false;
643 player->pending_seek.pos = 0;
644 player->msg_posted = FALSE;
645 player->has_many_types = FALSE;
646 player->no_more_pad = FALSE;
647 player->not_found_demuxer = 0;
648 player->seek_state = MMPLAYER_SEEK_NONE;
649 player->is_subtitle_force_drop = FALSE;
650 player->play_subtitle = FALSE;
651 player->adjust_subtitle_pos = 0;
653 player->total_bitrate = 0;
654 player->total_maximum_bitrate = 0;
656 _mmplayer_track_initialize(player);
657 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
659 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
660 player->bitrate[i] = 0;
661 player->maximum_bitrate[i] = 0;
664 if (player->v_stream_caps) {
665 gst_caps_unref(player->v_stream_caps);
666 player->v_stream_caps = NULL;
669 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
671 /* clean found audio decoders */
672 if (player->audio_decoders) {
673 GList *a_dec = player->audio_decoders;
674 for (; a_dec; a_dec = g_list_next(a_dec)) {
675 gchar *name = a_dec->data;
676 MMPLAYER_FREEIF(name);
678 g_list_free(player->audio_decoders);
679 player->audio_decoders = NULL;
682 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
687 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
689 LOGI("set pipeline reconfigure state %d", state);
690 MMPLAYER_RECONFIGURE_LOCK(player);
691 player->gapless.reconfigure = state;
692 if (!state) /* wake up the waiting job */
693 MMPLAYER_RECONFIGURE_SIGNAL(player);
694 MMPLAYER_RECONFIGURE_UNLOCK(player);
698 __mmplayer_gapless_play_thread(gpointer data)
700 mmplayer_t *player = (mmplayer_t *)data;
701 mmplayer_gst_element_t *mainbin = NULL;
703 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
705 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
706 while (!player->gapless_play_thread_exit) {
707 LOGD("gapless play thread started. waiting for signal.");
708 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
710 LOGD("reconfigure pipeline for gapless play.");
712 if (player->gapless_play_thread_exit) {
713 _mmplayer_set_reconfigure_state(player, FALSE);
714 LOGD("exiting gapless play thread");
718 mainbin = player->pipeline->mainbin;
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
726 /* Initialize Player values */
727 __mmplayer_initialize_gapless_play(player);
729 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
739 GSource *source = NULL;
743 source = g_main_context_find_source_by_id(context, source_id);
744 if (source != NULL) {
745 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
746 g_source_destroy(source);
753 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
755 mmplayer_t *player = (mmplayer_t *)hplayer;
756 GstMessage *msg = NULL;
757 GQueue *queue = NULL;
760 MMPLAYER_RETURN_IF_FAIL(player);
762 /* disconnecting bus watch */
763 if (player->bus_watcher)
764 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
765 player->bus_watcher = 0;
767 /* destroy the gst bus msg thread */
768 if (player->bus_msg_thread) {
769 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
770 player->bus_msg_thread_exit = TRUE;
771 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
772 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
774 LOGD("gst bus msg thread exit.");
775 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
776 player->bus_msg_thread = NULL;
778 g_mutex_clear(&player->bus_msg_thread_mutex);
779 g_cond_clear(&player->bus_msg_thread_cond);
782 g_mutex_lock(&player->bus_msg_q_lock);
783 queue = player->bus_msg_q;
784 while (!g_queue_is_empty(queue)) {
785 msg = (GstMessage *)g_queue_pop_head(queue);
790 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
791 gst_message_unref(msg);
793 g_mutex_unlock(&player->bus_msg_q_lock);
799 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
801 GstElement *parent = NULL;
803 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
804 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
807 MMPLAYER_FSINK_LOCK(player);
809 /* get parent of fakesink */
810 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
812 LOGD("fakesink already removed");
816 gst_element_set_locked_state(fakesink->gst, TRUE);
818 /* setting the state to NULL never returns async
819 * so no need to wait for completion of state transiton
821 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
822 LOGE("fakesink state change failure!");
823 /* FIXIT : should I return here? or try to proceed to next? */
826 /* remove fakesink from it's parent */
827 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
828 LOGE("failed to remove fakesink");
830 gst_object_unref(parent);
835 gst_object_unref(parent);
837 LOGD("state-holder removed");
839 gst_element_set_locked_state(fakesink->gst, FALSE);
841 MMPLAYER_FSINK_UNLOCK(player);
846 gst_element_set_locked_state(fakesink->gst, FALSE);
848 MMPLAYER_FSINK_UNLOCK(player);
852 static GstPadProbeReturn
853 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
855 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
856 return GST_PAD_PROBE_OK;
860 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
862 gint64 stop_running_time = 0;
863 gint64 position_running_time = 0;
867 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
868 if ((player->gapless.update_segment[idx] == TRUE) ||
869 !(player->track[idx].event_probe_id)) {
871 LOGW("[%d] skip", idx);
876 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
878 gst_segment_to_running_time(&player->gapless.segment[idx],
879 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
880 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
882 gst_segment_to_running_time(&player->gapless.segment[idx],
883 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
885 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
887 gst_segment_to_running_time(&player->gapless.segment[idx],
888 GST_FORMAT_TIME, player->duration);
891 position_running_time =
892 gst_segment_to_running_time(&player->gapless.segment[idx],
893 GST_FORMAT_TIME, player->gapless.segment[idx].position);
895 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
896 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
898 GST_TIME_ARGS(stop_running_time),
899 GST_TIME_ARGS(position_running_time),
900 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
901 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
903 position_running_time = MAX(position_running_time, stop_running_time);
904 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].start);
906 position_running_time = MAX(0, position_running_time);
907 position = MAX(position, position_running_time);
911 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
912 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
913 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
915 player->gapless.start_time[stream_type] += position;
921 static GstPadProbeReturn
922 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
925 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
926 mmplayer_t *player = (mmplayer_t *)data;
927 GstCaps *caps = NULL;
928 GstStructure *str = NULL;
929 const gchar *name = NULL;
930 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
931 gboolean caps_ret = TRUE;
933 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
934 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
935 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
936 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
937 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
940 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
944 if (strstr(name, "audio")) {
945 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
946 } else if (strstr(name, "video")) {
947 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
949 /* text track is not supportable */
950 LOGE("invalid name %s", name);
954 switch (GST_EVENT_TYPE(event)) {
957 /* in case of gapless, drop eos event not to send it to sink */
958 if (player->gapless.reconfigure && !player->msg_posted) {
959 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
960 ret = GST_PAD_PROBE_DROP;
964 case GST_EVENT_STREAM_START:
966 __mmplayer_gst_selector_update_start_time(player, stream_type);
969 case GST_EVENT_FLUSH_STOP:
971 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
972 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
973 player->gapless.start_time[stream_type] = 0;
976 case GST_EVENT_SEGMENT:
981 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
982 gst_event_copy_segment(event, &segment);
984 if (segment.format != GST_FORMAT_TIME)
987 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
988 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
989 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
990 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
991 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
992 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
994 /* keep the all the segment ev to cover the seeking */
995 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
996 player->gapless.update_segment[stream_type] = TRUE;
998 if (!player->gapless.running)
1001 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1003 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1005 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1006 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1007 gst_event_unref(event);
1008 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1014 gdouble proportion = 0.0;
1015 GstClockTimeDiff diff = 0;
1016 GstClockTime timestamp = 0;
1017 gint64 running_time_diff = -1;
1018 GstQOSType type = 0;
1019 GstEvent *tmpev = NULL;
1021 running_time_diff = player->gapless.segment[stream_type].base;
1023 if (running_time_diff <= 0) /* don't need to adjust */
1026 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1027 gst_event_unref(event);
1029 if (timestamp < running_time_diff) {
1030 LOGW("QOS event from previous group");
1031 ret = GST_PAD_PROBE_DROP;
1036 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1037 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1038 stream_type, GST_TIME_ARGS(timestamp),
1039 GST_TIME_ARGS(running_time_diff),
1040 GST_TIME_ARGS(timestamp - running_time_diff));
1043 timestamp -= running_time_diff;
1045 /* That case is invalid for QoS events */
1046 if (diff < 0 && -diff > timestamp) {
1047 LOGW("QOS event from previous group");
1048 ret = GST_PAD_PROBE_DROP;
1052 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1053 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1063 gst_caps_unref(caps);
1067 /* create fakesink for audio or video path witout audiobin or videobin */
1069 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1071 GstElement *pipeline = NULL;
1072 GstElement *fakesink = NULL;
1073 GstPad *sinkpad = NULL;
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1081 fakesink = gst_element_factory_make("fakesink", NULL);
1082 if (fakesink == NULL) {
1083 LOGE("failed to create fakesink");
1087 /* store it as it's sink element */
1088 __mmplayer_add_sink(player, fakesink);
1090 gst_bin_add(GST_BIN(pipeline), fakesink);
1093 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1095 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1097 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1098 LOGE("failed to link fakesink");
1099 gst_object_unref(GST_OBJECT(fakesink));
1103 if (strstr(name, "video")) {
1104 if (player->v_stream_caps) {
1105 gst_caps_unref(player->v_stream_caps);
1106 player->v_stream_caps = NULL;
1108 if (player->ini.set_dump_element_flag)
1109 __mmplayer_add_dump_buffer_probe(player, fakesink);
1112 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1113 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1117 gst_object_unref(GST_OBJECT(sinkpad));
1124 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1126 GstElement *pipeline = NULL;
1127 GstElement *selector = NULL;
1128 GstPad *srcpad = NULL;
1131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1133 selector = gst_element_factory_make("input-selector", NULL);
1135 LOGE("failed to create input-selector");
1138 g_object_set(selector, "sync-streams", TRUE, NULL);
1140 player->pipeline->mainbin[elem_idx].id = elem_idx;
1141 player->pipeline->mainbin[elem_idx].gst = selector;
1143 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1145 srcpad = gst_element_get_static_pad(selector, "src");
1147 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1148 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1149 __mmplayer_gst_selector_blocked, NULL, NULL);
1150 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1151 __mmplayer_gst_selector_event_probe, player, NULL);
1153 gst_element_set_state(selector, GST_STATE_PAUSED);
1155 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1156 gst_bin_add(GST_BIN(pipeline), selector);
1158 gst_object_unref(GST_OBJECT(srcpad));
1165 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1167 mmplayer_t *player = (mmplayer_t *)data;
1168 GstElement *selector = NULL;
1169 GstCaps *caps = NULL;
1170 GstStructure *str = NULL;
1171 const gchar *name = NULL;
1172 GstPad *sinkpad = NULL;
1173 gboolean first_track = FALSE;
1174 gboolean caps_ret = TRUE;
1176 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1177 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1180 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1181 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1183 LOGD("pad-added signal handling");
1185 /* get mimetype from caps */
1186 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1190 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1192 LOGD("detected mimetype : %s", name);
1195 if (strstr(name, "video")) {
1197 gchar *caps_str = NULL;
1199 caps_str = gst_caps_to_string(caps);
1200 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1201 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1202 player->set_mode.video_zc = true;
1204 MMPLAYER_FREEIF(caps_str);
1206 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1209 LOGD("surface type : %d", stype);
1211 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player)) {
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 /* in case of exporting video frame, it requires the 360 video filter.
1217 * it will be handled in _no_more_pads(). */
1218 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1219 __mmplayer_gst_make_fakesink(player, pad, name);
1223 LOGD("video selector is required");
1224 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1225 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1226 } else if (strstr(name, "audio")) {
1227 gint samplerate = 0;
1230 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player) || player->build_audio_offload) {
1231 if (player->build_audio_offload)
1232 player->no_more_pad = TRUE; /* remove state holder */
1233 __mmplayer_gst_create_sinkbin(elem, pad, player);
1237 gst_structure_get_int(str, "rate", &samplerate);
1238 gst_structure_get_int(str, "channels", &channels);
1240 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1241 __mmplayer_gst_make_fakesink(player, pad, name);
1245 LOGD("audio selector is required");
1246 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1247 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1249 } else if (strstr(name, "text")) {
1250 LOGD("text selector is required");
1251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1254 LOGE("invalid caps info");
1258 /* check selector and create it */
1259 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1260 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1265 LOGD("input-selector is already created.");
1269 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1271 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1273 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1274 LOGE("failed to link selector");
1275 gst_object_unref(GST_OBJECT(selector));
1280 LOGD("this track will be activated");
1281 g_object_set(selector, "active-pad", sinkpad, NULL);
1284 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1285 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1291 gst_caps_unref(caps);
1294 gst_object_unref(GST_OBJECT(sinkpad));
1302 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1304 GstPad *srcpad = NULL;
1307 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1309 LOGD("type %d", type);
1312 LOGD("there is no %d track", type);
1316 srcpad = gst_element_get_static_pad(selector, "src");
1318 LOGE("failed to get srcpad from selector");
1322 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1324 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1326 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1327 if (player->track[type].block_id) {
1328 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1329 player->track[type].block_id = 0;
1333 gst_object_unref(GST_OBJECT(srcpad));
1342 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1344 gint active_index = 0;
1347 MMPLAYER_RETURN_IF_FAIL(player);
1349 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1351 /* change track to active pad */
1352 active_index = player->track[type].active_track_index;
1353 if ((active_index != DEFAULT_TRACK) &&
1354 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1355 LOGW("failed to change %d type track to %d", type, active_index);
1356 player->track[type].active_track_index = DEFAULT_TRACK;
1360 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1361 mm_player_set_attribute((MMHandleType)player, NULL,
1362 "content_text_track_num", player->track[type].total_track_num,
1363 "current_text_track_index", player->track[type].active_track_index, NULL);
1370 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1373 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1375 if (!audio_selector) {
1376 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1378 /* in case the source is changed, output can be changed. */
1379 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1380 LOGD("remove previous audiobin if it exist");
1382 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1383 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1385 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1386 MMPLAYER_FREEIF(player->pipeline->audiobin);
1389 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1390 _mmplayer_pipeline_complete(NULL, player);
1395 /* apply the audio track information */
1396 if (!MMPLAYER_USE_URIDECODEBIN3(player))
1397 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1399 /* create audio sink path */
1400 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1401 LOGE("failed to create audio sink path");
1410 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1413 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1415 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1416 LOGD("text path is not supproted");
1420 /* apply the text track information */
1421 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1423 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1424 player->has_closed_caption = TRUE;
1426 /* create text decode path */
1427 player->no_more_pad = TRUE;
1429 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1430 LOGE("failed to create text sink path");
1439 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1441 gint64 dur_bytes = 0L;
1444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1445 player->pipeline->mainbin && player->streamer, FALSE);
1447 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1448 LOGE("fail to get duration.");
1450 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1451 * use file information was already set on Q2 when it was created. */
1452 _mm_player_streaming_set_queue2(player->streamer,
1453 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1454 TRUE, /* use_buffering */
1455 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1456 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1463 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1465 mmplayer_t *player = NULL;
1466 GstElement *video_selector = NULL;
1467 GstElement *audio_selector = NULL;
1468 GstElement *text_selector = NULL;
1471 player = (mmplayer_t *)data;
1473 LOGD("no-more-pad signal handling");
1475 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1476 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1477 LOGW("player is shutting down");
1481 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1482 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1483 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1484 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1485 LOGE("failed to set queue2 buffering");
1490 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1491 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1492 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1494 if (!video_selector && !audio_selector && !text_selector) {
1495 LOGW("there is no selector");
1496 player->no_more_pad = TRUE;
1500 /* create video path followed by video-select */
1501 if (video_selector && !audio_selector && !text_selector)
1502 player->no_more_pad = TRUE;
1504 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1507 /* create audio path followed by audio-select */
1508 if (audio_selector && !text_selector)
1509 player->no_more_pad = TRUE;
1511 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1514 /* create text path followed by text-select */
1515 __mmplayer_create_text_sink_path(player, text_selector);
1518 _mmplayer_set_reconfigure_state(player, FALSE);
1523 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1525 gboolean ret = FALSE;
1526 GstElement *pipeline = NULL;
1527 GstPad *sinkpad = NULL;
1530 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1531 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1533 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1535 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1537 LOGE("failed to get pad from sinkbin");
1543 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1544 LOGE("failed to link sinkbin for reusing");
1545 goto EXIT; /* exit either pass or fail */
1549 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1550 LOGE("failed to set state(READY) to sinkbin");
1555 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1556 LOGE("failed to add sinkbin to pipeline");
1561 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1562 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1567 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1568 LOGE("failed to set state(PAUSED) to sinkbin");
1577 gst_object_unref(GST_OBJECT(sinkpad));
1585 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1587 mmplayer_t *player = NULL;
1588 GstCaps *caps = NULL;
1589 gchar *caps_str = NULL;
1590 GstStructure *str = NULL;
1591 const gchar *name = NULL;
1592 GstElement *sinkbin = NULL;
1593 gboolean reusing = FALSE;
1594 gboolean caps_ret = TRUE;
1595 gchar *sink_pad_name = "sink";
1598 player = (mmplayer_t *)data;
1601 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1602 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1604 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1608 caps_str = gst_caps_to_string(caps);
1610 LOGD("detected mimetype : %s", name);
1612 if (strstr(name, "audio")) {
1613 if (player->pipeline->audiobin == NULL) {
1614 const gchar *audio_format = gst_structure_get_string(str, "format");
1616 LOGD("original audio format %s", audio_format);
1617 mm_player_set_attribute((MMHandleType)player, NULL,
1618 "content_audio_format", audio_format, strlen(audio_format), NULL);
1621 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1622 LOGE("failed to create audiobin. continuing without audio");
1626 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1627 LOGD("creating audiobin success");
1630 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1631 LOGD("reusing audiobin");
1632 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1634 } else if (strstr(name, "video")) {
1635 /* 1. zero copy is updated at _decode_pad_added()
1636 * 2. NULL surface type is handled in _decode_pad_added() */
1637 LOGD("zero copy %d", player->set_mode.video_zc);
1638 if (player->pipeline->videobin == NULL) {
1639 int surface_type = 0;
1640 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1641 LOGD("display_surface_type (%d)", surface_type);
1643 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1644 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1645 LOGE("failed to acquire video overlay resource");
1649 player->interrupted_by_resource = FALSE;
1651 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1652 LOGE("failed to create videobin. continuing without video");
1656 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1657 LOGD("creating videosink bin success");
1660 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1661 LOGD("re-using videobin");
1662 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1664 } else if (strstr(name, "text")) {
1665 if (player->pipeline->textbin == NULL) {
1666 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1667 LOGE("failed to create text sink bin. continuing without text");
1671 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1672 player->textsink_linked = 1;
1673 LOGD("creating textsink bin success");
1675 if (!player->textsink_linked) {
1676 LOGD("re-using textbin");
1678 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1679 player->textsink_linked = 1;
1681 /* linked textbin exist which means that the external subtitle path exist already */
1682 LOGW("ignoring internal subtutle since external subtitle is available");
1685 sink_pad_name = "text_sink";
1687 LOGW("unknown mime type %s, ignoring it", name);
1691 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1694 LOGD("[handle: %p] success to create and link sink bin", player);
1696 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1697 * streaming task. if the task blocked, then buffer will not flow to the next element
1698 *(autoplugging element). so this is special hack for streaming. please try to remove it
1700 /* dec stream count. we can remove fakesink if it's zero */
1701 if (player->num_dynamic_pad)
1702 player->num_dynamic_pad--;
1704 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1706 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1707 _mmplayer_pipeline_complete(NULL, player);
1711 MMPLAYER_FREEIF(caps_str);
1714 gst_caps_unref(caps);
1720 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1722 int required_angle = 0; /* Angle required for straight view */
1723 int rotation_angle = 0;
1725 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1726 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1728 /* Counter clockwise */
1729 switch (orientation) {
1734 required_angle = 270;
1737 required_angle = 180;
1740 required_angle = 90;
1744 rotation_angle = display_angle + required_angle;
1745 if (rotation_angle >= 360)
1746 rotation_angle -= 360;
1748 /* chech if supported or not */
1749 if (rotation_angle % 90) {
1750 LOGD("not supported rotation angle = %d", rotation_angle);
1754 switch (rotation_angle) {
1756 *value = MM_DISPLAY_ROTATION_NONE;
1759 *value = MM_DISPLAY_ROTATION_90;
1762 *value = MM_DISPLAY_ROTATION_180;
1765 *value = MM_DISPLAY_ROTATION_270;
1769 LOGD("setting rotation property value : %d", *value);
1775 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1777 int display_rotation = 0;
1778 gchar *org_orient = NULL;
1779 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1782 LOGE("cannot get content attribute");
1783 return MM_ERROR_PLAYER_INTERNAL;
1786 if (display_angle) {
1787 /* update user roation */
1788 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1790 /* Counter clockwise */
1791 switch (display_rotation) {
1792 case MM_DISPLAY_ROTATION_NONE:
1795 case MM_DISPLAY_ROTATION_90:
1796 *display_angle = 90;
1798 case MM_DISPLAY_ROTATION_180:
1799 *display_angle = 180;
1801 case MM_DISPLAY_ROTATION_270:
1802 *display_angle = 270;
1805 LOGW("wrong angle type : %d", display_rotation);
1808 LOGD("check user angle: %d", *display_angle);
1812 /* Counter clockwise */
1813 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1816 if (!strcmp(org_orient, "rotate-90"))
1818 else if (!strcmp(org_orient, "rotate-180"))
1820 else if (!strcmp(org_orient, "rotate-270"))
1823 LOGD("original rotation is %s", org_orient);
1825 LOGD("content_video_orientation get fail");
1828 LOGD("check orientation: %d", *orientation);
1831 return MM_ERROR_NONE;
1834 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1836 int rotation_value = 0;
1837 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1838 int display_angle = 0;
1841 /* check video sinkbin is created */
1842 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1845 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1847 /* get rotation value to set */
1848 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1849 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1850 LOGD("set video param : rotate %d", rotation_value);
1853 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1855 MMHandleType attrs = 0;
1859 /* check video sinkbin is created */
1860 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1863 attrs = MMPLAYER_GET_ATTRS(player);
1864 MMPLAYER_RETURN_IF_FAIL(attrs);
1866 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1867 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1868 LOGD("set video param : visible %d", visible);
1871 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1873 MMHandleType attrs = 0;
1874 int display_method = 0;
1877 /* check video sinkbin is created */
1878 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1881 attrs = MMPLAYER_GET_ATTRS(player);
1882 MMPLAYER_RETURN_IF_FAIL(attrs);
1884 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1885 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1886 LOGD("set video param : method %d", display_method);
1889 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1891 MMHandleType attrs = 0;
1895 /* check video sinkbin is created */
1896 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1899 attrs = MMPLAYER_GET_ATTRS(player);
1900 MMPLAYER_RETURN_IF_FAIL(attrs);
1902 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1903 MMPLAYER_RETURN_IF_FAIL(handle);
1905 gst_video_overlay_set_video_roi_area(
1906 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1907 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1908 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1912 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1914 MMHandleType attrs = 0;
1919 int win_roi_width = 0;
1920 int win_roi_height = 0;
1923 /* check video sinkbin is created */
1924 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1927 attrs = MMPLAYER_GET_ATTRS(player);
1928 MMPLAYER_RETURN_IF_FAIL(attrs);
1930 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1931 MMPLAYER_RETURN_IF_FAIL(handle);
1933 /* It should be set after setting window */
1934 mm_attrs_multiple_get(attrs, NULL,
1935 "display_win_roi_x", &win_roi_x,
1936 "display_win_roi_y", &win_roi_y,
1937 "display_win_roi_width", &win_roi_width,
1938 "display_win_roi_height", &win_roi_height, NULL);
1940 /* After setting window handle, set display roi area */
1941 gst_video_overlay_set_display_roi_area(
1942 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1943 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1944 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1945 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1948 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1950 MMHandleType attrs = 0;
1953 /* check video sinkbin is created */
1954 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1957 attrs = MMPLAYER_GET_ATTRS(player);
1958 MMPLAYER_RETURN_IF_FAIL(attrs);
1960 /* common case if using overlay surface */
1961 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1962 MMPLAYER_RETURN_IF_FAIL(handle);
1964 /* default is using wl_surface_id */
1965 LOGD("set video param : wl_surface_id %d", handle);
1966 gst_video_overlay_set_wl_window_wl_surface_id(
1967 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1972 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1974 gboolean update_all_param = FALSE;
1978 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1979 LOGW("videosink is not ready yet");
1980 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1983 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1984 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1985 return MM_ERROR_PLAYER_INTERNAL;
1988 LOGD("param_name : %s", param_name);
1989 if (!g_strcmp0(param_name, "update_all_param"))
1990 update_all_param = TRUE;
1992 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1993 __mmplayer_video_param_set_display_overlay(player);
1994 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1995 __mmplayer_video_param_set_display_method(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1997 __mmplayer_video_param_set_display_visible(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1999 __mmplayer_video_param_set_display_rotation(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2001 __mmplayer_video_param_set_roi_area(player);
2002 if (update_all_param)
2003 __mmplayer_video_param_set_video_roi_area(player);
2007 return MM_ERROR_NONE;
2011 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2013 gboolean disable_overlay = FALSE;
2014 mmplayer_t *player = (mmplayer_t *)hplayer;
2017 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2018 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2019 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2020 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2022 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2023 LOGW("Display control is not supported");
2024 return MM_ERROR_PLAYER_INTERNAL;
2027 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2029 if (audio_only == (bool)disable_overlay) {
2030 LOGE("It's the same with current setting: (%d)", audio_only);
2031 return MM_ERROR_NONE;
2035 LOGE("disable overlay");
2036 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2038 /* release overlay resource */
2039 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2040 LOGE("failed to release overlay resource");
2044 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2045 LOGE("failed to acquire video overlay resource");
2048 player->interrupted_by_resource = FALSE;
2050 LOGD("enable overlay");
2051 __mmplayer_video_param_set_display_overlay(player);
2052 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2057 return MM_ERROR_NONE;
2061 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2063 mmplayer_t *player = (mmplayer_t *)hplayer;
2064 gboolean disable_overlay = FALSE;
2068 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2069 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2070 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2071 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2072 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2074 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2075 LOGW("Display control is not supported");
2076 return MM_ERROR_PLAYER_INTERNAL;
2079 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2081 *paudio_only = (bool)disable_overlay;
2083 LOGD("audio_only : %d", *paudio_only);
2087 return MM_ERROR_NONE;
2091 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2093 GList *bucket = element_bucket;
2094 mmplayer_gst_element_t *element = NULL;
2095 mmplayer_gst_element_t *prv_element = NULL;
2096 GstElement *tee_element = NULL;
2097 gint successful_link_count = 0;
2101 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2103 prv_element = (mmplayer_gst_element_t *)bucket->data;
2104 bucket = bucket->next;
2106 for (; bucket; bucket = bucket->next) {
2107 element = (mmplayer_gst_element_t *)bucket->data;
2109 if (element && element->gst) {
2110 if (prv_element && prv_element->gst) {
2111 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2113 prv_element->gst = tee_element;
2115 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2116 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2117 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2121 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2122 LOGD("linking [%s] to [%s] success",
2123 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2124 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2125 successful_link_count++;
2126 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2127 LOGD("keep audio-tee element for next audio pipeline branch");
2128 tee_element = prv_element->gst;
2131 LOGD("linking [%s] to [%s] failed",
2132 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2133 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2139 prv_element = element;
2144 return successful_link_count;
2148 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2150 GList *bucket = element_bucket;
2151 mmplayer_gst_element_t *element = NULL;
2152 int successful_add_count = 0;
2156 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2157 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2159 for (; bucket; bucket = bucket->next) {
2160 element = (mmplayer_gst_element_t *)bucket->data;
2162 if (element && element->gst) {
2163 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2164 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2165 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2166 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2169 successful_add_count++;
2175 return successful_add_count;
2179 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2181 mmplayer_t *player = (mmplayer_t *)data;
2182 GstCaps *caps = NULL;
2183 GstStructure *str = NULL;
2185 gboolean caps_ret = TRUE;
2189 MMPLAYER_RETURN_IF_FAIL(pad);
2190 MMPLAYER_RETURN_IF_FAIL(unused);
2191 MMPLAYER_RETURN_IF_FAIL(data);
2193 caps = gst_pad_get_current_caps(pad);
2197 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2201 LOGD("name = %s", name);
2203 if (strstr(name, "audio")) {
2204 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2206 if (player->audio_stream_changed_cb) {
2207 LOGE("call the audio stream changed cb");
2208 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2210 } else if (strstr(name, "video")) {
2211 if ((name = gst_structure_get_string(str, "format")))
2212 player->set_mode.video_zc = name[0] == 'S';
2214 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2215 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2217 LOGW("invalid caps info");
2222 gst_caps_unref(caps);
2230 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2235 MMPLAYER_RETURN_IF_FAIL(player);
2237 if (player->audio_stream_buff_list) {
2238 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2239 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2242 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2243 __mmplayer_audio_stream_send_data(player, tmp);
2245 MMPLAYER_FREEIF(tmp->pcm_data);
2246 MMPLAYER_FREEIF(tmp);
2249 g_list_free(player->audio_stream_buff_list);
2250 player->audio_stream_buff_list = NULL;
2257 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2259 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2262 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2264 audio_stream.bitrate = a_buffer->bitrate;
2265 audio_stream.channel = a_buffer->channel;
2266 audio_stream.channel_mask = a_buffer->channel_mask;
2267 audio_stream.data_size = a_buffer->data_size;
2268 audio_stream.data = a_buffer->pcm_data;
2269 audio_stream.pcm_format = a_buffer->pcm_format;
2271 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2273 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2279 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2281 mmplayer_t *player = (mmplayer_t *)data;
2282 const gchar *pcm_format = NULL;
2285 guint64 channel_mask = 0;
2286 void *a_data = NULL;
2288 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2289 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2293 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2295 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2296 a_data = mapinfo.data;
2297 a_size = mapinfo.size;
2299 GstCaps *caps = gst_pad_get_current_caps(pad);
2300 GstStructure *structure = gst_caps_get_structure(caps, 0);
2302 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2304 pcm_format = gst_structure_get_string(structure, "format");
2305 gst_structure_get_int(structure, "rate", &rate);
2306 gst_structure_get_int(structure, "channels", &channel);
2307 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2308 gst_caps_unref(GST_CAPS(caps));
2310 /* In case of the sync is false, use buffer list. *
2311 * The num of buffer list depends on the num of audio channels */
2312 if (player->audio_stream_buff_list) {
2313 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2314 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2316 if (channel_mask == tmp->channel_mask) {
2318 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2320 if (tmp->data_size + a_size < tmp->buff_size) {
2321 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2322 tmp->data_size += a_size;
2324 /* send data to client */
2325 __mmplayer_audio_stream_send_data(player, tmp);
2327 if (a_size > tmp->buff_size) {
2328 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2329 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2330 if (tmp->pcm_data == NULL) {
2331 LOGE("failed to realloc data.");
2334 tmp->buff_size = a_size;
2336 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2337 memcpy(tmp->pcm_data, a_data, a_size);
2338 tmp->data_size = a_size;
2343 LOGE("data is empty in list.");
2349 /* create new audio stream data for newly found audio channel */
2350 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2351 if (a_buffer == NULL) {
2352 LOGE("failed to alloc data.");
2355 a_buffer->bitrate = rate;
2356 a_buffer->channel = channel;
2357 a_buffer->channel_mask = channel_mask;
2358 a_buffer->data_size = a_size;
2359 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2361 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2362 /* If sync is FALSE, use buffer list to reduce the IPC. */
2363 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2364 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2365 if (a_buffer->pcm_data == NULL) {
2366 LOGE("failed to alloc data.");
2367 MMPLAYER_FREEIF(a_buffer);
2370 memcpy(a_buffer->pcm_data, a_data, a_size);
2372 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2374 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2376 /* If sync is TRUE, send data directly. */
2377 a_buffer->pcm_data = a_data;
2378 __mmplayer_audio_stream_send_data(player, a_buffer);
2379 MMPLAYER_FREEIF(a_buffer);
2383 gst_buffer_unmap(buffer, &mapinfo);
2388 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2390 mmplayer_t *player = (mmplayer_t *)data;
2391 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2392 GstPad *sinkpad = NULL;
2393 GstElement *queue = NULL, *sink = NULL;
2396 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2398 queue = gst_element_factory_make("queue", NULL);
2399 if (queue == NULL) {
2400 LOGD("fail make queue");
2404 sink = gst_element_factory_make("fakesink", NULL);
2406 LOGD("fail make fakesink");
2410 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2412 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2413 LOGW("failed to link queue & sink");
2417 sinkpad = gst_element_get_static_pad(queue, "sink");
2419 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2420 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2424 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2426 gst_object_unref(sinkpad);
2427 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2428 g_object_set(sink, "sync", TRUE, NULL);
2429 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2431 /* keep the first sink reference only */
2432 if (!audiobin[MMPLAYER_A_SINK].gst) {
2433 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2434 audiobin[MMPLAYER_A_SINK].gst = sink;
2438 _mmplayer_add_signal_connection(player,
2440 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2442 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2445 __mmplayer_add_sink(player, sink);
2447 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2448 LOGE("failed to sync state");
2452 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2453 LOGE("failed to sync state");
2461 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2463 gst_object_unref(GST_OBJECT(queue));
2467 gst_object_unref(GST_OBJECT(sink));
2471 gst_object_unref(GST_OBJECT(sinkpad));
2479 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2481 mmplayer_t *player = (mmplayer_t *)data;
2484 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2486 player->no_more_pad = TRUE;
2487 _mmplayer_pipeline_complete(NULL, player);
2494 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2496 #define MAX_PROPS_LEN 128
2497 mmplayer_gst_element_t *audiobin = NULL;
2498 gint latency_mode = 0;
2499 gchar *stream_type = NULL;
2500 gchar *latency = NULL;
2502 gchar stream_props[MAX_PROPS_LEN] = {0,};
2503 GstStructure *props = NULL;
2506 * It should be set after player creation through attribute.
2507 * But, it can not be changed during playing.
2510 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2512 audiobin = player->pipeline->audiobin;
2514 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2515 if (player->sound.mute) {
2516 LOGD("mute enabled");
2517 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2520 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2521 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2524 snprintf(stream_props, sizeof(stream_props) - 1,
2525 "props,application.process.id.origin=%d", player->client_pid);
2527 snprintf(stream_props, sizeof(stream_props) - 1,
2528 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2529 stream_type, stream_id, player->client_pid);
2531 props = gst_structure_from_string(stream_props, NULL);
2532 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2533 LOGI("props result[%s].", stream_props);
2534 gst_structure_free(props);
2536 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2538 switch (latency_mode) {
2539 case AUDIO_LATENCY_MODE_LOW:
2540 latency = g_strdup("low");
2542 case AUDIO_LATENCY_MODE_MID:
2543 latency = g_strdup("mid");
2545 case AUDIO_LATENCY_MODE_HIGH:
2546 latency = g_strdup("high");
2549 latency = g_strdup("mid");
2553 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2555 LOGD("audiosink property - latency=%s", latency);
2557 MMPLAYER_FREEIF(latency);
2563 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2565 mmplayer_gst_element_t *audiobin = NULL;
2568 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2569 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2571 audiobin = player->pipeline->audiobin;
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2574 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2575 LOGE("failed to create media stream info");
2576 return MM_ERROR_PLAYER_INTERNAL;
2579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2581 if (player->video360_yaw_radians <= M_PI &&
2582 player->video360_yaw_radians >= -M_PI &&
2583 player->video360_pitch_radians <= M_PI_2 &&
2584 player->video360_pitch_radians >= -M_PI_2) {
2585 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2586 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2587 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2588 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2589 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2590 "source-orientation-y", player->video360_metadata.init_view_heading,
2591 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2595 return MM_ERROR_NONE;
2599 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2601 mmplayer_gst_element_t *audiobin = NULL;
2602 GstPad *sink_pad = NULL;
2603 GstCaps *acaps = NULL;
2605 int pitch_control = 0;
2606 double pitch_value = 1.0;
2609 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2610 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2612 audiobin = player->pipeline->audiobin;
2614 LOGD("make element for normal audio playback");
2616 /* audio bin structure for playback. {} means optional.
2617 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2619 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2620 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2623 /* for pitch control */
2624 mm_attrs_multiple_get(player->attrs, NULL,
2625 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2626 MM_PLAYER_PITCH_VALUE, &pitch_value,
2629 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2630 if (pitch_control && (player->videodec_linked == 0)) {
2631 GstElementFactory *factory;
2633 factory = gst_element_factory_find("pitch");
2635 gst_object_unref(factory);
2638 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2642 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2644 LOGW("there is no pitch element");
2649 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2651 /* replaygain volume */
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2653 if (player->sound.rg_enable)
2654 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2661 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2662 /* currently, only openalsink uses volume element */
2663 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2664 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2666 if (player->sound.mute) {
2667 LOGD("mute enabled");
2668 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2672 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2674 /* audio effect element. if audio effect is enabled */
2675 if ((strcmp(player->ini.audioeffect_element, ""))
2677 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2678 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2680 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2682 if ((!player->bypass_audio_effect)
2683 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2684 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2685 if (!_mmplayer_audio_effect_custom_apply(player))
2686 LOGI("apply audio effect(custom) setting success");
2690 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2691 && (player->set_mode.rich_audio)) {
2692 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2696 /* create audio sink */
2697 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2698 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2699 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2701 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2702 if (player->is_360_feature_enabled &&
2703 player->is_content_spherical &&
2705 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2706 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2707 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2709 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2714 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2715 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2716 gst_caps_unref(acaps);
2718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2720 player->is_openal_plugin_used = TRUE;
2722 if (player->is_360_feature_enabled && player->is_content_spherical)
2723 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2724 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2727 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2728 (player->videodec_linked && player->ini.use_system_clock)) {
2729 LOGD("system clock will be used.");
2730 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2733 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2734 __mmplayer_gst_set_pulsesink_property(player);
2735 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2736 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2741 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2742 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2744 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2745 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2746 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2747 gst_object_unref(GST_OBJECT(sink_pad));
2749 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2752 return MM_ERROR_NONE;
2754 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2756 return MM_ERROR_PLAYER_INTERNAL;
2760 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2762 mmplayer_gst_element_t *audiobin = NULL;
2763 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2765 gchar *dst_format = NULL;
2767 int dst_samplerate = 0;
2768 int dst_channels = 0;
2769 GstCaps *caps = NULL;
2770 char *caps_str = NULL;
2773 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2774 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2776 audiobin = player->pipeline->audiobin;
2778 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2780 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2782 [case 1] extract interleave audio pcm without playback
2783 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2784 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2786 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2788 [case 2] deinterleave for each channel without playback
2789 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2790 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2792 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2793 - fakesink (sync or not)
2796 [case 3] [case 1(sync only)] + playback
2797 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2799 * src - ... - tee - queue1 - playback path
2800 - queue2 - [case1 pipeline with sync]
2802 [case 4] [case 2(sync only)] + playback
2803 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2805 * src - ... - tee - queue1 - playback path
2806 - queue2 - [case2 pipeline with sync]
2810 /* 1. create tee and playback path
2811 'tee' should be added at first to copy the decoded stream
2813 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2814 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2815 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2817 /* tee - path 1 : for playback path */
2818 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2819 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2821 /* tee - path 2 : for extract path */
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2823 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2826 /* if there is tee, 'tee - path 2' is linked here */
2828 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2831 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2833 /* 2. decide the extract pcm format */
2834 mm_attrs_multiple_get(player->attrs, NULL,
2835 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2836 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2837 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2840 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2841 dst_format, dst_len, dst_samplerate, dst_channels);
2843 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2844 mm_attrs_multiple_get(player->attrs, NULL,
2845 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2846 "content_audio_samplerate", &dst_samplerate,
2847 "content_audio_channels", &dst_channels,
2850 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2851 dst_format, dst_len, dst_samplerate, dst_channels);
2853 /* If there is no enough information, set it to platform default value. */
2854 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2855 LOGD("set platform default format");
2856 dst_format = DEFAULT_PCM_OUT_FORMAT;
2858 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2859 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2862 /* 3. create capsfilter */
2863 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2864 caps = gst_caps_new_simple("audio/x-raw",
2865 "format", G_TYPE_STRING, dst_format,
2866 "rate", G_TYPE_INT, dst_samplerate,
2867 "channels", G_TYPE_INT, dst_channels,
2870 caps_str = gst_caps_to_string(caps);
2871 LOGD("new caps : %s", caps_str);
2873 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2876 gst_caps_unref(caps);
2877 MMPLAYER_FREEIF(caps_str);
2879 /* 4-1. create deinterleave to extract pcm for each channel */
2880 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2882 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2884 /* audiosink will be added after getting signal for each channel */
2885 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2886 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2887 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2888 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2889 player->no_more_pad = FALSE;
2891 /* 4-2. create fakesink to extract interlevaed pcm */
2892 LOGD("add audio fakesink for interleaved audio");
2893 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2894 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2895 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2896 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2898 _mmplayer_add_signal_connection(player,
2899 G_OBJECT(audiobin[extract_sink_id].gst),
2900 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2902 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2905 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2909 return MM_ERROR_NONE;
2911 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2913 return MM_ERROR_PLAYER_INTERNAL;
2917 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2919 int ret = MM_ERROR_NONE;
2920 mmplayer_gst_element_t *audiobin = NULL;
2921 GList *element_bucket = NULL;
2924 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2925 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2927 audiobin = player->pipeline->audiobin;
2929 if (player->build_audio_offload) { /* skip all the audio filters */
2930 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2932 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2933 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2934 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2936 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2940 /* FIXME: need to mention the supportable condition at API reference */
2941 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2942 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2944 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2946 if (ret != MM_ERROR_NONE)
2949 LOGD("success to make audio bin element");
2950 *bucket = element_bucket;
2953 return MM_ERROR_NONE;
2956 LOGE("failed to make audio bin element");
2957 g_list_free(element_bucket);
2961 return MM_ERROR_PLAYER_INTERNAL;
2965 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2967 mmplayer_gst_element_t *first_element = NULL;
2968 mmplayer_gst_element_t *audiobin = NULL;
2970 GstPad *ghostpad = NULL;
2971 GList *element_bucket = NULL;
2975 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2978 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2980 LOGE("failed to allocate memory for audiobin");
2981 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2985 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2986 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2987 if (!audiobin[MMPLAYER_A_BIN].gst) {
2988 LOGE("failed to create audiobin");
2993 player->pipeline->audiobin = audiobin;
2995 /* create audio filters and audiosink */
2996 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2999 /* adding created elements to bin */
3000 LOGD("adding created elements to bin");
3001 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3004 /* linking elements in the bucket by added order. */
3005 LOGD("Linking elements in the bucket by added order.");
3006 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3009 /* get first element's sinkpad for creating ghostpad */
3010 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3011 if (!first_element) {
3012 LOGE("failed to get first elem");
3016 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3018 LOGE("failed to get pad from first element of audiobin");
3022 ghostpad = gst_ghost_pad_new("sink", pad);
3024 LOGE("failed to create ghostpad");
3028 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3029 LOGE("failed to add ghostpad to audiobin");
3033 gst_object_unref(pad);
3035 g_list_free(element_bucket);
3038 return MM_ERROR_NONE;
3041 LOGD("ERROR : releasing audiobin");
3044 gst_object_unref(GST_OBJECT(pad));
3047 gst_object_unref(GST_OBJECT(ghostpad));
3050 g_list_free(element_bucket);
3052 /* release element which are not added to bin */
3053 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3054 /* NOTE : skip bin */
3055 if (audiobin[i].gst) {
3056 GstObject *parent = NULL;
3057 parent = gst_element_get_parent(audiobin[i].gst);
3060 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3061 audiobin[i].gst = NULL;
3063 gst_object_unref(GST_OBJECT(parent));
3067 /* release audiobin with it's childs */
3068 if (audiobin[MMPLAYER_A_BIN].gst)
3069 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3071 MMPLAYER_FREEIF(audiobin);
3073 player->pipeline->audiobin = NULL;
3075 return MM_ERROR_PLAYER_INTERNAL;
3079 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3081 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3085 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3087 int ret = MM_ERROR_NONE;
3089 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3090 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3092 MMPLAYER_VIDEO_BO_LOCK(player);
3094 if (player->video_bo_list) {
3095 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3096 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3097 if (tmp && tmp->bo == bo) {
3099 LOGD("release bo %p", bo);
3100 tbm_bo_unref(tmp->bo);
3101 MMPLAYER_VIDEO_BO_UNLOCK(player);
3102 MMPLAYER_VIDEO_BO_SIGNAL(player);
3107 /* hw codec is running or the list was reset for DRC. */
3108 LOGW("there is no bo list.");
3110 MMPLAYER_VIDEO_BO_UNLOCK(player);
3112 LOGW("failed to find bo %p", bo);
3117 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3122 MMPLAYER_RETURN_IF_FAIL(player);
3124 MMPLAYER_VIDEO_BO_LOCK(player);
3125 if (player->video_bo_list) {
3126 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3127 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3128 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3131 tbm_bo_unref(tmp->bo);
3135 g_list_free(player->video_bo_list);
3136 player->video_bo_list = NULL;
3138 player->video_bo_size = 0;
3139 MMPLAYER_VIDEO_BO_UNLOCK(player);
3146 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3149 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3150 gboolean ret = TRUE;
3152 /* check DRC, if it is, destroy the prev bo list to create again */
3153 if (player->video_bo_size != size) {
3154 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3155 __mmplayer_video_stream_destroy_bo_list(player);
3156 player->video_bo_size = size;
3159 MMPLAYER_VIDEO_BO_LOCK(player);
3161 if ((!player->video_bo_list) ||
3162 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3164 /* create bo list */
3166 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3168 if (player->video_bo_list) {
3169 /* if bo list did not created all, try it again. */
3170 idx = g_list_length(player->video_bo_list);
3171 LOGD("bo list exist(len: %d)", idx);
3174 for (; idx < player->ini.num_of_video_bo; idx++) {
3175 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3177 LOGE("Fail to alloc bo_info.");
3180 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3182 LOGE("Fail to tbm_bo_alloc.");
3183 MMPLAYER_FREEIF(bo_info);
3186 bo_info->used = FALSE;
3187 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3190 /* update video num buffers */
3191 LOGD("video_num_buffers : %d", idx);
3192 mm_player_set_attribute((MMHandleType)player, NULL,
3193 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3194 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3198 MMPLAYER_VIDEO_BO_UNLOCK(player);
3204 /* get bo from list*/
3205 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3206 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3207 if (tmp && (tmp->used == FALSE)) {
3208 LOGD("found bo %p to use", tmp->bo);
3210 MMPLAYER_VIDEO_BO_UNLOCK(player);
3211 return tbm_bo_ref(tmp->bo);
3215 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3216 MMPLAYER_VIDEO_BO_UNLOCK(player);
3220 if (player->ini.video_bo_timeout <= 0) {
3221 MMPLAYER_VIDEO_BO_WAIT(player);
3223 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3224 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3231 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3233 mmplayer_t *player = (mmplayer_t *)data;
3235 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3237 /* send prerolled pkt */
3238 player->video_stream_prerolled = false;
3240 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3242 /* not to send prerolled pkt again */
3243 player->video_stream_prerolled = true;
3247 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3249 mmplayer_t *player = (mmplayer_t *)data;
3250 mmplayer_video_decoded_data_info_t *stream = NULL;
3251 GstMemory *mem = NULL;
3254 MMPLAYER_RETURN_IF_FAIL(player);
3255 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3257 if (player->video_stream_prerolled) {
3258 player->video_stream_prerolled = false;
3259 LOGD("skip the prerolled pkt not to send it again");
3263 /* clear stream data structure */
3264 stream = __mmplayer_create_stream_from_pad(pad);
3266 LOGE("failed to alloc stream");
3270 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3272 /* set size and timestamp */
3273 mem = gst_buffer_peek_memory(buffer, 0);
3274 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3275 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3277 /* check zero-copy */
3278 if (player->set_mode.video_zc &&
3279 player->set_mode.video_export &&
3280 gst_is_tizen_memory(mem)) {
3281 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3282 stream->internal_buffer = gst_buffer_ref(buffer);
3283 } else { /* sw codec */
3284 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3287 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3291 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3292 LOGE("failed to send video decoded data.");
3299 LOGE("release video stream resource.");
3300 if (gst_is_tizen_memory(mem)) {
3302 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3304 tbm_bo_unref(stream->bo[i]);
3307 /* unref gst buffer */
3308 if (stream->internal_buffer)
3309 gst_buffer_unref(stream->internal_buffer);
3312 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3314 MMPLAYER_FREEIF(stream);
3319 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3321 mmplayer_gst_element_t *videobin = NULL;
3324 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3326 videobin = player->pipeline->videobin;
3328 /* Set spatial media metadata and/or user settings to the element.
3330 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3331 "projection-type", player->video360_metadata.projection_type, NULL);
3333 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3334 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3336 if (player->video360_metadata.full_pano_width_pixels &&
3337 player->video360_metadata.full_pano_height_pixels &&
3338 player->video360_metadata.cropped_area_image_width &&
3339 player->video360_metadata.cropped_area_image_height) {
3340 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3341 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3342 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3343 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3344 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3345 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3346 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3350 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3351 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3352 "horizontal-fov", player->video360_horizontal_fov,
3353 "vertical-fov", player->video360_vertical_fov, NULL);
3356 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3357 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3358 "zoom", 1.0f / player->video360_zoom, NULL);
3361 if (player->video360_yaw_radians <= M_PI &&
3362 player->video360_yaw_radians >= -M_PI &&
3363 player->video360_pitch_radians <= M_PI_2 &&
3364 player->video360_pitch_radians >= -M_PI_2) {
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3367 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3368 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3369 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3370 "pose-yaw", player->video360_metadata.init_view_heading,
3371 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3374 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3375 "passthrough", !player->is_video360_enabled, NULL);
3382 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3384 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3385 GList *element_bucket = NULL;
3388 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3390 /* create video360 filter */
3391 if (player->is_360_feature_enabled && player->is_content_spherical) {
3392 LOGD("create video360 element");
3393 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3394 __mmplayer_gst_set_video360_property(player);
3398 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3399 LOGD("skip creating the videoconv and rotator");
3400 return MM_ERROR_NONE;
3403 /* in case of sw codec & overlay surface type, except 360 playback.
3404 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3405 LOGD("create video converter: %s", video_csc);
3406 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3409 *bucket = element_bucket;
3411 return MM_ERROR_NONE;
3413 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3414 g_list_free(element_bucket);
3418 return MM_ERROR_PLAYER_INTERNAL;
3422 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3424 gchar *factory_name = NULL;
3426 switch (surface_type) {
3427 case MM_DISPLAY_SURFACE_OVERLAY:
3428 if (strlen(player->ini.videosink_element_overlay) > 0)
3429 factory_name = player->ini.videosink_element_overlay;
3431 case MM_DISPLAY_SURFACE_REMOTE:
3432 case MM_DISPLAY_SURFACE_NULL:
3433 if (strlen(player->ini.videosink_element_fake) > 0)
3434 factory_name = player->ini.videosink_element_fake;
3437 LOGE("unidentified surface type");
3441 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3442 return factory_name;
3446 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3448 gchar *factory_name = NULL;
3449 mmplayer_gst_element_t *videobin = NULL;
3454 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3456 videobin = player->pipeline->videobin;
3457 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3459 attrs = MMPLAYER_GET_ATTRS(player);
3461 LOGE("cannot get content attribute");
3462 return MM_ERROR_PLAYER_INTERNAL;
3465 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3466 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3467 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3468 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3469 "use-tbm", use_tbm, NULL);
3472 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3473 return MM_ERROR_PLAYER_INTERNAL;
3475 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3478 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3479 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3482 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3484 LOGD("disable last-sample");
3485 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3488 if (player->set_mode.video_export) {
3490 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3491 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3492 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3494 _mmplayer_add_signal_connection(player,
3495 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3496 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3498 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3501 _mmplayer_add_signal_connection(player,
3502 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3503 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3505 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3509 if (videobin[MMPLAYER_V_SINK].gst) {
3510 GstPad *sink_pad = NULL;
3511 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3513 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3514 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3515 gst_object_unref(GST_OBJECT(sink_pad));
3517 LOGE("failed to get sink pad from videosink");
3521 return MM_ERROR_NONE;
3526 * - video overlay surface(arm/x86) : tizenwlsink
3529 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3532 GList *element_bucket = NULL;
3533 mmplayer_gst_element_t *first_element = NULL;
3534 mmplayer_gst_element_t *videobin = NULL;
3535 gchar *videosink_factory_name = NULL;
3538 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3541 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3543 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3545 player->pipeline->videobin = videobin;
3548 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3549 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3550 if (!videobin[MMPLAYER_V_BIN].gst) {
3551 LOGE("failed to create videobin");
3555 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3558 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3559 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3561 /* additional setting for sink plug-in */
3562 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3563 LOGE("failed to set video property");
3567 /* store it as it's sink element */
3568 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3570 /* adding created elements to bin */
3571 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3572 LOGE("failed to add elements");
3576 /* Linking elements in the bucket by added order */
3577 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3578 LOGE("failed to link elements");
3582 /* get first element's sinkpad for creating ghostpad */
3583 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3584 if (!first_element) {
3585 LOGE("failed to get first element from bucket");
3589 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3591 LOGE("failed to get pad from first element");
3595 /* create ghostpad */
3596 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3597 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3598 LOGE("failed to add ghostpad to videobin");
3601 gst_object_unref(pad);
3603 /* done. free allocated variables */
3604 g_list_free(element_bucket);
3608 return MM_ERROR_NONE;
3611 LOGE("ERROR : releasing videobin");
3612 g_list_free(element_bucket);
3615 gst_object_unref(GST_OBJECT(pad));
3617 /* release videobin with it's childs */
3618 if (videobin[MMPLAYER_V_BIN].gst)
3619 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3621 MMPLAYER_FREEIF(videobin);
3622 player->pipeline->videobin = NULL;
3624 return MM_ERROR_PLAYER_INTERNAL;
3628 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3630 GList *element_bucket = NULL;
3631 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3633 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3634 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3635 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3636 "signal-handoffs", FALSE,
3639 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3640 _mmplayer_add_signal_connection(player,
3641 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3642 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3644 G_CALLBACK(__mmplayer_update_subtitle),
3647 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3648 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3650 if (!player->play_subtitle) {
3651 LOGD("add textbin sink as sink element of whole pipeline.");
3652 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3655 /* adding created elements to bin */
3656 LOGD("adding created elements to bin");
3657 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3658 LOGE("failed to add elements");
3662 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3663 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3664 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3666 /* linking elements in the bucket by added order. */
3667 LOGD("Linking elements in the bucket by added order.");
3668 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3669 LOGE("failed to link elements");
3673 /* done. free allocated variables */
3674 g_list_free(element_bucket);
3676 if (textbin[MMPLAYER_T_QUEUE].gst) {
3678 GstPad *ghostpad = NULL;
3680 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3682 LOGE("failed to get sink pad of text queue");
3686 ghostpad = gst_ghost_pad_new("text_sink", pad);
3687 gst_object_unref(pad);
3690 LOGE("failed to create ghostpad of textbin");
3694 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3695 LOGE("failed to add ghostpad to textbin");
3696 gst_object_unref(ghostpad);
3701 return MM_ERROR_NONE;
3704 g_list_free(element_bucket);
3706 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3707 LOGE("remove textbin sink from sink list");
3708 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3711 /* release element at __mmplayer_gst_create_text_sink_bin */
3712 return MM_ERROR_PLAYER_INTERNAL;
3716 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3718 mmplayer_gst_element_t *textbin = NULL;
3719 GList *element_bucket = NULL;
3720 int surface_type = 0;
3725 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3728 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3730 LOGE("failed to allocate memory for textbin");
3731 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3735 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3736 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3737 if (!textbin[MMPLAYER_T_BIN].gst) {
3738 LOGE("failed to create textbin");
3743 player->pipeline->textbin = textbin;
3746 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3747 LOGD("surface type for subtitle : %d", surface_type);
3748 switch (surface_type) {
3749 case MM_DISPLAY_SURFACE_OVERLAY:
3750 case MM_DISPLAY_SURFACE_NULL:
3751 case MM_DISPLAY_SURFACE_REMOTE:
3752 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3753 LOGE("failed to make plain text elements");
3764 return MM_ERROR_NONE;
3768 LOGD("ERROR : releasing textbin");
3770 g_list_free(element_bucket);
3772 /* release signal */
3773 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3775 /* release element which are not added to bin */
3776 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3777 /* NOTE : skip bin */
3778 if (textbin[i].gst) {
3779 GstObject *parent = NULL;
3780 parent = gst_element_get_parent(textbin[i].gst);
3783 gst_object_unref(GST_OBJECT(textbin[i].gst));
3784 textbin[i].gst = NULL;
3786 gst_object_unref(GST_OBJECT(parent));
3791 /* release textbin with it's childs */
3792 if (textbin[MMPLAYER_T_BIN].gst)
3793 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3795 MMPLAYER_FREEIF(textbin);
3796 player->pipeline->textbin = NULL;
3799 return MM_ERROR_PLAYER_INTERNAL;
3803 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3805 mmplayer_gst_element_t *mainbin = NULL;
3806 mmplayer_gst_element_t *textbin = NULL;
3807 MMHandleType attrs = 0;
3808 GstElement *subsrc = NULL;
3809 GstElement *subparse = NULL;
3810 gchar *subtitle_uri = NULL;
3811 const gchar *charset = NULL;
3817 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3819 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3821 mainbin = player->pipeline->mainbin;
3823 attrs = MMPLAYER_GET_ATTRS(player);
3825 LOGE("cannot get content attribute");
3826 return MM_ERROR_PLAYER_INTERNAL;
3829 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3830 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3831 LOGE("subtitle uri is not proper filepath.");
3832 return MM_ERROR_PLAYER_INVALID_URI;
3835 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3836 LOGE("failed to get storage info of subtitle path");
3837 return MM_ERROR_PLAYER_INVALID_URI;
3840 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3842 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3843 player->subtitle_language_list = NULL;
3844 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3846 /* create the subtitle source */
3847 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3849 LOGE("failed to create filesrc element");
3852 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3854 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3855 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3857 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3858 LOGW("failed to add queue");
3859 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3860 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3861 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3866 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3868 LOGE("failed to create subparse element");
3872 charset = _mmplayer_get_charset(subtitle_uri);
3874 LOGD("detected charset is %s", charset);
3875 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3878 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3879 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3881 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3882 LOGW("failed to add subparse");
3883 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3884 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3885 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3889 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3890 LOGW("failed to link subsrc and subparse");
3894 player->play_subtitle = TRUE;
3895 player->adjust_subtitle_pos = 0;
3897 LOGD("play subtitle using subtitle file");
3899 if (player->pipeline->textbin == NULL) {
3900 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3901 LOGE("failed to create text sink bin. continuing without text");
3905 textbin = player->pipeline->textbin;
3907 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3908 LOGW("failed to add textbin");
3910 /* release signal */
3911 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3913 /* release textbin with it's childs */
3914 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3915 MMPLAYER_FREEIF(player->pipeline->textbin);
3916 player->pipeline->textbin = textbin = NULL;
3920 LOGD("link text input selector and textbin ghost pad");
3922 player->textsink_linked = 1;
3923 player->external_text_idx = 0;
3924 LOGI("textsink is linked");
3926 textbin = player->pipeline->textbin;
3927 LOGD("text bin has been created. reuse it.");
3928 player->external_text_idx = 1;
3931 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3932 LOGW("failed to link subparse and textbin");
3936 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3938 LOGE("failed to get sink pad from textsink to probe data");
3942 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3943 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3945 gst_object_unref(pad);
3948 /* create dot. for debugging */
3949 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3952 return MM_ERROR_NONE;
3955 /* release text pipeline resource */
3956 player->textsink_linked = 0;
3958 /* release signal */
3959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3961 if (player->pipeline->textbin) {
3962 LOGE("remove textbin");
3964 /* release textbin with it's childs */
3965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3966 MMPLAYER_FREEIF(player->pipeline->textbin);
3967 player->pipeline->textbin = NULL;
3971 /* release subtitle elem */
3972 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3973 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3975 return MM_ERROR_PLAYER_INTERNAL;
3979 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3981 mmplayer_t *player = (mmplayer_t *)data;
3982 MMMessageParamType msg = {0, };
3983 GstClockTime duration = 0;
3984 gpointer text = NULL;
3985 guint text_size = 0;
3986 gboolean ret = TRUE;
3987 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3992 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3994 if (player->is_subtitle_force_drop) {
3995 LOGW("subtitle is dropped forcedly.");
3999 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4000 text = mapinfo.data;
4001 text_size = mapinfo.size;
4003 if (player->set_mode.subtitle_off) {
4004 LOGD("subtitle is OFF.");
4008 if (!text || (text_size == 0)) {
4009 LOGD("There is no subtitle to be displayed.");
4013 msg.data = (void *)text;
4015 duration = GST_BUFFER_DURATION(buffer);
4017 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4018 if (player->duration > GST_BUFFER_PTS(buffer))
4019 duration = player->duration - GST_BUFFER_PTS(buffer);
4022 LOGI("subtitle duration is invalid, subtitle duration change "
4023 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4025 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4027 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4029 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4030 gst_buffer_unmap(buffer, &mapinfo);
4037 static GstPadProbeReturn
4038 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4040 mmplayer_t *player = (mmplayer_t *)u_data;
4041 GstClockTime cur_timestamp = 0;
4042 gint64 adjusted_timestamp = 0;
4043 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4045 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4047 if (player->set_mode.subtitle_off) {
4048 LOGD("subtitle is OFF.");
4052 if (player->adjust_subtitle_pos == 0) {
4053 LOGD("nothing to do");
4057 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4058 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4060 if (adjusted_timestamp < 0) {
4061 LOGD("adjusted_timestamp under zero");
4066 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4067 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4068 GST_TIME_ARGS(cur_timestamp),
4069 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4071 return GST_PAD_PROBE_OK;
4075 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4079 /* check player and subtitlebin are created */
4080 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4081 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4083 if (position == 0) {
4084 LOGD("nothing to do");
4086 return MM_ERROR_NONE;
4089 /* check current postion */
4090 player->adjust_subtitle_pos = position;
4092 LOGD("save adjust_subtitle_pos in player");
4096 return MM_ERROR_NONE;
4100 * This function is to create audio or video pipeline for playing.
4102 * @param player [in] handle of player
4104 * @return This function returns zero on success.
4109 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4111 int ret = MM_ERROR_NONE;
4112 mmplayer_gst_element_t *mainbin = NULL;
4113 MMHandleType attrs = 0;
4116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4118 /* get profile attribute */
4119 attrs = MMPLAYER_GET_ATTRS(player);
4121 LOGE("failed to get content attribute");
4125 /* create pipeline handles */
4126 if (player->pipeline) {
4127 LOGE("pipeline should be released before create new one");
4131 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4133 /* create mainbin */
4134 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4135 if (mainbin == NULL)
4138 /* create pipeline */
4139 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4140 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4141 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4142 LOGE("failed to create pipeline");
4147 player->pipeline->mainbin = mainbin;
4149 /* create the source and decoder elements */
4150 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4151 ret = _mmplayer_gst_build_es_pipeline(player);
4153 ret = _mmplayer_gst_build_pipeline(player);
4155 if (ret != MM_ERROR_NONE) {
4156 LOGE("failed to create some elements");
4160 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4161 if (__mmplayer_check_subtitle(player)
4162 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4163 LOGE("failed to create text pipeline");
4166 ret = _mmplayer_gst_add_bus_watch(player);
4167 if (ret != MM_ERROR_NONE) {
4168 LOGE("failed to add bus watch");
4173 return MM_ERROR_NONE;
4176 __mmplayer_gst_destroy_pipeline(player);
4177 return MM_ERROR_PLAYER_INTERNAL;
4181 __mmplayer_reset_gapless_state(mmplayer_t *player)
4184 MMPLAYER_RETURN_IF_FAIL(player
4186 && player->pipeline->audiobin
4187 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4189 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4196 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4199 int ret = MM_ERROR_NONE;
4203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4205 /* cleanup stuffs */
4206 MMPLAYER_FREEIF(player->type);
4207 player->no_more_pad = FALSE;
4208 player->num_dynamic_pad = 0;
4210 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4211 player->subtitle_language_list = NULL;
4212 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4214 MMPLAYER_RECONFIGURE_LOCK(player);
4215 __mmplayer_reset_gapless_state(player);
4216 MMPLAYER_RECONFIGURE_UNLOCK(player);
4218 if (player->streamer) {
4219 _mm_player_streaming_initialize(player->streamer, FALSE);
4220 _mm_player_streaming_destroy(player->streamer);
4221 player->streamer = NULL;
4224 /* cleanup unlinked mime type */
4225 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4226 MMPLAYER_FREEIF(player->unlinked_video_mime);
4227 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4229 /* cleanup running stuffs */
4230 _mmplayer_cancel_eos_timer(player);
4232 /* cleanup gst stuffs */
4233 if (player->pipeline) {
4234 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4235 GstTagList *tag_list = player->pipeline->tag_list;
4237 /* first we need to disconnect all signal hander */
4238 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4241 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4242 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4243 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4244 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4245 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4246 gst_object_unref(bus);
4248 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4249 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4250 if (ret != MM_ERROR_NONE) {
4251 LOGE("fail to change state to NULL");
4252 return MM_ERROR_PLAYER_INTERNAL;
4255 LOGW("succeeded in changing state to NULL");
4257 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4260 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4261 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4263 /* free avsysaudiosink
4264 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4265 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4267 MMPLAYER_FREEIF(audiobin);
4268 MMPLAYER_FREEIF(videobin);
4269 MMPLAYER_FREEIF(textbin);
4270 MMPLAYER_FREEIF(mainbin);
4274 gst_tag_list_unref(tag_list);
4276 MMPLAYER_FREEIF(player->pipeline);
4278 MMPLAYER_FREEIF(player->album_art);
4280 if (player->v_stream_caps) {
4281 gst_caps_unref(player->v_stream_caps);
4282 player->v_stream_caps = NULL;
4285 if (player->a_stream_caps) {
4286 gst_caps_unref(player->a_stream_caps);
4287 player->a_stream_caps = NULL;
4290 if (player->s_stream_caps) {
4291 gst_caps_unref(player->s_stream_caps);
4292 player->s_stream_caps = NULL;
4294 _mmplayer_track_destroy(player);
4296 if (player->sink_elements)
4297 g_list_free(player->sink_elements);
4298 player->sink_elements = NULL;
4300 if (player->bufmgr) {
4301 tbm_bufmgr_deinit(player->bufmgr);
4302 player->bufmgr = NULL;
4305 LOGW("finished destroy pipeline");
4313 __mmplayer_gst_realize(mmplayer_t *player)
4316 int ret = MM_ERROR_NONE;
4320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4322 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4324 ret = __mmplayer_gst_create_pipeline(player);
4326 LOGE("failed to create pipeline");
4330 /* set pipeline state to READY */
4331 /* NOTE : state change to READY must be performed sync. */
4332 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4333 ret = _mmplayer_gst_set_state(player,
4334 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4336 if (ret != MM_ERROR_NONE) {
4337 /* return error if failed to set state */
4338 LOGE("failed to set READY state");
4342 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4344 /* create dot before error-return. for debugging */
4345 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4353 __mmplayer_gst_unrealize(mmplayer_t *player)
4355 int ret = MM_ERROR_NONE;
4359 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4361 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4362 MMPLAYER_PRINT_STATE(player);
4364 /* release miscellaneous information */
4365 __mmplayer_release_misc(player);
4367 /* destroy pipeline */
4368 ret = __mmplayer_gst_destroy_pipeline(player);
4369 if (ret != MM_ERROR_NONE) {
4370 LOGE("failed to destory pipeline");
4374 /* release miscellaneous information.
4375 these info needs to be released after pipeline is destroyed. */
4376 __mmplayer_release_misc_post(player);
4378 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4386 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4391 LOGW("set_message_callback is called with invalid player handle");
4392 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4395 player->msg_cb = callback;
4396 player->msg_cb_param = user_param;
4398 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4402 return MM_ERROR_NONE;
4406 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4408 int ret = MM_ERROR_NONE;
4413 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4414 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4415 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4417 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4419 if (strstr(uri, "es_buff://")) {
4420 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4421 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4422 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4423 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4425 tmp = g_ascii_strdown(uri, strlen(uri));
4426 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4427 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4429 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4431 } else if (strstr(uri, "mms://")) {
4432 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4433 } else if ((path = strstr(uri, "mem://"))) {
4434 ret = __mmplayer_set_mem_uri(data, path, param);
4436 ret = __mmplayer_set_file_uri(data, uri);
4439 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4440 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4441 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4442 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4444 /* dump parse result */
4445 SECURE_LOGW("incoming uri : %s", uri);
4446 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4447 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4455 __mmplayer_can_do_interrupt(mmplayer_t *player)
4457 if (!player || !player->pipeline || !player->attrs) {
4458 LOGW("not initialized");
4462 if (player->audio_decoded_cb) {
4463 LOGW("not support in pcm extraction mode");
4467 /* check if seeking */
4468 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4469 MMMessageParamType msg_param;
4470 memset(&msg_param, 0, sizeof(MMMessageParamType));
4471 msg_param.code = MM_ERROR_PLAYER_SEEK;
4472 player->seek_state = MMPLAYER_SEEK_NONE;
4473 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4477 /* check other thread */
4478 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4479 LOGW("locked already, cmd state : %d", player->cmd);
4481 /* check application command */
4482 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4483 LOGW("playing.. should wait cmd lock then, will be interrupted");
4485 /* lock will be released at mrp_resource_release_cb() */
4486 MMPLAYER_CMD_LOCK(player);
4489 LOGW("nothing to do");
4492 LOGW("can interrupt immediately");
4496 FAILED: /* with CMD UNLOCKED */
4499 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4504 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4507 mmplayer_t *player = NULL;
4508 MMMessageParamType msg = {0, };
4510 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4515 LOGE("user_data is null");
4518 player = (mmplayer_t *)user_data;
4520 if (!__mmplayer_can_do_interrupt(player)) {
4521 LOGW("no need to interrupt, so leave");
4522 /* FIXME: there is no way to avoid releasing resource. */
4526 player->interrupted_by_resource = TRUE;
4528 /* get last play position */
4529 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4530 msg.union_type = MM_MSG_UNION_TIME;
4531 msg.time.elapsed = pos;
4532 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4534 LOGW("failed to get play position.");
4537 LOGD("video resource conflict so, resource will be freed by unrealizing");
4538 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4539 LOGE("failed to unrealize");
4541 /* lock is called in __mmplayer_can_do_interrupt() */
4542 MMPLAYER_CMD_UNLOCK(player);
4544 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4545 player->hw_resource[res_idx] = NULL;
4549 return TRUE; /* release all the resources */
4553 __mmplayer_initialize_video_roi(mmplayer_t *player)
4555 player->video_roi.scale_x = 0.0;
4556 player->video_roi.scale_y = 0.0;
4557 player->video_roi.scale_width = 1.0;
4558 player->video_roi.scale_height = 1.0;
4562 _mmplayer_create_player(MMHandleType handle)
4564 int ret = MM_ERROR_PLAYER_INTERNAL;
4565 bool enabled = false;
4567 mmplayer_t *player = MM_PLAYER_CAST(handle);
4571 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4573 /* initialize player state */
4574 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4575 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4576 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4577 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4579 /* check current state */
4580 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4582 /* construct attributes */
4583 player->attrs = _mmplayer_construct_attribute(handle);
4585 if (!player->attrs) {
4586 LOGE("Failed to construct attributes");
4590 /* initialize gstreamer with configured parameter */
4591 if (!__mmplayer_init_gstreamer(player)) {
4592 LOGE("Initializing gstreamer failed");
4593 _mmplayer_deconstruct_attribute(handle);
4597 /* create lock. note that g_tread_init() has already called in gst_init() */
4598 g_mutex_init(&player->fsink_lock);
4600 /* create update tag lock */
4601 g_mutex_init(&player->update_tag_lock);
4603 /* create gapless play mutex */
4604 g_mutex_init(&player->gapless_play_thread_mutex);
4606 /* create gapless play cond */
4607 g_cond_init(&player->gapless_play_thread_cond);
4609 /* create gapless play thread */
4610 player->gapless_play_thread =
4611 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4612 if (!player->gapless_play_thread) {
4613 LOGE("failed to create gapless play thread");
4614 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4615 g_mutex_clear(&player->gapless_play_thread_mutex);
4616 g_cond_clear(&player->gapless_play_thread_cond);
4620 player->bus_msg_q = g_queue_new();
4621 if (!player->bus_msg_q) {
4622 LOGE("failed to create queue for bus_msg");
4623 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4627 ret = _mmplayer_initialize_video_capture(player);
4628 if (ret != MM_ERROR_NONE) {
4629 LOGE("failed to initialize video capture");
4633 /* initialize resource manager */
4634 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4635 __resource_release_cb, player, &player->resource_manager)
4636 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4637 LOGE("failed to initialize resource manager");
4638 ret = MM_ERROR_PLAYER_INTERNAL;
4642 /* create video bo lock and cond */
4643 g_mutex_init(&player->video_bo_mutex);
4644 g_cond_init(&player->video_bo_cond);
4646 /* create subtitle info lock and cond */
4647 g_mutex_init(&player->subtitle_info_mutex);
4648 g_cond_init(&player->subtitle_info_cond);
4650 player->streaming_type = STREAMING_SERVICE_NONE;
4652 /* give default value of audio effect setting */
4653 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4654 player->sound.rg_enable = false;
4655 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4657 player->play_subtitle = FALSE;
4658 player->has_closed_caption = FALSE;
4659 player->pending_resume = FALSE;
4660 if (player->ini.dump_element_keyword[0][0] == '\0')
4661 player->ini.set_dump_element_flag = FALSE;
4663 player->ini.set_dump_element_flag = TRUE;
4665 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4666 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4667 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4669 /* Set video360 settings to their defaults for just-created player.
4672 player->is_360_feature_enabled = FALSE;
4673 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4674 LOGI("spherical feature info: %d", enabled);
4676 player->is_360_feature_enabled = TRUE;
4678 LOGE("failed to get spherical feature info");
4681 player->is_content_spherical = FALSE;
4682 player->is_video360_enabled = TRUE;
4683 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4684 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4685 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4686 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4687 player->video360_zoom = 1.0f;
4688 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4689 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4691 __mmplayer_initialize_video_roi(player);
4693 /* set player state to null */
4694 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4695 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4699 return MM_ERROR_NONE;
4703 g_mutex_clear(&player->fsink_lock);
4704 /* free update tag lock */
4705 g_mutex_clear(&player->update_tag_lock);
4706 g_queue_free(player->bus_msg_q);
4707 player->bus_msg_q = NULL;
4708 /* free gapless play thread */
4709 if (player->gapless_play_thread) {
4710 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4711 player->gapless_play_thread_exit = TRUE;
4712 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4713 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4715 g_thread_join(player->gapless_play_thread);
4716 player->gapless_play_thread = NULL;
4718 g_mutex_clear(&player->gapless_play_thread_mutex);
4719 g_cond_clear(&player->gapless_play_thread_cond);
4722 /* release attributes */
4723 _mmplayer_deconstruct_attribute(handle);
4731 __mmplayer_init_gstreamer(mmplayer_t *player)
4733 static gboolean initialized = FALSE;
4734 static const int max_argc = 50;
4736 gchar **argv = NULL;
4737 gchar **argv2 = NULL;
4743 LOGD("gstreamer already initialized.");
4748 argc = malloc(sizeof(int));
4749 argv = malloc(sizeof(gchar *) * max_argc);
4750 argv2 = malloc(sizeof(gchar *) * max_argc);
4752 if (!argc || !argv || !argv2)
4755 memset(argv, 0, sizeof(gchar *) * max_argc);
4756 memset(argv2, 0, sizeof(gchar *) * max_argc);
4760 argv[0] = g_strdup("mmplayer");
4763 for (i = 0; i < 5; i++) {
4764 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4765 if (strlen(player->ini.gst_param[i]) > 0) {
4766 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4771 /* we would not do fork for scanning plugins */
4772 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4775 /* check disable registry scan */
4776 if (player->ini.skip_rescan) {
4777 argv[*argc] = g_strdup("--gst-disable-registry-update");
4781 /* check disable segtrap */
4782 if (player->ini.disable_segtrap) {
4783 argv[*argc] = g_strdup("--gst-disable-segtrap");
4787 LOGD("initializing gstreamer with following parameter");
4788 LOGD("argc : %d", *argc);
4791 for (i = 0; i < arg_count; i++) {
4793 LOGD("argv[%d] : %s", i, argv2[i]);
4796 /* initializing gstreamer */
4797 if (!gst_init_check(argc, &argv, &err)) {
4798 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4805 for (i = 0; i < arg_count; i++) {
4807 LOGD("release - argv[%d] : %s", i, argv2[i]);
4809 MMPLAYER_FREEIF(argv2[i]);
4812 MMPLAYER_FREEIF(argv);
4813 MMPLAYER_FREEIF(argv2);
4814 MMPLAYER_FREEIF(argc);
4824 for (i = 0; i < arg_count; i++) {
4825 LOGD("free[%d] : %s", i, argv2[i]);
4826 MMPLAYER_FREEIF(argv2[i]);
4829 MMPLAYER_FREEIF(argv);
4830 MMPLAYER_FREEIF(argv2);
4831 MMPLAYER_FREEIF(argc);
4837 __mmplayer_check_async_state_transition(mmplayer_t *player)
4839 GstState element_state = GST_STATE_VOID_PENDING;
4840 GstState element_pending_state = GST_STATE_VOID_PENDING;
4841 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4842 GstElement *element = NULL;
4843 gboolean async = FALSE;
4845 /* check player handle */
4846 MMPLAYER_RETURN_IF_FAIL(player &&
4848 player->pipeline->mainbin &&
4849 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4852 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4854 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4855 LOGD("don't need to check the pipeline state");
4859 MMPLAYER_PRINT_STATE(player);
4861 /* wait for state transition */
4862 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4863 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4865 if (ret == GST_STATE_CHANGE_FAILURE) {
4866 LOGE(" [%s] state : %s pending : %s",
4867 GST_ELEMENT_NAME(element),
4868 gst_element_state_get_name(element_state),
4869 gst_element_state_get_name(element_pending_state));
4871 /* dump state of all element */
4872 _mmplayer_dump_pipeline_state(player);
4877 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4882 _mmplayer_destroy(MMHandleType handle)
4884 mmplayer_t *player = MM_PLAYER_CAST(handle);
4888 /* check player handle */
4889 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4891 /* destroy can called at anytime */
4892 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4894 /* check async state transition */
4895 __mmplayer_check_async_state_transition(player);
4897 /* release gapless play thread */
4898 if (player->gapless_play_thread) {
4899 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4900 player->gapless_play_thread_exit = TRUE;
4901 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4902 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4904 LOGD("waitting for gapless play thread exit");
4905 g_thread_join(player->gapless_play_thread);
4906 g_mutex_clear(&player->gapless_play_thread_mutex);
4907 g_cond_clear(&player->gapless_play_thread_cond);
4908 LOGD("gapless play thread released");
4911 _mmplayer_release_video_capture(player);
4913 /* de-initialize resource manager */
4914 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4915 player->resource_manager))
4916 LOGE("failed to deinitialize resource manager");
4918 /* release miscellaneous information */
4919 __mmplayer_release_misc(player);
4921 /* release pipeline */
4922 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4923 LOGE("failed to destory pipeline");
4924 return MM_ERROR_PLAYER_INTERNAL;
4927 g_queue_free(player->bus_msg_q);
4929 /* release subtitle info lock and cond */
4930 g_mutex_clear(&player->subtitle_info_mutex);
4931 g_cond_clear(&player->subtitle_info_cond);
4933 __mmplayer_release_dump_list(player->dump_list);
4935 /* release miscellaneous information.
4936 these info needs to be released after pipeline is destroyed. */
4937 __mmplayer_release_misc_post(player);
4939 /* release attributes */
4940 _mmplayer_deconstruct_attribute(handle);
4942 if (player->uri_info.uri_list) {
4943 GList *uri_list = player->uri_info.uri_list;
4944 for (; uri_list; uri_list = g_list_next(uri_list)) {
4945 gchar *uri = uri_list->data;
4946 MMPLAYER_FREEIF(uri);
4948 g_list_free(player->uri_info.uri_list);
4949 player->uri_info.uri_list = NULL;
4953 g_mutex_clear(&player->fsink_lock);
4956 g_mutex_clear(&player->update_tag_lock);
4958 /* release video bo lock and cond */
4959 g_mutex_clear(&player->video_bo_mutex);
4960 g_cond_clear(&player->video_bo_cond);
4964 return MM_ERROR_NONE;
4968 _mmplayer_realize(MMHandleType hplayer)
4970 mmplayer_t *player = (mmplayer_t *)hplayer;
4971 int ret = MM_ERROR_NONE;
4974 MMHandleType attrs = 0;
4975 int video_codec_type = 0;
4976 int audio_codec_type = 0;
4977 int default_codec_type = 0;
4980 /* check player handle */
4981 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4983 /* check current state */
4984 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4986 attrs = MMPLAYER_GET_ATTRS(player);
4988 LOGE("fail to get attributes.");
4989 return MM_ERROR_PLAYER_INTERNAL;
4991 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4992 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4994 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4995 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4997 if (ret != MM_ERROR_NONE) {
4998 LOGE("failed to parse profile");
5003 if (uri && (strstr(uri, "es_buff://"))) {
5004 if (strstr(uri, "es_buff://push_mode"))
5005 player->es_player_push_mode = TRUE;
5007 player->es_player_push_mode = FALSE;
5010 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5011 LOGW("mms protocol is not supported format.");
5012 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5015 if (MMPLAYER_IS_STREAMING(player))
5016 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5018 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5020 player->smooth_streaming = FALSE;
5021 player->videodec_linked = 0;
5022 player->audiodec_linked = 0;
5023 player->textsink_linked = 0;
5024 player->is_external_subtitle_present = FALSE;
5025 player->is_external_subtitle_added_now = FALSE;
5026 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5027 player->video360_metadata.is_spherical = -1;
5028 player->is_openal_plugin_used = FALSE;
5029 player->subtitle_language_list = NULL;
5030 player->is_subtitle_force_drop = FALSE;
5032 _mmplayer_track_initialize(player);
5033 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5035 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5036 gint prebuffer_ms = 0, rebuffer_ms = 0;
5038 player->streamer = _mm_player_streaming_create();
5039 _mm_player_streaming_initialize(player->streamer, TRUE);
5041 mm_attrs_multiple_get(player->attrs, NULL,
5042 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5043 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5045 if (prebuffer_ms > 0) {
5046 prebuffer_ms = MAX(prebuffer_ms, 1000);
5047 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5050 if (rebuffer_ms > 0) {
5051 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5052 rebuffer_ms = MAX(rebuffer_ms, 1000);
5053 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5056 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5057 player->streamer->buffering_req.rebuffer_time);
5060 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5061 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5062 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5064 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5066 if (audio_codec_type != default_codec_type) {
5067 LOGD("audio dec sorting is required");
5068 player->need_audio_dec_sorting = TRUE;
5071 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5072 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5073 LOGD("video dec sorting is required");
5074 player->need_video_dec_sorting = TRUE;
5077 /* realize pipeline */
5078 ret = __mmplayer_gst_realize(player);
5079 if (ret != MM_ERROR_NONE)
5080 LOGE("fail to realize the player.");
5082 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5090 _mmplayer_unrealize(MMHandleType hplayer)
5092 mmplayer_t *player = (mmplayer_t *)hplayer;
5093 int ret = MM_ERROR_NONE;
5097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5099 MMPLAYER_CMD_UNLOCK(player);
5100 /* destroy the gst bus msg thread which is created during realize.
5101 this funct have to be called before getting cmd lock. */
5102 _mmplayer_bus_msg_thread_destroy(player);
5103 MMPLAYER_CMD_LOCK(player);
5105 /* check current state */
5106 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5108 /* check async state transition */
5109 __mmplayer_check_async_state_transition(player);
5111 /* unrealize pipeline */
5112 ret = __mmplayer_gst_unrealize(player);
5114 if (!player->interrupted_by_resource) {
5115 int rm_ret = MM_ERROR_NONE;
5116 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5118 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5119 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5120 if (rm_ret != MM_ERROR_NONE)
5121 LOGE("failed to release [%d] resources", res_idx);
5130 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5132 mmplayer_t *player = (mmplayer_t *)hplayer;
5134 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5136 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5140 _mmplayer_get_state(MMHandleType hplayer, int *state)
5142 mmplayer_t *player = (mmplayer_t *)hplayer;
5144 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5146 *state = MMPLAYER_CURRENT_STATE(player);
5148 return MM_ERROR_NONE;
5152 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5154 GstElement *vol_element = NULL;
5155 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5158 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5159 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5161 /* check pipeline handle */
5162 if (!player->pipeline || !player->pipeline->audiobin) {
5163 LOGD("'%s' will be applied when audiobin is created", prop_name);
5165 /* NOTE : stored value will be used in create_audiobin
5166 * returning MM_ERROR_NONE here makes application to able to
5167 * set audio volume or mute at anytime.
5169 return MM_ERROR_NONE;
5172 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5173 volume_elem_id = MMPLAYER_A_SINK;
5175 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5177 LOGE("failed to get vol element %d", volume_elem_id);
5178 return MM_ERROR_PLAYER_INTERNAL;
5181 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5183 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5184 LOGE("there is no '%s' property", prop_name);
5185 return MM_ERROR_PLAYER_INTERNAL;
5188 if (!strcmp(prop_name, "volume")) {
5189 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5190 } else if (!strcmp(prop_name, "mute")) {
5191 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5193 LOGE("invalid property %s", prop_name);
5194 return MM_ERROR_PLAYER_INTERNAL;
5197 return MM_ERROR_NONE;
5201 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5203 int ret = MM_ERROR_NONE;
5204 mmplayer_t *player = (mmplayer_t *)hplayer;
5207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209 LOGD("volume = %f", volume);
5211 /* invalid factor range or not */
5212 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5213 LOGE("Invalid volume value");
5214 return MM_ERROR_INVALID_ARGUMENT;
5217 player->sound.volume = volume;
5219 ret = __mmplayer_gst_set_volume_property(player, "volume");
5226 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5228 mmplayer_t *player = (mmplayer_t *)hplayer;
5232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5233 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5235 *volume = player->sound.volume;
5237 LOGD("current vol = %f", *volume);
5240 return MM_ERROR_NONE;
5244 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5246 int ret = MM_ERROR_NONE;
5247 mmplayer_t *player = (mmplayer_t *)hplayer;
5250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5252 LOGD("mute = %d", mute);
5254 player->sound.mute = mute;
5256 ret = __mmplayer_gst_set_volume_property(player, "mute");
5263 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5265 mmplayer_t *player = (mmplayer_t *)hplayer;
5269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5270 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5272 *mute = player->sound.mute;
5274 LOGD("current mute = %d", *mute);
5278 return MM_ERROR_NONE;
5282 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5284 mmplayer_t *player = (mmplayer_t *)hplayer;
5288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5290 player->audio_stream_changed_cb = callback;
5291 player->audio_stream_changed_cb_user_param = user_param;
5292 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5296 return MM_ERROR_NONE;
5300 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5302 mmplayer_t *player = (mmplayer_t *)hplayer;
5306 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5308 player->audio_decoded_cb = callback;
5309 player->audio_decoded_cb_user_param = user_param;
5310 player->audio_extract_opt = opt;
5311 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5315 return MM_ERROR_NONE;
5319 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5321 mmplayer_t *player = (mmplayer_t *)hplayer;
5325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5327 if (callback && !player->bufmgr)
5328 player->bufmgr = tbm_bufmgr_init(-1);
5330 player->set_mode.video_export = (callback) ? true : false;
5331 player->video_decoded_cb = callback;
5332 player->video_decoded_cb_user_param = user_param;
5334 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5338 return MM_ERROR_NONE;
5342 _mmplayer_start(MMHandleType hplayer)
5344 mmplayer_t *player = (mmplayer_t *)hplayer;
5345 gint ret = MM_ERROR_NONE;
5349 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5351 /* check current state */
5352 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5354 /* start pipeline */
5355 ret = _mmplayer_gst_start(player);
5356 if (ret != MM_ERROR_NONE)
5357 LOGE("failed to start player.");
5359 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5360 LOGD("force playing start even during buffering");
5361 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5369 /* NOTE: post "not supported codec message" to application
5370 * when one codec is not found during AUTOPLUGGING in MSL.
5371 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5372 * And, if any codec is not found, don't send message here.
5373 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5376 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5378 MMMessageParamType msg_param;
5379 memset(&msg_param, 0, sizeof(MMMessageParamType));
5380 gboolean post_msg_direct = FALSE;
5384 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5386 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5387 player->not_supported_codec, player->can_support_codec);
5389 if (player->not_found_demuxer) {
5390 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5391 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5393 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5394 MMPLAYER_FREEIF(msg_param.data);
5396 return MM_ERROR_NONE;
5399 if (player->not_supported_codec) {
5400 if (player->can_support_codec) {
5401 // There is one codec to play
5402 post_msg_direct = TRUE;
5404 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5405 post_msg_direct = TRUE;
5408 if (post_msg_direct) {
5409 MMMessageParamType msg_param;
5410 memset(&msg_param, 0, sizeof(MMMessageParamType));
5412 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5413 LOGW("not found AUDIO codec, posting error code to application.");
5415 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5416 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5417 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5418 LOGW("not found VIDEO codec, posting error code to application.");
5420 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5421 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5424 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5426 MMPLAYER_FREEIF(msg_param.data);
5428 return MM_ERROR_NONE;
5430 // no any supported codec case
5431 LOGW("not found any codec, posting error code to application.");
5433 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5434 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5435 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5437 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5438 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5441 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5443 MMPLAYER_FREEIF(msg_param.data);
5449 return MM_ERROR_NONE;
5452 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5454 GstState element_state = GST_STATE_VOID_PENDING;
5455 GstState element_pending_state = GST_STATE_VOID_PENDING;
5456 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5457 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5459 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5461 MMPLAYER_RECONFIGURE_LOCK(player);
5462 if (!player->gapless.reconfigure) {
5463 MMPLAYER_RECONFIGURE_UNLOCK(player);
5467 LOGI("reconfigure is under process");
5468 MMPLAYER_RECONFIGURE_WAIT(player);
5469 MMPLAYER_RECONFIGURE_UNLOCK(player);
5470 LOGI("reconfigure is completed.");
5472 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5473 &element_state, &element_pending_state, timeout * GST_SECOND);
5474 if (result == GST_STATE_CHANGE_FAILURE)
5475 LOGW("failed to get pipeline state in %d sec", timeout);
5480 /* NOTE : it should be able to call 'stop' anytime*/
5482 _mmplayer_stop(MMHandleType hplayer)
5484 mmplayer_t *player = (mmplayer_t *)hplayer;
5485 int ret = MM_ERROR_NONE;
5489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5491 /* check current state */
5492 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5494 /* need to wait till the rebuilding pipeline is completed */
5495 __mmplayer_check_pipeline_reconfigure_state(player);
5496 MMPLAYER_RECONFIGURE_LOCK(player);
5497 __mmplayer_reset_gapless_state(player);
5498 MMPLAYER_RECONFIGURE_UNLOCK(player);
5500 /* NOTE : application should not wait for EOS after calling STOP */
5501 _mmplayer_cancel_eos_timer(player);
5504 player->seek_state = MMPLAYER_SEEK_NONE;
5507 ret = _mmplayer_gst_stop(player);
5509 if (ret != MM_ERROR_NONE)
5510 LOGE("failed to stop player.");
5518 _mmplayer_pause(MMHandleType hplayer)
5520 mmplayer_t *player = (mmplayer_t *)hplayer;
5521 gint64 pos_nsec = 0;
5522 gboolean async = FALSE;
5523 gint ret = MM_ERROR_NONE;
5527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5529 /* check current state */
5530 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5532 /* check pipline reconfigure state */
5533 __mmplayer_check_pipeline_reconfigure_state(player);
5535 switch (MMPLAYER_CURRENT_STATE(player)) {
5536 case MM_PLAYER_STATE_READY:
5538 /* check prepare async or not.
5539 * In the case of streaming playback, it's recommned to avoid blocking wait.
5541 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5542 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5544 /* Changing back sync of rtspsrc to async */
5545 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5546 LOGD("async prepare working mode for rtsp");
5552 case MM_PLAYER_STATE_PLAYING:
5554 /* NOTE : store current point to overcome some bad operation
5555 *(returning zero when getting current position in paused state) of some
5558 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5559 LOGW("getting current position failed in paused");
5561 player->last_position = pos_nsec;
5563 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5564 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5565 This causes problem is position calculation during normal pause resume scenarios also.
5566 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5567 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5568 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5569 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5575 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5576 LOGD("doing async pause in case of ms buff src");
5580 /* pause pipeline */
5581 ret = _mmplayer_gst_pause(player, async);
5583 if (ret != MM_ERROR_NONE)
5584 LOGE("failed to pause player. ret : 0x%x", ret);
5586 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5587 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5588 LOGE("failed to update display_rotation");
5596 /* in case of streaming, pause could take long time.*/
5598 _mmplayer_abort_pause(MMHandleType hplayer)
5600 mmplayer_t *player = (mmplayer_t *)hplayer;
5601 int ret = MM_ERROR_NONE;
5605 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5607 player->pipeline->mainbin,
5608 MM_ERROR_PLAYER_NOT_INITIALIZED);
5610 LOGD("set the pipeline state to READY");
5612 /* set state to READY */
5613 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5614 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5615 if (ret != MM_ERROR_NONE) {
5616 LOGE("fail to change state to READY");
5617 return MM_ERROR_PLAYER_INTERNAL;
5620 LOGD("succeeded in changing state to READY");
5625 _mmplayer_resume(MMHandleType hplayer)
5627 mmplayer_t *player = (mmplayer_t *)hplayer;
5628 int ret = MM_ERROR_NONE;
5629 gboolean async = FALSE;
5633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5635 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5636 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5637 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5641 /* Changing back sync mode rtspsrc to async */
5642 LOGD("async resume for rtsp case");
5646 /* check current state */
5647 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5649 ret = _mmplayer_gst_resume(player, async);
5650 if (ret != MM_ERROR_NONE)
5651 LOGE("failed to resume player.");
5653 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5654 LOGD("force resume even during buffering");
5655 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5664 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5666 mmplayer_t *player = (mmplayer_t *)hplayer;
5667 gint64 pos_nsec = 0;
5668 int ret = MM_ERROR_NONE;
5670 signed long long start = 0, stop = 0;
5671 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5674 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5675 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5677 /* The sound of video is not supported under 0.0 and over 2.0. */
5678 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5679 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5682 _mmplayer_set_mute(hplayer, mute);
5684 if (player->playback_rate == rate)
5685 return MM_ERROR_NONE;
5687 /* If the position is reached at start potion during fast backward, EOS is posted.
5688 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5690 player->playback_rate = rate;
5692 current_state = MMPLAYER_CURRENT_STATE(player);
5694 if (current_state != MM_PLAYER_STATE_PAUSED)
5695 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5697 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5699 if ((current_state == MM_PLAYER_STATE_PAUSED)
5700 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5701 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5702 pos_nsec = player->last_position;
5707 stop = GST_CLOCK_TIME_NONE;
5709 start = GST_CLOCK_TIME_NONE;
5713 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5714 player->playback_rate,
5716 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5717 GST_SEEK_TYPE_SET, start,
5718 GST_SEEK_TYPE_SET, stop)) {
5719 LOGE("failed to set speed playback");
5720 return MM_ERROR_PLAYER_SEEK;
5723 LOGD("succeeded to set speed playback as %0.1f", rate);
5727 return MM_ERROR_NONE;;
5731 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5733 mmplayer_t *player = (mmplayer_t *)hplayer;
5734 int ret = MM_ERROR_NONE;
5738 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5740 /* check pipline reconfigure state */
5741 __mmplayer_check_pipeline_reconfigure_state(player);
5743 ret = _mmplayer_gst_set_position(player, position, FALSE);
5751 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5753 mmplayer_t *player = (mmplayer_t *)hplayer;
5754 int ret = MM_ERROR_NONE;
5756 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5757 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5759 if (g_strrstr(player->type, "video/mpegts"))
5760 __mmplayer_update_duration_value(player);
5762 *duration = player->duration;
5767 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5769 mmplayer_t *player = (mmplayer_t *)hplayer;
5770 int ret = MM_ERROR_NONE;
5772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5774 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5780 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5782 mmplayer_t *player = (mmplayer_t *)hplayer;
5783 int ret = MM_ERROR_NONE;
5787 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5789 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5797 __mmplayer_is_midi_type(gchar *str_caps)
5799 if ((g_strrstr(str_caps, "audio/midi")) ||
5800 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5801 (g_strrstr(str_caps, "application/x-smaf")) ||
5802 (g_strrstr(str_caps, "audio/x-imelody")) ||
5803 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5804 (g_strrstr(str_caps, "audio/xmf")) ||
5805 (g_strrstr(str_caps, "audio/mxmf"))) {
5814 __mmplayer_is_only_mp3_type(gchar *str_caps)
5816 if (g_strrstr(str_caps, "application/x-id3") ||
5817 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5823 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5825 GstStructure *caps_structure = NULL;
5826 gint samplerate = 0;
5830 MMPLAYER_RETURN_IF_FAIL(player && caps);
5832 caps_structure = gst_caps_get_structure(caps, 0);
5834 /* set stream information */
5835 gst_structure_get_int(caps_structure, "rate", &samplerate);
5836 gst_structure_get_int(caps_structure, "channels", &channels);
5838 mm_player_set_attribute((MMHandleType)player, NULL,
5839 "content_audio_samplerate", samplerate,
5840 "content_audio_channels", channels, NULL);
5842 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5846 __mmplayer_update_content_type_info(mmplayer_t *player)
5849 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5851 if (__mmplayer_is_midi_type(player->type)) {
5852 player->bypass_audio_effect = TRUE;
5856 if (!player->streamer) {
5857 LOGD("no need to check streaming type");
5861 if (g_strrstr(player->type, "application/x-hls")) {
5862 /* If it can't know exact type when it parses uri because of redirection case,
5863 * it will be fixed by typefinder or when doing autoplugging.
5865 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5866 player->streamer->is_adaptive_streaming = TRUE;
5867 } else if (g_strrstr(player->type, "application/dash+xml")) {
5868 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5869 player->streamer->is_adaptive_streaming = TRUE;
5872 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5873 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5874 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5876 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5877 if (player->streamer->is_adaptive_streaming)
5878 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5880 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5884 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5889 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5890 GstCaps *caps, gpointer data)
5892 mmplayer_t *player = (mmplayer_t *)data;
5896 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5898 /* store type string */
5899 MMPLAYER_FREEIF(player->type);
5900 player->type = gst_caps_to_string(caps);
5902 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5903 player, player->type, probability, gst_caps_get_size(caps));
5905 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5906 (g_strrstr(player->type, "audio/x-raw-int"))) {
5907 LOGE("not support media format");
5909 if (player->msg_posted == FALSE) {
5910 MMMessageParamType msg_param;
5911 memset(&msg_param, 0, sizeof(MMMessageParamType));
5913 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5914 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5916 /* don't post more if one was sent already */
5917 player->msg_posted = TRUE;
5922 __mmplayer_update_content_type_info(player);
5924 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5927 pad = gst_element_get_static_pad(tf, "src");
5929 LOGE("fail to get typefind src pad.");
5933 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5934 gboolean async = FALSE;
5935 LOGE("failed to autoplug %s", player->type);
5937 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5939 if (async && player->msg_posted == FALSE)
5940 __mmplayer_handle_missed_plugin(player);
5942 gst_object_unref(GST_OBJECT(pad));
5949 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5951 GstElement *decodebin = NULL;
5955 /* create decodebin */
5956 decodebin = gst_element_factory_make("decodebin", NULL);
5959 LOGE("fail to create decodebin");
5963 /* raw pad handling signal */
5964 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5965 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5967 /* no-more-pad pad handling signal */
5968 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5969 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5971 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5972 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
5974 /* This signal is emitted when a pad for which there is no further possible
5975 decoding is added to the decodebin.*/
5976 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5977 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
5979 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5980 before looking for any elements that can handle that stream.*/
5981 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5982 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5984 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5985 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5986 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5988 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5989 before looking for any elements that can handle that stream.*/
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5991 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5993 /* This signal is emitted once decodebin has finished decoding all the data.*/
5994 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5995 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
5997 /* This signal is emitted when a element is added to the bin.*/
5998 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5999 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6006 __mmplayer_gst_make_queue2(mmplayer_t *player)
6008 GstElement *queue2 = NULL;
6009 gint64 dur_bytes = 0L;
6010 mmplayer_gst_element_t *mainbin = NULL;
6011 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6014 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6016 mainbin = player->pipeline->mainbin;
6018 queue2 = gst_element_factory_make("queue2", "queue2");
6020 LOGE("failed to create buffering queue element");
6024 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6025 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6027 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6029 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6030 * skip the pull mode(file or ring buffering) setting. */
6031 if (dur_bytes > 0) {
6032 if (!g_strrstr(player->type, "video/mpegts")) {
6033 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6034 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6040 _mm_player_streaming_set_queue2(player->streamer,
6044 (guint64)dur_bytes); /* no meaning at the moment */
6050 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6052 mmplayer_gst_element_t *mainbin = NULL;
6053 GstElement *decodebin = NULL;
6054 GstElement *queue2 = NULL;
6055 GstPad *sinkpad = NULL;
6056 GstPad *qsrcpad = NULL;
6059 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6061 mainbin = player->pipeline->mainbin;
6063 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6065 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6066 LOGW("need to check: muxed buffer is not null");
6069 queue2 = __mmplayer_gst_make_queue2(player);
6071 LOGE("failed to make queue2");
6075 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6076 LOGE("failed to add buffering queue");
6080 sinkpad = gst_element_get_static_pad(queue2, "sink");
6081 qsrcpad = gst_element_get_static_pad(queue2, "src");
6083 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6084 LOGE("failed to link [%s:%s]-[%s:%s]",
6085 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6089 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6090 LOGE("failed to sync queue2 state with parent");
6094 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6095 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6099 gst_object_unref(GST_OBJECT(sinkpad));
6103 /* create decodebin */
6104 decodebin = _mmplayer_gst_make_decodebin(player);
6106 LOGE("failed to make decodebin");
6110 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6111 LOGE("failed to add decodebin");
6115 /* to force caps on the decodebin element and avoid reparsing stuff by
6116 * typefind. It also avoids a deadlock in the way typefind activates pads in
6117 * the state change */
6118 g_object_set(decodebin, "sink-caps", caps, NULL);
6120 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6122 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6123 LOGE("failed to link [%s:%s]-[%s:%s]",
6124 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6128 gst_object_unref(GST_OBJECT(sinkpad));
6130 gst_object_unref(GST_OBJECT(qsrcpad));
6133 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6134 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6136 /* set decodebin property about buffer in streaming playback. *
6137 * in case of HLS/DASH, it does not need to have big buffer *
6138 * because it is kind of adaptive streaming. */
6139 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6140 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6141 gint high_percent = 0;
6143 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6144 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6146 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6148 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6150 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6151 "high-percent", high_percent,
6152 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6153 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6154 "max-size-buffers", 0, NULL); // disable or automatic
6157 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6158 LOGE("failed to sync decodebin state with parent");
6169 gst_object_unref(GST_OBJECT(sinkpad));
6172 gst_object_unref(GST_OBJECT(qsrcpad));
6175 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6176 * You need to explicitly set elements to the NULL state before
6177 * dropping the final reference, to allow them to clean up.
6179 gst_element_set_state(queue2, GST_STATE_NULL);
6181 /* And, it still has a parent "player".
6182 * You need to let the parent manage the object instead of unreffing the object directly.
6184 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6185 gst_object_unref(queue2);
6190 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6191 * You need to explicitly set elements to the NULL state before
6192 * dropping the final reference, to allow them to clean up.
6194 gst_element_set_state(decodebin, GST_STATE_NULL);
6196 /* And, it still has a parent "player".
6197 * You need to let the parent manage the object instead of unreffing the object directly.
6200 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6201 gst_object_unref(decodebin);
6209 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6213 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6214 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6216 LOGD("class : %s, mime : %s", factory_class, mime);
6218 /* add missing plugin */
6219 /* NOTE : msl should check missing plugin for image mime type.
6220 * Some motion jpeg clips can have playable audio track.
6221 * So, msl have to play audio after displaying popup written video format not supported.
6223 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6224 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6225 LOGD("not found demuxer");
6226 player->not_found_demuxer = TRUE;
6227 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6233 if (!g_strrstr(factory_class, "Demuxer")) {
6234 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6235 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6236 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6238 /* check that clip have multi tracks or not */
6239 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6240 LOGD("video plugin is already linked");
6242 LOGW("add VIDEO to missing plugin");
6243 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6244 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6246 } else if (g_str_has_prefix(mime, "audio")) {
6247 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6248 LOGD("audio plugin is already linked");
6250 LOGW("add AUDIO to missing plugin");
6251 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6252 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6260 return MM_ERROR_NONE;
6264 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6266 mmplayer_t *player = (mmplayer_t *)data;
6270 MMPLAYER_RETURN_IF_FAIL(player);
6272 /* remove fakesink. */
6273 if (!_mmplayer_gst_remove_fakesink(player,
6274 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6275 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6276 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6277 * source element are not same. To overcome this situation, this function will called
6278 * several places and several times. Therefore, this is not an error case.
6283 LOGD("[handle: %p] pipeline has completely constructed", player);
6285 if ((player->msg_posted == FALSE) &&
6286 (player->cmd >= MMPLAYER_COMMAND_START))
6287 __mmplayer_handle_missed_plugin(player);
6289 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6293 __mmplayer_check_profile(void)
6296 static int profile_tv = -1;
6298 if (__builtin_expect(profile_tv != -1, 1))
6301 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6302 switch (*profileName) {
6317 __mmplayer_get_next_uri(mmplayer_t *player)
6319 mmplayer_parse_profile_t profile;
6321 guint num_of_list = 0;
6324 num_of_list = g_list_length(player->uri_info.uri_list);
6325 uri_idx = player->uri_info.uri_idx;
6327 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6328 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6329 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6331 LOGW("next uri does not exist");
6335 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6336 LOGE("failed to parse profile");
6340 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6341 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6342 LOGW("uri type is not supported(%d)", profile.uri_type);
6346 LOGD("success to find next uri %d", uri_idx);
6350 if (!uri || uri_idx == num_of_list) {
6351 LOGE("failed to find next uri");
6355 player->uri_info.uri_idx = uri_idx;
6356 if (mm_player_set_attribute((MMHandleType)player, NULL,
6357 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6358 LOGE("failed to set attribute");
6362 SECURE_LOGD("next playback uri: %s", uri);
6367 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6369 #define REPEAT_COUNT_INFINITE -1
6370 #define REPEAT_COUNT_MIN 2
6371 #define ORIGINAL_URI_ONLY 1
6373 MMHandleType attrs = 0;
6377 guint num_of_uri = 0;
6378 int profile_tv = -1;
6382 LOGD("checking for gapless play option");
6384 if (player->build_audio_offload) {
6385 LOGE("offload path is not supportable.");
6389 if (player->pipeline->textbin) {
6390 LOGE("subtitle path is enabled. gapless play is not supported.");
6394 attrs = MMPLAYER_GET_ATTRS(player);
6396 LOGE("fail to get attributes.");
6400 mm_attrs_multiple_get(player->attrs, NULL,
6401 "content_video_found", &video,
6402 "profile_play_count", &count,
6403 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6405 /* gapless playback is not supported in case of video at TV profile. */
6406 profile_tv = __mmplayer_check_profile();
6407 if (profile_tv && video) {
6408 LOGW("not support video gapless playback");
6412 /* check repeat count in case of audio */
6414 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6415 LOGW("gapless is disabled");
6419 num_of_uri = g_list_length(player->uri_info.uri_list);
6421 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6423 if (num_of_uri == ORIGINAL_URI_ONLY) {
6424 /* audio looping path */
6425 if (count >= REPEAT_COUNT_MIN) {
6426 /* decrease play count */
6427 /* we succeeded to rewind. update play count and then wait for next EOS */
6429 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6430 } else if (count != REPEAT_COUNT_INFINITE) {
6431 LOGD("there is no next uri and no repeat");
6434 LOGD("looping cnt %d", count);
6436 /* gapless playback path */
6437 if (!__mmplayer_get_next_uri(player)) {
6438 LOGE("failed to get next uri");
6445 LOGE("unable to play gapless path. EOS will be posted soon");
6450 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6452 mmplayer_track_t *selector = &player->track[type];
6453 mmplayer_gst_element_t *sinkbin = NULL;
6454 main_element_id_e selectorId = MMPLAYER_M_NUM;
6455 main_element_id_e sinkId = MMPLAYER_M_NUM;
6456 GstPad *srcpad = NULL;
6457 GstPad *sinkpad = NULL;
6458 gboolean send_notice = FALSE;
6461 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6463 LOGD("type %d", type);
6466 case MM_PLAYER_TRACK_TYPE_AUDIO:
6467 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6468 sinkId = MMPLAYER_A_BIN;
6469 sinkbin = player->pipeline->audiobin;
6471 case MM_PLAYER_TRACK_TYPE_VIDEO:
6472 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6473 sinkId = MMPLAYER_V_BIN;
6474 sinkbin = player->pipeline->videobin;
6477 case MM_PLAYER_TRACK_TYPE_TEXT:
6478 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6479 sinkId = MMPLAYER_T_BIN;
6480 sinkbin = player->pipeline->textbin;
6483 LOGE("requested type is not supportable");
6488 if (player->pipeline->mainbin[selectorId].gst) {
6491 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6493 if (selector->event_probe_id != 0)
6494 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6495 selector->event_probe_id = 0;
6497 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6498 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6500 if (srcpad && sinkpad) {
6501 /* after getting drained signal there is no data flows, so no need to do pad_block */
6502 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6503 gst_pad_unlink(srcpad, sinkpad);
6505 /* send custom event to sink pad to handle it at video sink */
6507 LOGD("send custom event to sinkpad");
6508 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6509 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6510 gst_pad_send_event(sinkpad, event);
6514 gst_object_unref(sinkpad);
6517 gst_object_unref(srcpad);
6520 LOGD("selector release");
6522 /* release and unref requests pad from the selector */
6523 for (n = 0; n < selector->streams->len; n++) {
6524 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6525 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6528 g_ptr_array_set_size(selector->streams, 0);
6530 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6531 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6533 player->pipeline->mainbin[selectorId].gst = NULL;
6541 __mmplayer_deactivate_old_path(mmplayer_t *player)
6544 MMPLAYER_RETURN_IF_FAIL(player);
6546 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6547 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6548 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6549 LOGE("deactivate selector error");
6553 _mmplayer_track_destroy(player);
6554 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6556 if (player->streamer) {
6557 _mm_player_streaming_initialize(player->streamer, FALSE);
6558 _mm_player_streaming_destroy(player->streamer);
6559 player->streamer = NULL;
6562 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6568 if (!player->msg_posted) {
6569 MMMessageParamType msg = {0,};
6572 msg.code = MM_ERROR_PLAYER_INTERNAL;
6573 LOGE("gapless_uri_play> deactivate error");
6575 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6576 player->msg_posted = TRUE;
6582 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6584 int result = MM_ERROR_NONE;
6585 mmplayer_t *player = (mmplayer_t *)hplayer;
6588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6589 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6591 if (mm_player_set_attribute(hplayer, NULL,
6592 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6593 LOGE("failed to set attribute");
6594 result = MM_ERROR_PLAYER_INTERNAL;
6596 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6597 LOGE("failed to add the original uri in the uri list.");
6605 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6607 mmplayer_t *player = (mmplayer_t *)hplayer;
6608 guint num_of_list = 0;
6612 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6613 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6615 if (player->pipeline && player->pipeline->textbin) {
6616 LOGE("subtitle path is enabled.");
6617 return MM_ERROR_PLAYER_INVALID_STATE;
6620 num_of_list = g_list_length(player->uri_info.uri_list);
6622 if (is_first_path) {
6623 if (num_of_list == 0) {
6624 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6625 SECURE_LOGD("add original path : %s", uri);
6627 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6628 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6630 SECURE_LOGD("change original path : %s", uri);
6633 MMHandleType attrs = 0;
6634 attrs = MMPLAYER_GET_ATTRS(player);
6636 if (num_of_list == 0) {
6637 char *original_uri = NULL;
6640 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6642 if (!original_uri) {
6643 LOGE("there is no original uri.");
6644 return MM_ERROR_PLAYER_INVALID_STATE;
6647 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6648 player->uri_info.uri_idx = 0;
6650 SECURE_LOGD("add original path at first : %s", original_uri);
6654 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6655 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6659 return MM_ERROR_NONE;
6663 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6665 mmplayer_t *player = (mmplayer_t *)hplayer;
6666 char *next_uri = NULL;
6667 guint num_of_list = 0;
6670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6672 num_of_list = g_list_length(player->uri_info.uri_list);
6674 if (num_of_list > 0) {
6675 gint uri_idx = player->uri_info.uri_idx;
6677 if (uri_idx < num_of_list-1)
6682 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6683 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6685 *uri = g_strdup(next_uri);
6689 return MM_ERROR_NONE;
6693 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6694 GstCaps *caps, gpointer data)
6696 mmplayer_t *player = (mmplayer_t *)data;
6697 const gchar *klass = NULL;
6698 const gchar *mime = NULL;
6699 gchar *caps_str = NULL;
6701 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6702 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6703 caps_str = gst_caps_to_string(caps);
6705 LOGW("unknown type of caps : %s from %s",
6706 caps_str, GST_ELEMENT_NAME(elem));
6708 MMPLAYER_FREEIF(caps_str);
6710 /* There is no available codec. */
6711 __mmplayer_check_not_supported_codec(player, klass, mime);
6715 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6716 GstCaps *caps, gpointer data)
6718 mmplayer_t *player = (mmplayer_t *)data;
6719 const char *mime = NULL;
6720 gboolean ret = TRUE;
6722 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6723 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6725 if (g_str_has_prefix(mime, "audio")) {
6726 GstStructure *caps_structure = NULL;
6727 gint samplerate = 0;
6729 gchar *caps_str = NULL;
6731 caps_structure = gst_caps_get_structure(caps, 0);
6732 gst_structure_get_int(caps_structure, "rate", &samplerate);
6733 gst_structure_get_int(caps_structure, "channels", &channels);
6735 if ((channels > 0 && samplerate == 0)) {
6736 LOGD("exclude audio...");
6740 caps_str = gst_caps_to_string(caps);
6741 /* set it directly because not sent by TAG */
6742 if (g_strrstr(caps_str, "mobile-xmf"))
6743 mm_player_set_attribute((MMHandleType)player, NULL,
6744 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6746 MMPLAYER_FREEIF(caps_str);
6747 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6748 LOGD("already video linked");
6751 LOGD("found new stream");
6758 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6760 gboolean ret = FALSE;
6761 GDBusConnection *conn = NULL;
6763 GVariant *result = NULL;
6764 const gchar *dbus_device_type = NULL;
6765 const gchar *dbus_ret = NULL;
6768 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6770 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6775 result = g_dbus_connection_call_sync(conn,
6776 "org.pulseaudio.Server",
6777 "/org/pulseaudio/StreamManager",
6778 "org.pulseaudio.StreamManager",
6779 "GetCurrentMediaRoutingPath",
6780 g_variant_new("(s)", "out"),
6781 G_VARIANT_TYPE("(ss)"),
6782 G_DBUS_CALL_FLAGS_NONE,
6786 if (!result || err) {
6787 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6792 /* device type is listed in stream-map.json at mmfw-sysconf */
6793 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6795 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6796 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6799 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6800 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6801 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6802 LOGD("audio offload is supportable");
6808 LOGD("audio offload is not supportable");
6811 g_variant_unref(result);
6813 g_object_unref(conn);
6818 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6820 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6821 gint64 position = 0;
6823 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6824 player->pipeline && player->pipeline->mainbin);
6826 MMPLAYER_CMD_LOCK(player);
6827 current_state = MMPLAYER_CURRENT_STATE(player);
6829 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6830 LOGW("getting current position failed in paused");
6832 _mmplayer_unrealize((MMHandleType)player);
6833 _mmplayer_realize((MMHandleType)player);
6835 _mmplayer_set_position((MMHandleType)player, position);
6837 /* async not to be blocked in streaming case */
6838 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6840 _mmplayer_pause((MMHandleType)player);
6842 if (current_state == MM_PLAYER_STATE_PLAYING)
6843 _mmplayer_start((MMHandleType)player);
6844 MMPLAYER_CMD_UNLOCK(player);
6846 LOGD("rebuilding audio pipeline is completed.");
6849 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6851 mmplayer_t *player = (mmplayer_t *)user_data;
6852 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6853 gboolean is_supportable = FALSE;
6855 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6856 LOGW("failed to get device type");
6858 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6860 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6861 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6862 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6863 LOGD("ignore this dev connected info");
6867 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6868 if (player->build_audio_offload == is_supportable) {
6869 LOGD("keep current pipeline without re-building");
6873 /* rebuild pipeline */
6874 LOGD("re-build pipeline - offload: %d", is_supportable);
6875 player->build_audio_offload = FALSE;
6876 __mmplayer_rebuild_audio_pipeline(player);
6882 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6884 unsigned int id = 0;
6886 if (player->audio_device_cb_id != 0) {
6887 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6891 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6892 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6893 LOGD("added device connected cb (%u)", id);
6894 player->audio_device_cb_id = id;
6896 LOGW("failed to add device connected cb");
6903 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6905 mmplayer_t *player = (mmplayer_t *)hplayer;
6908 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6909 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6911 *activated = player->build_audio_offload;
6913 LOGD("offload activated : %d", (int)*activated);
6916 return MM_ERROR_NONE;
6920 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6923 this function need to be updated according to the supported media format
6924 @see player->ini.audio_offload_media_format */
6926 if (__mmplayer_is_only_mp3_type(player->type)) {
6927 LOGD("offload supportable media format type");
6935 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6937 gboolean ret = FALSE;
6938 GstElementFactory *factory = NULL;
6941 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6943 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6944 if (!__mmplayer_is_offload_supported_type(player))
6947 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6948 LOGD("there is no audio offload sink");
6952 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6953 LOGW("there is no audio device type to support offload");
6957 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6959 LOGW("there is no installed audio offload sink element");
6962 gst_object_unref(factory);
6964 if (__mmplayer_acquire_hw_resource(player,
6965 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6966 LOGE("failed to acquire audio offload decoder resource");
6970 if (!__mmplayer_add_audio_device_connected_cb(player))
6973 if (!__mmplayer_is_audio_offload_device_type(player))
6976 LOGD("audio offload can be built");
6981 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6987 static GstAutoplugSelectResult
6988 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6990 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6991 int audio_offload = 0;
6993 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6994 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6996 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6997 LOGD("expose audio path to build offload output path");
6998 player->build_audio_offload = TRUE;
6999 /* update codec info */
7000 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7001 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7002 player->audiodec_linked = 1;
7004 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7008 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7009 And need to consider the multi-track audio content.
7010 There is no HW audio decoder in public. */
7012 /* set stream information */
7013 if (!player->audiodec_linked)
7014 __mmplayer_set_audio_attrs(player, caps);
7016 /* update codec info */
7017 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7018 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7019 player->audiodec_linked = 1;
7021 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7023 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7024 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7026 /* mark video decoder for acquire */
7027 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7028 LOGW("video decoder resource is already acquired, skip it.");
7029 ret = GST_AUTOPLUG_SELECT_SKIP;
7033 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7034 LOGE("failed to acquire video decoder resource");
7035 ret = GST_AUTOPLUG_SELECT_SKIP;
7038 player->interrupted_by_resource = FALSE;
7041 /* update codec info */
7042 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7043 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7044 player->videodec_linked = 1;
7052 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7053 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7055 #define DEFAULT_IDX 0xFFFF
7056 #define MIN_FACTORY_NUM 2
7057 mmplayer_t *player = (mmplayer_t *)data;
7058 GValueArray *new_factories = NULL;
7059 GValue val = { 0, };
7060 GstElementFactory *factory = NULL;
7061 const gchar *klass = NULL;
7062 gchar *factory_name = NULL;
7063 guint hw_dec_idx = DEFAULT_IDX;
7064 guint first_sw_dec_idx = DEFAULT_IDX;
7065 guint last_sw_dec_idx = DEFAULT_IDX;
7066 guint new_pos = DEFAULT_IDX;
7067 guint rm_pos = DEFAULT_IDX;
7068 int audio_codec_type;
7069 int video_codec_type;
7070 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7072 if (factories->n_values < MIN_FACTORY_NUM)
7075 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7076 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7079 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7081 for (int i = 0 ; i < factories->n_values ; i++) {
7082 gchar *hw_dec_info = NULL;
7083 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7085 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7087 LOGW("failed to get factory object");
7090 klass = gst_element_factory_get_klass(factory);
7091 factory_name = GST_OBJECT_NAME(factory);
7094 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7096 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7097 if (!player->need_audio_dec_sorting) {
7098 LOGD("sorting is not required");
7101 codec_type = audio_codec_type;
7102 hw_dec_info = player->ini.audiocodec_element_hw;
7103 sw_dec_info = player->ini.audiocodec_element_sw;
7104 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7105 if (!player->need_video_dec_sorting) {
7106 LOGD("sorting is not required");
7109 codec_type = video_codec_type;
7110 hw_dec_info = player->ini.videocodec_element_hw;
7111 sw_dec_info = player->ini.videocodec_element_sw;
7116 if (g_strrstr(factory_name, hw_dec_info)) {
7119 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7120 if (strstr(factory_name, sw_dec_info[j])) {
7121 last_sw_dec_idx = i;
7122 if (first_sw_dec_idx == DEFAULT_IDX) {
7123 first_sw_dec_idx = i;
7128 if (first_sw_dec_idx == DEFAULT_IDX)
7129 LOGW("unknown codec %s", factory_name);
7133 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7136 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7137 if (hw_dec_idx < first_sw_dec_idx)
7139 new_pos = first_sw_dec_idx;
7140 rm_pos = hw_dec_idx + 1;
7141 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7142 if (last_sw_dec_idx < hw_dec_idx)
7144 new_pos = last_sw_dec_idx + 1;
7145 rm_pos = hw_dec_idx;
7150 /* change position - insert H/W decoder according to the new position */
7151 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7153 LOGW("failed to get factory object");
7156 new_factories = g_value_array_copy(factories);
7157 g_value_init (&val, G_TYPE_OBJECT);
7158 g_value_set_object (&val, factory);
7159 g_value_array_insert(new_factories, new_pos, &val);
7160 g_value_unset (&val);
7161 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7163 for (int i = 0 ; i < new_factories->n_values ; i++) {
7164 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7166 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7167 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7169 LOGE("[Re-arranged] failed to get factory object");
7172 return new_factories;
7176 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7177 GstCaps *caps, GstElementFactory *factory, gpointer data)
7179 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7180 mmplayer_t *player = (mmplayer_t *)data;
7182 gchar *factory_name = NULL;
7183 gchar *caps_str = NULL;
7184 const gchar *klass = NULL;
7187 factory_name = GST_OBJECT_NAME(factory);
7188 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7189 caps_str = gst_caps_to_string(caps);
7191 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7193 /* store type string */
7194 if (player->type == NULL) {
7195 player->type = gst_caps_to_string(caps);
7196 __mmplayer_update_content_type_info(player);
7199 /* filtering exclude keyword */
7200 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7201 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7202 LOGW("skipping [%s] by exculde keyword [%s]",
7203 factory_name, player->ini.exclude_element_keyword[idx]);
7205 result = GST_AUTOPLUG_SELECT_SKIP;
7210 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7211 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7212 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7213 factory_name, player->ini.unsupported_codec_keyword[idx]);
7214 result = GST_AUTOPLUG_SELECT_SKIP;
7219 /* exclude webm format */
7220 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7221 * because webm format is not supportable.
7222 * If webm is disabled in "autoplug-continue", there is no state change
7223 * failure or error because the decodebin will expose the pad directly.
7224 * It make MSL invoke _prepare_async_callback.
7225 * So, we need to disable webm format in "autoplug-select" */
7226 if (caps_str && strstr(caps_str, "webm")) {
7227 LOGW("webm is not supported");
7228 result = GST_AUTOPLUG_SELECT_SKIP;
7232 /* check factory class for filtering */
7233 /* NOTE : msl don't need to use image plugins.
7234 * So, those plugins should be skipped for error handling.
7236 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7237 LOGD("skipping [%s] by not required", factory_name);
7238 result = GST_AUTOPLUG_SELECT_SKIP;
7242 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7243 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7244 // TO CHECK : subtitle if needed, add subparse exception.
7245 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7246 result = GST_AUTOPLUG_SELECT_SKIP;
7250 if (g_strrstr(factory_name, "mpegpsdemux")) {
7251 LOGD("skipping PS container - not support");
7252 result = GST_AUTOPLUG_SELECT_SKIP;
7256 if (g_strrstr(factory_name, "mssdemux"))
7257 player->smooth_streaming = TRUE;
7259 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7260 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7263 GstStructure *str = NULL;
7264 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7266 /* don't make video because of not required */
7267 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7268 (!player->set_mode.video_export)) {
7269 LOGD("no need video decoding, expose pad");
7270 result = GST_AUTOPLUG_SELECT_EXPOSE;
7274 /* get w/h for omx state-tune */
7275 /* FIXME: deprecated? */
7276 str = gst_caps_get_structure(caps, 0);
7277 gst_structure_get_int(str, "width", &width);
7280 if (player->v_stream_caps) {
7281 gst_caps_unref(player->v_stream_caps);
7282 player->v_stream_caps = NULL;
7285 player->v_stream_caps = gst_caps_copy(caps);
7286 LOGD("take caps for video state tune");
7287 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7291 if (g_strrstr(klass, "Codec/Decoder")) {
7292 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7293 if (result != GST_AUTOPLUG_SELECT_TRY) {
7294 LOGW("skip add decoder");
7300 MMPLAYER_FREEIF(caps_str);
7306 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7309 //mmplayer_t *player = (mmplayer_t *)data;
7310 GstCaps *caps = NULL;
7312 LOGD("[Decodebin2] pad-removed signal");
7314 caps = gst_pad_query_caps(new_pad, NULL);
7316 LOGW("query caps is NULL");
7320 gchar *caps_str = NULL;
7321 caps_str = gst_caps_to_string(caps);
7323 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7325 MMPLAYER_FREEIF(caps_str);
7326 gst_caps_unref(caps);
7330 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7332 mmplayer_t *player = (mmplayer_t *)data;
7333 GstIterator *iter = NULL;
7334 GValue item = { 0, };
7336 gboolean done = FALSE;
7337 gboolean is_all_drained = TRUE;
7340 MMPLAYER_RETURN_IF_FAIL(player);
7342 LOGD("got drained signal");
7344 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7345 LOGW("Fail to get cmd lock");
7349 if (!__mmplayer_verify_gapless_play_path(player)) {
7350 LOGD("decoding is finished.");
7351 MMPLAYER_CMD_UNLOCK(player);
7355 _mmplayer_set_reconfigure_state(player, TRUE);
7356 MMPLAYER_CMD_UNLOCK(player);
7358 /* check decodebin src pads whether they received EOS or not */
7359 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7362 switch (gst_iterator_next(iter, &item)) {
7363 case GST_ITERATOR_OK:
7364 pad = g_value_get_object(&item);
7365 if (pad && !GST_PAD_IS_EOS(pad)) {
7366 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7367 is_all_drained = FALSE;
7370 g_value_reset(&item);
7372 case GST_ITERATOR_RESYNC:
7373 gst_iterator_resync(iter);
7375 case GST_ITERATOR_ERROR:
7376 case GST_ITERATOR_DONE:
7381 g_value_unset(&item);
7382 gst_iterator_free(iter);
7384 if (!is_all_drained) {
7385 LOGD("Wait util the all pads get EOS.");
7390 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7391 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7393 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7394 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7395 __mmplayer_deactivate_old_path(player);
7401 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7403 mmplayer_t *player = (mmplayer_t *)data;
7404 const gchar *klass = NULL;
7405 gchar *factory_name = NULL;
7407 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7408 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7410 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7412 if (__mmplayer_add_dump_buffer_probe(player, element))
7413 LOGD("add buffer probe");
7415 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7416 gchar *selected = NULL;
7417 selected = g_strdup(GST_ELEMENT_NAME(element));
7418 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7421 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7422 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7423 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7425 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7426 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7428 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7429 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7430 "max-video-width", player->adaptive_info.limit.width,
7431 "max-video-height", player->adaptive_info.limit.height, NULL);
7433 } else if (g_strrstr(klass, "Demuxer")) {
7435 LOGD("plugged element is demuxer. take it");
7437 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7438 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7441 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7442 int surface_type = 0;
7444 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7447 // to support trust-zone only
7448 if (g_strrstr(factory_name, "asfdemux")) {
7449 LOGD("set file-location %s", player->profile.uri);
7450 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7451 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7452 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7453 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7454 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7455 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7456 (__mmplayer_is_only_mp3_type(player->type))) {
7457 LOGD("[mpegaudioparse] set streaming pull mode.");
7458 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7460 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7461 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7464 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7465 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7466 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7468 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7469 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7471 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7472 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7473 (MMPLAYER_IS_DASH_STREAMING(player))) {
7474 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7475 _mm_player_streaming_set_multiqueue(player->streamer, element);
7476 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7485 __mmplayer_release_misc(mmplayer_t *player)
7488 bool cur_mode = player->set_mode.rich_audio;
7491 MMPLAYER_RETURN_IF_FAIL(player);
7493 player->sent_bos = FALSE;
7494 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7496 player->seek_state = MMPLAYER_SEEK_NONE;
7498 player->total_bitrate = 0;
7499 player->total_maximum_bitrate = 0;
7501 player->not_found_demuxer = 0;
7503 player->last_position = 0;
7504 player->duration = 0;
7505 player->http_content_size = 0;
7506 player->not_supported_codec = MISSING_PLUGIN_NONE;
7507 player->can_support_codec = FOUND_PLUGIN_NONE;
7508 player->pending_seek.is_pending = false;
7509 player->pending_seek.pos = 0;
7510 player->msg_posted = FALSE;
7511 player->has_many_types = FALSE;
7512 player->is_subtitle_force_drop = FALSE;
7513 player->play_subtitle = FALSE;
7514 player->adjust_subtitle_pos = 0;
7515 player->has_closed_caption = FALSE;
7516 player->set_mode.video_export = false;
7517 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7518 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7520 player->set_mode.rich_audio = cur_mode;
7522 if (player->audio_device_cb_id > 0 &&
7523 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7524 LOGW("failed to remove audio device_connected_callback");
7525 player->audio_device_cb_id = 0;
7527 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7528 player->bitrate[i] = 0;
7529 player->maximum_bitrate[i] = 0;
7532 /* free memory related to audio effect */
7533 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7535 if (player->adaptive_info.var_list) {
7536 g_list_free_full(player->adaptive_info.var_list, g_free);
7537 player->adaptive_info.var_list = NULL;
7540 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7541 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7542 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7544 /* Reset video360 settings to their defaults in case if the pipeline is to be
7547 player->video360_metadata.is_spherical = -1;
7548 player->is_openal_plugin_used = FALSE;
7550 player->is_content_spherical = FALSE;
7551 player->is_video360_enabled = TRUE;
7552 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7553 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7554 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7555 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7556 player->video360_zoom = 1.0f;
7557 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7558 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7560 player->sound.rg_enable = false;
7562 __mmplayer_initialize_video_roi(player);
7567 __mmplayer_release_misc_post(mmplayer_t *player)
7569 char *original_uri = NULL;
7572 /* player->pipeline is already released before. */
7573 MMPLAYER_RETURN_IF_FAIL(player);
7575 player->video_decoded_cb = NULL;
7576 player->video_decoded_cb_user_param = NULL;
7577 player->video_stream_prerolled = false;
7579 player->audio_decoded_cb = NULL;
7580 player->audio_decoded_cb_user_param = NULL;
7581 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7583 player->audio_stream_changed_cb = NULL;
7584 player->audio_stream_changed_cb_user_param = NULL;
7586 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7588 /* clean found audio decoders */
7589 if (player->audio_decoders) {
7590 GList *a_dec = player->audio_decoders;
7591 for (; a_dec; a_dec = g_list_next(a_dec)) {
7592 gchar *name = a_dec->data;
7593 MMPLAYER_FREEIF(name);
7595 g_list_free(player->audio_decoders);
7596 player->audio_decoders = NULL;
7599 /* clean the uri list except original uri */
7600 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7601 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7603 LOGW("failed to get original uri info");
7605 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7606 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7608 GList *uri_list = player->uri_info.uri_list;
7609 for (; uri_list; uri_list = g_list_next(uri_list)) {
7610 gchar *uri = uri_list->data;
7611 if (original_uri != uri)
7612 MMPLAYER_FREEIF(uri);
7616 /* clear the audio stream buffer list */
7617 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7619 /* clear the video stream bo list */
7620 __mmplayer_video_stream_destroy_bo_list(player);
7621 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7623 if (player->profile.input_mem.buf) {
7624 free(player->profile.input_mem.buf);
7625 player->profile.input_mem.buf = NULL;
7627 player->profile.input_mem.len = 0;
7628 player->profile.input_mem.offset = 0;
7630 player->uri_info.uri_idx = 0;
7635 __mmplayer_check_subtitle(mmplayer_t *player)
7637 MMHandleType attrs = 0;
7638 char *subtitle_uri = NULL;
7642 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7644 /* get subtitle attribute */
7645 attrs = MMPLAYER_GET_ATTRS(player);
7649 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7650 if (!subtitle_uri || !strlen(subtitle_uri))
7653 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7654 player->is_external_subtitle_present = TRUE;
7662 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7664 MMPLAYER_RETURN_IF_FAIL(player);
7666 if (player->eos_timer) {
7667 LOGD("cancel eos timer");
7668 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7669 player->eos_timer = 0;
7676 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7680 MMPLAYER_RETURN_IF_FAIL(player);
7681 MMPLAYER_RETURN_IF_FAIL(sink);
7683 player->sink_elements = g_list_append(player->sink_elements, sink);
7689 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7693 MMPLAYER_RETURN_IF_FAIL(player);
7694 MMPLAYER_RETURN_IF_FAIL(sink);
7696 player->sink_elements = g_list_remove(player->sink_elements, sink);
7702 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7703 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7705 mmplayer_signal_item_t *item = NULL;
7708 MMPLAYER_RETURN_IF_FAIL(player);
7710 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7711 LOGE("invalid signal type [%d]", type);
7715 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7717 LOGE("cannot connect signal [%s]", signal);
7722 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7723 player->signals[type] = g_list_append(player->signals[type], item);
7729 /* NOTE : be careful with calling this api. please refer to below glib comment
7730 * glib comment : Note that there is a bug in GObject that makes this function much
7731 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7732 * will no longer be called, but, the signal handler is not currently disconnected.
7733 * If the instance is itself being freed at the same time than this doesn't matter,
7734 * since the signal will automatically be removed, but if instance persists,
7735 * then the signal handler will leak. You should not remove the signal yourself
7736 * because in a future versions of GObject, the handler will automatically be
7739 * It's possible to work around this problem in a way that will continue to work
7740 * with future versions of GObject by checking that the signal handler is still
7741 * connected before disconnected it:
7743 * if (g_signal_handler_is_connected(instance, id))
7744 * g_signal_handler_disconnect(instance, id);
7747 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7749 GList *sig_list = NULL;
7750 mmplayer_signal_item_t *item = NULL;
7754 MMPLAYER_RETURN_IF_FAIL(player);
7756 LOGD("release signals type : %d", type);
7758 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7759 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7760 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7761 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7767 sig_list = player->signals[type];
7769 for (; sig_list; sig_list = sig_list->next) {
7770 item = sig_list->data;
7772 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7773 if (g_signal_handler_is_connected(item->obj, item->sig))
7774 g_signal_handler_disconnect(item->obj, item->sig);
7777 MMPLAYER_FREEIF(item);
7780 g_list_free(player->signals[type]);
7781 player->signals[type] = NULL;
7789 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7791 mmplayer_t *player = 0;
7792 int prev_display_surface_type = 0;
7796 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7798 player = MM_PLAYER_CAST(handle);
7800 /* check video sinkbin is created */
7801 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7802 LOGW("Videosink is already created");
7803 return MM_ERROR_NONE;
7806 LOGD("videosink element is not yet ready");
7808 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7809 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7811 return MM_ERROR_INVALID_ARGUMENT;
7814 /* load previous attributes */
7815 if (player->attrs) {
7816 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7817 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7818 if (prev_display_surface_type == surface_type) {
7819 LOGD("incoming display surface type is same as previous one, do nothing..");
7821 return MM_ERROR_NONE;
7824 LOGE("failed to load attributes");
7826 return MM_ERROR_PLAYER_INTERNAL;
7829 /* videobin is not created yet, so we just set attributes related to display surface */
7830 LOGD("store display attribute for given surface type(%d)", surface_type);
7831 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7832 "display_overlay", wl_surface_id, NULL);
7835 return MM_ERROR_NONE;
7838 /* Note : if silent is true, then subtitle would not be displayed. :*/
7840 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7842 mmplayer_t *player = (mmplayer_t *)hplayer;
7846 /* check player handle */
7847 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7849 player->set_mode.subtitle_off = silent;
7851 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7855 return MM_ERROR_NONE;
7859 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7861 mmplayer_gst_element_t *mainbin = NULL;
7862 mmplayer_gst_element_t *textbin = NULL;
7863 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7864 GstState current_state = GST_STATE_VOID_PENDING;
7865 GstState element_state = GST_STATE_VOID_PENDING;
7866 GstState element_pending_state = GST_STATE_VOID_PENDING;
7868 GstEvent *event = NULL;
7869 int result = MM_ERROR_NONE;
7871 GstClock *curr_clock = NULL;
7872 GstClockTime base_time, start_time, curr_time;
7877 /* check player handle */
7878 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7880 player->pipeline->mainbin &&
7881 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7883 mainbin = player->pipeline->mainbin;
7884 textbin = player->pipeline->textbin;
7886 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7888 // sync clock with current pipeline
7889 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7890 curr_time = gst_clock_get_time(curr_clock);
7892 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7893 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7895 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7896 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7898 if (current_state > GST_STATE_READY) {
7899 // sync state with current pipeline
7900 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7901 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7902 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7904 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7905 if (GST_STATE_CHANGE_FAILURE == ret) {
7906 LOGE("fail to state change.");
7907 result = MM_ERROR_PLAYER_INTERNAL;
7911 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7912 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7915 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7916 gst_object_unref(curr_clock);
7919 // seek to current position
7920 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7921 result = MM_ERROR_PLAYER_INVALID_STATE;
7922 LOGE("gst_element_query_position failed, invalid state");
7926 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7927 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);
7929 _mmplayer_gst_send_event_to_sink(player, event);
7931 result = MM_ERROR_PLAYER_INTERNAL;
7932 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7936 /* sync state with current pipeline */
7937 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7938 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7939 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7941 return MM_ERROR_NONE;
7944 /* release text pipeline resource */
7945 player->textsink_linked = 0;
7947 /* release signal */
7948 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7950 /* release textbin with it's childs */
7951 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7952 MMPLAYER_FREEIF(player->pipeline->textbin);
7953 player->pipeline->textbin = NULL;
7955 /* release subtitle elem */
7956 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7957 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7963 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7965 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7966 GstState current_state = GST_STATE_VOID_PENDING;
7968 MMHandleType attrs = 0;
7969 mmplayer_gst_element_t *mainbin = NULL;
7970 mmplayer_gst_element_t *textbin = NULL;
7972 gchar *subtitle_uri = NULL;
7973 int result = MM_ERROR_NONE;
7974 const gchar *charset = NULL;
7978 /* check player handle */
7979 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7981 player->pipeline->mainbin &&
7982 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7983 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7985 mainbin = player->pipeline->mainbin;
7986 textbin = player->pipeline->textbin;
7988 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7989 if (current_state < GST_STATE_READY) {
7990 result = MM_ERROR_PLAYER_INVALID_STATE;
7991 LOGE("Pipeline is not in proper state");
7995 attrs = MMPLAYER_GET_ATTRS(player);
7997 LOGE("cannot get content attribute");
7998 result = MM_ERROR_PLAYER_INTERNAL;
8002 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8003 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8004 LOGE("subtitle uri is not proper filepath");
8005 result = MM_ERROR_PLAYER_INVALID_URI;
8009 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8010 LOGE("failed to get storage info of subtitle path");
8011 result = MM_ERROR_PLAYER_INVALID_URI;
8015 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8016 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8018 if (!strcmp(filepath, subtitle_uri)) {
8019 LOGD("subtitle path is not changed");
8022 if (mm_player_set_attribute((MMHandleType)player, NULL,
8023 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8024 LOGE("failed to set attribute");
8029 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8030 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8031 player->subtitle_language_list = NULL;
8032 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8034 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8035 if (ret != GST_STATE_CHANGE_SUCCESS) {
8036 LOGE("failed to change state of textbin to READY");
8037 result = MM_ERROR_PLAYER_INTERNAL;
8041 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8042 if (ret != GST_STATE_CHANGE_SUCCESS) {
8043 LOGE("failed to change state of subparse to READY");
8044 result = MM_ERROR_PLAYER_INTERNAL;
8048 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8049 if (ret != GST_STATE_CHANGE_SUCCESS) {
8050 LOGE("failed to change state of filesrc to READY");
8051 result = MM_ERROR_PLAYER_INTERNAL;
8055 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8057 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8059 charset = _mmplayer_get_charset(filepath);
8061 LOGD("detected charset is %s", charset);
8062 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8065 result = _mmplayer_sync_subtitle_pipeline(player);
8072 /* API to switch between external subtitles */
8074 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8076 int result = MM_ERROR_NONE;
8077 mmplayer_t *player = (mmplayer_t *)hplayer;
8082 /* check player handle */
8083 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8085 /* filepath can be null in idle state */
8087 /* check file path */
8088 if ((path = strstr(filepath, "file://")))
8089 result = _mmplayer_exist_file_path(path + 7);
8091 result = _mmplayer_exist_file_path(filepath);
8093 if (result != MM_ERROR_NONE) {
8094 LOGE("invalid subtitle path 0x%X", result);
8095 return result; /* file not found or permission denied */
8099 if (!player->pipeline) {
8101 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8102 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8103 LOGE("failed to set attribute");
8104 return MM_ERROR_PLAYER_INTERNAL;
8107 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8108 /* check filepath */
8109 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8111 if (!__mmplayer_check_subtitle(player)) {
8112 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8113 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8114 LOGE("failed to set attribute");
8115 return MM_ERROR_PLAYER_INTERNAL;
8118 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8119 LOGE("fail to create text pipeline");
8120 return MM_ERROR_PLAYER_INTERNAL;
8123 result = _mmplayer_sync_subtitle_pipeline(player);
8125 result = __mmplayer_change_external_subtitle_language(player, filepath);
8128 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8129 player->is_external_subtitle_added_now = TRUE;
8131 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8132 if (!player->subtitle_language_list) {
8133 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8134 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8135 LOGW("subtitle language list is not updated yet");
8137 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8145 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8147 guint active_idx = 0;
8148 GstStream *stream = NULL;
8149 GList *streams = NULL;
8150 GstEvent *ev = NULL;
8152 LOGD("Switching Streams... type: %d, index: %d", type, index);
8154 player->track[type].active_track_index = index;
8156 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8157 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8158 if (player->track[i].total_track_num > 0) {
8159 active_idx = player->track[i].active_track_index;
8160 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8161 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8162 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8166 ev = gst_event_new_select_streams(streams);
8167 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8168 g_list_free(streams);
8170 return MM_ERROR_NONE;
8174 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8176 int result = MM_ERROR_NONE;
8177 gchar *change_pad_name = NULL;
8178 GstPad *sinkpad = NULL;
8179 mmplayer_gst_element_t *mainbin = NULL;
8180 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8181 GstCaps *caps = NULL;
8182 gint total_track_num = 0;
8186 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8187 MM_ERROR_PLAYER_NOT_INITIALIZED);
8189 LOGD("Change Track(%d) to %d", type, index);
8191 mainbin = player->pipeline->mainbin;
8193 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8194 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8195 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8196 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8198 /* Changing Video Track is not supported. */
8199 LOGE("Track Type Error");
8203 if (mainbin[elem_idx].gst == NULL) {
8204 result = MM_ERROR_PLAYER_NO_OP;
8205 LOGD("Req track doesn't exist");
8209 total_track_num = player->track[type].total_track_num;
8210 if (total_track_num <= 0) {
8211 result = MM_ERROR_PLAYER_NO_OP;
8212 LOGD("Language list is not available");
8216 if ((index < 0) || (index >= total_track_num)) {
8217 result = MM_ERROR_INVALID_ARGUMENT;
8218 LOGD("Not a proper index : %d", index);
8222 /*To get the new pad from the selector*/
8223 change_pad_name = g_strdup_printf("sink_%u", index);
8224 if (change_pad_name == NULL) {
8225 result = MM_ERROR_PLAYER_INTERNAL;
8226 LOGD("Pad does not exists");
8230 LOGD("new active pad name: %s", change_pad_name);
8232 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8233 if (sinkpad == NULL) {
8234 LOGD("sinkpad is NULL");
8235 result = MM_ERROR_PLAYER_INTERNAL;
8239 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8240 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8242 caps = gst_pad_get_current_caps(sinkpad);
8243 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8246 gst_object_unref(sinkpad);
8248 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8249 __mmplayer_set_audio_attrs(player, caps);
8252 MMPLAYER_FREEIF(change_pad_name);
8257 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8259 int result = MM_ERROR_NONE;
8260 mmplayer_t *player = NULL;
8261 mmplayer_gst_element_t *mainbin = NULL;
8263 gint current_active_index = 0;
8265 GstState current_state = GST_STATE_VOID_PENDING;
8270 player = (mmplayer_t *)hplayer;
8271 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8273 if (!player->pipeline) {
8274 LOGE("Track %d pre setting -> %d", type, index);
8276 player->track[type].active_track_index = index;
8280 mainbin = player->pipeline->mainbin;
8282 current_active_index = player->track[type].active_track_index;
8284 /*If index is same as running index no need to change the pad*/
8285 if (current_active_index == index)
8288 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8289 result = MM_ERROR_PLAYER_INVALID_STATE;
8293 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8294 if (current_state < GST_STATE_PAUSED) {
8295 result = MM_ERROR_PLAYER_INVALID_STATE;
8296 LOGW("Pipeline not in porper state");
8300 if (MMPLAYER_USE_URIDECODEBIN3(player)) {
8301 result = __mmplayer_switch_stream(player, type, index);
8303 result = __mmplayer_change_selector_pad(player, type, index);
8305 if (result != MM_ERROR_NONE) {
8306 LOGE("failed to change track");
8310 player->track[type].active_track_index = index;
8312 if (!MMPLAYER_USE_URIDECODEBIN3(player)) {
8313 GstEvent *event = NULL;
8314 if (current_state == GST_STATE_PLAYING) {
8315 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8316 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8317 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8319 _mmplayer_gst_send_event_to_sink(player, event);
8321 result = MM_ERROR_PLAYER_INTERNAL;
8332 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8334 mmplayer_t *player = (mmplayer_t *)hplayer;
8338 /* check player handle */
8339 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8341 *silent = player->set_mode.subtitle_off;
8343 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8347 return MM_ERROR_NONE;
8351 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8353 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8354 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8356 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8357 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8361 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8362 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8363 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8364 mmplayer_dump_t *dump_s;
8365 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8366 if (dump_s == NULL) {
8367 LOGE("malloc fail");
8371 dump_s->dump_element_file = NULL;
8372 dump_s->dump_pad = NULL;
8373 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8375 if (dump_s->dump_pad) {
8376 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8377 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]);
8378 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8379 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);
8380 /* add list for removed buffer probe and close FILE */
8381 player->dump_list = g_list_append(player->dump_list, dump_s);
8382 LOGD("%s sink pad added buffer probe for dump", factory_name);
8385 MMPLAYER_FREEIF(dump_s);
8386 LOGE("failed to get %s sink pad added", factory_name);
8393 static GstPadProbeReturn
8394 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8396 FILE *dump_data = (FILE *)u_data;
8398 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8399 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8401 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8403 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8405 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8407 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8409 gst_buffer_unmap(buffer, &probe_info);
8411 return GST_PAD_PROBE_OK;
8415 __mmplayer_release_dump_list(GList *dump_list)
8417 GList *d_list = dump_list;
8422 for (; d_list; d_list = g_list_next(d_list)) {
8423 mmplayer_dump_t *dump_s = d_list->data;
8424 if (dump_s->dump_pad) {
8425 if (dump_s->probe_handle_id)
8426 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8427 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8429 if (dump_s->dump_element_file) {
8430 fclose(dump_s->dump_element_file);
8431 dump_s->dump_element_file = NULL;
8433 MMPLAYER_FREEIF(dump_s);
8435 g_list_free(dump_list);
8440 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8442 mmplayer_t *player = (mmplayer_t *)hplayer;
8446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8447 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8449 *exist = (bool)player->has_closed_caption;
8453 return MM_ERROR_NONE;
8457 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8462 LOGD("unref internal gst buffer %p", buffer);
8464 gst_buffer_unref((GstBuffer *)buffer);
8471 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8473 mmplayer_t *player = (mmplayer_t *)hplayer;
8477 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8478 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8480 if (MMPLAYER_IS_STREAMING(player))
8481 *timeout = (int)player->ini.live_state_change_timeout;
8483 *timeout = (int)player->ini.localplayback_state_change_timeout;
8485 LOGD("timeout = %d", *timeout);
8488 return MM_ERROR_NONE;
8492 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8496 MMPLAYER_RETURN_IF_FAIL(player);
8498 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8500 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8501 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8502 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8503 player->storage_info[i].id = -1;
8504 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8506 if (path_type != MMPLAYER_PATH_MAX)
8515 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8517 int ret = MM_ERROR_NONE;
8518 mmplayer_t *player = (mmplayer_t *)hplayer;
8519 MMMessageParamType msg_param = {0, };
8522 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8524 LOGW("state changed storage %d:%d", id, state);
8526 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8527 return MM_ERROR_NONE;
8529 /* FIXME: text path should be handled seperately. */
8530 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8531 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8532 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8533 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8534 LOGW("external storage is removed");
8536 if (player->msg_posted == FALSE) {
8537 memset(&msg_param, 0, sizeof(MMMessageParamType));
8538 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8539 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8540 player->msg_posted = TRUE;
8543 /* unrealize the player */
8544 ret = _mmplayer_unrealize(hplayer);
8545 if (ret != MM_ERROR_NONE)
8546 LOGE("failed to unrealize");
8554 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8556 int ret = MM_ERROR_NONE;
8557 mmplayer_t *player = (mmplayer_t *)hplayer;
8558 int idx = 0, total = 0;
8559 gchar *result = NULL, *tmp = NULL;
8562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8563 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8565 total = *num = g_list_length(player->adaptive_info.var_list);
8567 LOGW("There is no stream variant info.");
8571 result = g_strdup("");
8572 for (idx = 0 ; idx < total ; idx++) {
8573 stream_variant_t *v_data = NULL;
8574 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8577 gchar data[64] = {0};
8578 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8580 tmp = g_strconcat(result, data, NULL);
8584 LOGW("There is no variant data in %d", idx);
8589 *var_info = (char *)result;
8591 LOGD("variant info %d:%s", *num, *var_info);
8597 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8599 int ret = MM_ERROR_NONE;
8600 mmplayer_t *player = (mmplayer_t *)hplayer;
8603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8605 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8607 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8608 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8609 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8611 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8612 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8613 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8614 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8616 /* FIXME: seek to current position for applying new variant limitation */
8625 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8627 int ret = MM_ERROR_NONE;
8628 mmplayer_t *player = (mmplayer_t *)hplayer;
8631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8632 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8634 *bandwidth = player->adaptive_info.limit.bandwidth;
8635 *width = player->adaptive_info.limit.width;
8636 *height = player->adaptive_info.limit.height;
8638 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8645 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8647 int ret = MM_ERROR_NONE;
8648 mmplayer_t *player = (mmplayer_t *)hplayer;
8651 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8652 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8653 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8655 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8657 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8658 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8659 else /* live case */
8660 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8662 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8669 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8671 #define IDX_FIRST_SW_CODEC 0
8672 mmplayer_t *player = (mmplayer_t *)hplayer;
8673 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8678 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8679 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8680 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8682 switch (stream_type) {
8683 case MM_PLAYER_STREAM_TYPE_AUDIO:
8684 /* to support audio codec selection, codec info have to be added in ini file as below.
8685 audio codec element hw = xxxx
8686 audio codec element sw = avdec
8687 and in case of audio hw codec is supported and selected,
8688 audio filter elements should be applied depending on the hw capabilities.
8690 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8691 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8692 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8693 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8694 LOGE("There is no audio codec info for codec_type %d", codec_type);
8695 return MM_ERROR_PLAYER_NO_OP;
8698 case MM_PLAYER_STREAM_TYPE_VIDEO:
8699 /* to support video codec selection, codec info have to be added in ini file as below.
8700 video codec element hw = omx
8701 video codec element sw = avdec */
8702 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8703 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8704 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8705 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8706 LOGE("There is no video codec info for codec_type %d", codec_type);
8707 return MM_ERROR_PLAYER_NO_OP;
8711 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8712 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8716 LOGD("update %s codec_type to %d", attr_name, codec_type);
8717 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8720 return MM_ERROR_NONE;
8724 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8726 mmplayer_t *player = (mmplayer_t *)hplayer;
8727 GstElement *rg_vol_element = NULL;
8731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 player->sound.rg_enable = enabled;
8735 /* just hold rgvolume enable value if pipeline is not ready */
8736 if (!player->pipeline || !player->pipeline->audiobin) {
8737 LOGD("pipeline is not ready. holding rgvolume enable value");
8738 return MM_ERROR_NONE;
8741 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8743 if (!rg_vol_element) {
8744 LOGD("rgvolume element is not created");
8745 return MM_ERROR_PLAYER_INTERNAL;
8749 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8751 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8755 return MM_ERROR_NONE;
8759 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8761 mmplayer_t *player = (mmplayer_t *)hplayer;
8762 GstElement *rg_vol_element = NULL;
8763 gboolean enable = FALSE;
8767 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8768 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8770 /* just hold enable_rg value if pipeline is not ready */
8771 if (!player->pipeline || !player->pipeline->audiobin) {
8772 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8773 *enabled = player->sound.rg_enable;
8774 return MM_ERROR_NONE;
8777 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8779 if (!rg_vol_element) {
8780 LOGD("rgvolume element is not created");
8781 return MM_ERROR_PLAYER_INTERNAL;
8784 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8785 *enabled = (bool)enable;
8789 return MM_ERROR_NONE;
8793 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8795 mmplayer_t *player = (mmplayer_t *)hplayer;
8796 MMHandleType attrs = 0;
8798 int ret = MM_ERROR_NONE;
8802 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8804 attrs = MMPLAYER_GET_ATTRS(player);
8805 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8807 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8809 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8810 return MM_ERROR_PLAYER_INTERNAL;
8813 player->video_roi.scale_x = scale_x;
8814 player->video_roi.scale_y = scale_y;
8815 player->video_roi.scale_width = scale_width;
8816 player->video_roi.scale_height = scale_height;
8818 /* check video sinkbin is created */
8819 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8820 return MM_ERROR_NONE;
8822 if (!gst_video_overlay_set_video_roi_area(
8823 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8824 scale_x, scale_y, scale_width, scale_height))
8825 ret = MM_ERROR_PLAYER_INTERNAL;
8827 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8828 scale_x, scale_y, scale_width, scale_height);
8836 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8838 mmplayer_t *player = (mmplayer_t *)hplayer;
8839 int ret = MM_ERROR_NONE;
8843 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8844 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8846 *scale_x = player->video_roi.scale_x;
8847 *scale_y = player->video_roi.scale_y;
8848 *scale_width = player->video_roi.scale_width;
8849 *scale_height = player->video_roi.scale_height;
8851 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8852 *scale_x, *scale_y, *scale_width, *scale_height);
8858 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8860 mmplayer_t *player = (mmplayer_t *)hplayer;
8864 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8866 player->client_pid = pid;
8868 LOGD("client pid[%d] %p", pid, player);
8872 return MM_ERROR_NONE;
8876 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8878 mmplayer_t *player = (mmplayer_t *)hplayer;
8879 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8880 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8884 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8885 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8888 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8890 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8892 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8893 return MM_ERROR_NONE;
8895 /* in case of audio codec default type is HW */
8897 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8898 if (player->ini.support_audio_effect)
8899 return MM_ERROR_NONE;
8900 elem_id = MMPLAYER_A_FILTER;
8902 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8903 if (player->ini.support_replaygain_control)
8904 return MM_ERROR_NONE;
8905 elem_id = MMPLAYER_A_RGVOL;
8907 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8908 if (player->ini.support_pitch_control)
8909 return MM_ERROR_NONE;
8910 elem_id = MMPLAYER_A_PITCH;
8912 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8913 if (player->ini.support_audio_effect)
8914 return MM_ERROR_NONE;
8916 /* default case handling is not required */
8919 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8920 LOGW("audio control option [%d] is not available", opt);
8923 /* setting pcm exporting option is allowed before READY state */
8924 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8925 return MM_ERROR_PLAYER_INVALID_STATE;
8927 /* check whether the audio filter exist or not after READY state,
8928 because the sw codec could be added during auto-plugging in some cases */
8929 if (!player->pipeline ||
8930 !player->pipeline->audiobin ||
8931 !player->pipeline->audiobin[elem_id].gst) {
8932 LOGW("there is no audio elem [%d]", elem_id);
8937 LOGD("audio control opt %d, available %d", opt, *available);
8941 return MM_ERROR_NONE;
8945 __mmplayer_update_duration_value(mmplayer_t *player)
8947 gboolean ret = FALSE;
8948 gint64 dur_nsec = 0;
8949 LOGD("try to update duration");
8951 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8952 player->duration = dur_nsec;
8953 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8957 if (player->duration < 0) {
8958 LOGW("duration is Non-Initialized !!!");
8959 player->duration = 0;
8962 /* update streaming service type */
8963 player->streaming_type = _mmplayer_get_stream_service_type(player);
8965 /* check duration is OK */
8966 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8967 /* FIXIT : find another way to get duration here. */
8968 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8974 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8976 /* update audio params
8977 NOTE : We need original audio params and it can be only obtained from src pad of audio
8978 decoder. Below code only valid when we are not using 'resampler' just before
8979 'audioconverter'. */
8980 GstCaps *caps_a = NULL;
8982 gint samplerate = 0, channels = 0;
8983 GstStructure *p = NULL;
8984 GstElement *aconv = NULL;
8986 LOGD("try to update audio attrs");
8988 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8990 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8991 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8992 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8993 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8995 LOGE("there is no audio converter");
8999 pad = gst_element_get_static_pad(aconv, "sink");
9002 LOGW("failed to get pad from audio converter");
9006 caps_a = gst_pad_get_current_caps(pad);
9008 LOGW("not ready to get audio caps");
9009 gst_object_unref(pad);
9013 p = gst_caps_get_structure(caps_a, 0);
9015 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9017 gst_structure_get_int(p, "rate", &samplerate);
9018 gst_structure_get_int(p, "channels", &channels);
9020 mm_player_set_attribute((MMHandleType)player, NULL,
9021 "content_audio_samplerate", samplerate,
9022 "content_audio_channels", channels, NULL);
9024 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9026 gst_caps_unref(caps_a);
9027 gst_object_unref(pad);
9033 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9035 LOGD("try to update video attrs");
9037 GstCaps *caps_v = NULL;
9041 GstStructure *p = NULL;
9043 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9044 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9046 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9048 LOGD("no videosink sink pad");
9052 caps_v = gst_pad_get_current_caps(pad);
9053 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9054 if (!caps_v && player->v_stream_caps) {
9055 caps_v = player->v_stream_caps;
9056 gst_caps_ref(caps_v);
9060 LOGD("no negitiated caps from videosink");
9061 gst_object_unref(pad);
9065 p = gst_caps_get_structure(caps_v, 0);
9066 gst_structure_get_int(p, "width", &width);
9067 gst_structure_get_int(p, "height", &height);
9069 mm_player_set_attribute((MMHandleType)player, NULL,
9070 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9072 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9074 SECURE_LOGD("width : %d height : %d", width, height);
9076 gst_caps_unref(caps_v);
9077 gst_object_unref(pad);
9080 mm_player_set_attribute((MMHandleType)player, NULL,
9081 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9082 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9089 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9091 gboolean ret = FALSE;
9092 guint64 data_size = 0;
9096 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9097 if (!player->duration)
9100 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9101 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9102 if (stat(path, &sb) == 0)
9103 data_size = (guint64)sb.st_size;
9105 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9106 data_size = player->http_content_size;
9109 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9112 guint64 bitrate = 0;
9113 guint64 msec_dur = 0;
9115 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9117 bitrate = data_size * 8 * 1000 / msec_dur;
9118 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9119 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9120 mm_player_set_attribute((MMHandleType)player, NULL,
9121 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9124 LOGD("player duration is less than 0");
9128 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9129 if (player->total_bitrate) {
9130 mm_player_set_attribute((MMHandleType)player, NULL,
9131 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9140 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9142 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9143 data->uri_type = uri_type;
9147 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9149 int ret = MM_ERROR_PLAYER_INVALID_URI;
9151 char *buffer = NULL;
9152 char *seperator = strchr(path, ',');
9153 char ext[100] = {0,}, size[100] = {0,};
9156 if ((buffer = strstr(path, "ext="))) {
9157 buffer += strlen("ext=");
9159 if (strlen(buffer)) {
9160 strncpy(ext, buffer, 99);
9162 if ((seperator = strchr(ext, ','))
9163 || (seperator = strchr(ext, ' '))
9164 || (seperator = strchr(ext, '\0'))) {
9165 seperator[0] = '\0';
9170 if ((buffer = strstr(path, "size="))) {
9171 buffer += strlen("size=");
9173 if (strlen(buffer) > 0) {
9174 strncpy(size, buffer, 99);
9176 if ((seperator = strchr(size, ','))
9177 || (seperator = strchr(size, ' '))
9178 || (seperator = strchr(size, '\0'))) {
9179 seperator[0] = '\0';
9182 mem_size = atoi(size);
9187 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9189 if (mem_size && param) {
9190 if (data->input_mem.buf)
9191 free(data->input_mem.buf);
9192 data->input_mem.buf = malloc(mem_size);
9194 if (data->input_mem.buf) {
9195 memcpy(data->input_mem.buf, param, mem_size);
9196 data->input_mem.len = mem_size;
9197 ret = MM_ERROR_NONE;
9199 LOGE("failed to alloc mem %d", mem_size);
9200 ret = MM_ERROR_PLAYER_INTERNAL;
9203 data->input_mem.offset = 0;
9204 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9211 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9213 gchar *location = NULL;
9216 int ret = MM_ERROR_NONE;
9218 if ((path = strstr(uri, "file://"))) {
9219 location = g_filename_from_uri(uri, NULL, &err);
9220 if (!location || (err != NULL)) {
9221 LOGE("Invalid URI '%s' for filesrc: %s", path,
9222 (err != NULL) ? err->message : "unknown error");
9226 MMPLAYER_FREEIF(location);
9228 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9229 return MM_ERROR_PLAYER_INVALID_URI;
9231 LOGD("path from uri: %s", location);
9234 path = (location != NULL) ? (location) : ((char *)uri);
9237 ret = _mmplayer_exist_file_path(path);
9239 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9240 if (ret == MM_ERROR_NONE) {
9241 if (_mmplayer_is_sdp_file(path)) {
9242 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9243 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9244 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9246 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9247 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9249 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9250 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9252 LOGE("invalid uri, could not play..");
9253 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9256 MMPLAYER_FREEIF(location);
9261 static mmplayer_video_decoded_data_info_t *
9262 __mmplayer_create_stream_from_pad(GstPad *pad)
9264 GstCaps *caps = NULL;
9265 GstStructure *structure = NULL;
9266 unsigned int fourcc = 0;
9267 const gchar *string_format = NULL;
9268 mmplayer_video_decoded_data_info_t *stream = NULL;
9270 MMPixelFormatType format;
9273 caps = gst_pad_get_current_caps(pad);
9275 LOGE("Caps is NULL.");
9280 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9282 structure = gst_caps_get_structure(caps, 0);
9283 gst_structure_get_int(structure, "width", &width);
9284 gst_structure_get_int(structure, "height", &height);
9285 string_format = gst_structure_get_string(structure, "format");
9288 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9289 format = _mmplayer_get_pixtype(fourcc);
9290 gst_video_info_from_caps(&info, caps);
9291 gst_caps_unref(caps);
9294 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9295 LOGE("Wrong condition!!");
9299 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9301 LOGE("failed to alloc mem for video data");
9305 stream->width = width;
9306 stream->height = height;
9307 stream->format = format;
9308 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9314 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9316 unsigned int pitch = 0;
9317 unsigned int size = 0;
9319 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9322 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9323 bo = gst_tizen_memory_get_bos(mem, index);
9325 stream->bo[index] = tbm_bo_ref(bo);
9327 LOGE("failed to get bo for index %d", index);
9330 for (index = 0; index < stream->plane_num; index++) {
9331 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9332 stream->stride[index] = pitch;
9334 stream->elevation[index] = size / pitch;
9336 stream->elevation[index] = stream->height;
9341 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9343 if (stream->format == MM_PIXEL_FORMAT_I420) {
9344 int ret = TBM_SURFACE_ERROR_NONE;
9345 tbm_surface_h surface;
9346 tbm_surface_info_s info;
9348 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9350 ret = tbm_surface_get_info(surface, &info);
9351 if (ret != TBM_SURFACE_ERROR_NONE) {
9352 tbm_surface_destroy(surface);
9356 tbm_surface_destroy(surface);
9357 stream->stride[0] = info.planes[0].stride;
9358 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9359 stream->stride[1] = info.planes[1].stride;
9360 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9361 stream->stride[2] = info.planes[2].stride;
9362 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9363 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9364 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9365 stream->stride[0] = stream->width * 4;
9366 stream->elevation[0] = stream->height;
9367 stream->bo_size = stream->stride[0] * stream->height;
9369 LOGE("Not support format %d", stream->format);
9377 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9379 tbm_bo_handle thandle;
9381 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9382 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9383 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9387 unsigned char *src = NULL;
9388 unsigned char *dest = NULL;
9389 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9391 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9393 LOGE("fail to gst_memory_map");
9397 if (!mapinfo.data) {
9398 LOGE("data pointer is wrong");
9402 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9403 if (!stream->bo[0]) {
9404 LOGE("Fail to tbm_bo_alloc!!");
9408 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9410 LOGE("thandle pointer is wrong");
9414 if (stream->format == MM_PIXEL_FORMAT_I420) {
9415 src_stride[0] = GST_ROUND_UP_4(stream->width);
9416 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9417 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9418 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9421 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9422 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9424 for (i = 0; i < 3; i++) {
9425 src = mapinfo.data + src_offset[i];
9426 dest = thandle.ptr + dest_offset[i];
9431 for (j = 0; j < stream->height >> k; j++) {
9432 memcpy(dest, src, stream->width>>k);
9433 src += src_stride[i];
9434 dest += stream->stride[i];
9437 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9438 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9440 LOGE("Not support format %d", stream->format);
9444 tbm_bo_unmap(stream->bo[0]);
9445 gst_memory_unmap(mem, &mapinfo);
9451 tbm_bo_unmap(stream->bo[0]);
9454 gst_memory_unmap(mem, &mapinfo);
9460 __mmplayer_set_pause_state(mmplayer_t *player)
9462 if (player->sent_bos)
9465 /* rtsp case, get content attrs by GstMessage */
9466 if (MMPLAYER_IS_RTSP_STREAMING(player))
9469 /* it's first time to update all content attrs. */
9470 _mmplayer_update_content_attrs(player, ATTR_ALL);
9474 __mmplayer_set_playing_state(mmplayer_t *player)
9476 gchar *audio_codec = NULL;
9478 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9479 /* initialize because auto resume is done well. */
9480 player->resumed_by_rewind = FALSE;
9481 player->playback_rate = 1.0;
9484 if (player->sent_bos)
9487 /* try to get content metadata */
9489 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9490 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9491 * legacy mmfw-player api
9493 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9495 if ((player->cmd == MMPLAYER_COMMAND_START)
9496 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9497 __mmplayer_handle_missed_plugin(player);
9500 /* check audio codec field is set or not
9501 * we can get it from typefinder or codec's caps.
9503 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9505 /* The codec format can't be sent for audio only case like amr, mid etc.
9506 * Because, parser don't make related TAG.
9507 * So, if it's not set yet, fill it with found data.
9510 if (g_strrstr(player->type, "audio/midi"))
9511 audio_codec = "MIDI";
9512 else if (g_strrstr(player->type, "audio/x-amr"))
9513 audio_codec = "AMR";
9514 else if (g_strrstr(player->type, "audio/mpeg")
9515 && !g_strrstr(player->type, "mpegversion=(int)1"))
9516 audio_codec = "AAC";
9518 audio_codec = "unknown";
9520 if (mm_player_set_attribute((MMHandleType)player, NULL,
9521 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9522 LOGE("failed to set attribute");
9524 LOGD("set audio codec type with caps");