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->selector[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->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1145 srcpad = gst_element_get_static_pad(selector, "src");
1147 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1148 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1149 __mmplayer_gst_selector_blocked, NULL, NULL);
1150 player->selector[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;
1175 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1176 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1179 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1180 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1182 LOGD("pad-added signal handling");
1184 /* get mimetype from caps */
1185 caps = gst_pad_get_current_caps(pad);
1187 str = gst_caps_get_structure(caps, 0);
1189 name = gst_structure_get_name(str);
1194 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1196 LOGD("detected mimetype : %s", name);
1199 if (strstr(name, "video")) {
1201 gchar *caps_str = NULL;
1203 caps_str = gst_caps_to_string(caps);
1204 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1205 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1206 player->set_mode.video_zc = true;
1208 MMPLAYER_FREEIF(caps_str);
1210 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1211 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1213 LOGD("surface type : %d", stype);
1215 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player)) {
1216 __mmplayer_gst_create_sinkbin(elem, pad, player);
1220 /* in case of exporting video frame, it requires the 360 video filter.
1221 * it will be handled in _no_more_pads(). */
1222 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1223 __mmplayer_gst_make_fakesink(player, pad, name);
1227 LOGD("video selector is required");
1228 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1229 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1230 } else if (strstr(name, "audio")) {
1231 gint samplerate = 0;
1234 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player) || player->build_audio_offload) {
1235 if (player->build_audio_offload)
1236 player->no_more_pad = TRUE; /* remove state holder */
1237 __mmplayer_gst_create_sinkbin(elem, pad, player);
1241 gst_structure_get_int(str, "rate", &samplerate);
1242 gst_structure_get_int(str, "channels", &channels);
1244 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1245 __mmplayer_gst_make_fakesink(player, pad, name);
1249 LOGD("audio selector is required");
1250 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1251 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1253 } else if (strstr(name, "text")) {
1254 LOGD("text selector is required");
1255 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1256 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1258 LOGE("invalid caps info");
1262 /* check selector and create it */
1263 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1264 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1269 LOGD("input-selector is already created.");
1273 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1275 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1277 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1278 LOGE("failed to link selector");
1279 gst_object_unref(GST_OBJECT(selector));
1284 LOGD("this track will be activated");
1285 g_object_set(selector, "active-pad", sinkpad, NULL);
1288 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1294 gst_caps_unref(caps);
1297 gst_object_unref(GST_OBJECT(sinkpad));
1305 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1307 GstPad *srcpad = NULL;
1310 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1312 LOGD("type %d", type);
1315 LOGD("there is no %d track", type);
1319 srcpad = gst_element_get_static_pad(selector, "src");
1321 LOGE("failed to get srcpad from selector");
1325 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1327 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1329 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1330 if (player->selector[type].block_id) {
1331 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1332 player->selector[type].block_id = 0;
1336 gst_object_unref(GST_OBJECT(srcpad));
1345 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1347 gint active_index = 0;
1350 MMPLAYER_RETURN_IF_FAIL(player);
1352 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1354 /* change track to active pad */
1355 active_index = player->selector[type].active_pad_index;
1356 if ((active_index != DEFAULT_TRACK) &&
1357 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1358 LOGW("failed to change %d type track to %d", type, active_index);
1359 player->selector[type].active_pad_index = DEFAULT_TRACK;
1363 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1364 mm_player_set_attribute((MMHandleType)player, NULL,
1365 "content_text_track_num", player->selector[type].total_track_num,
1366 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1373 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1376 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1378 if (!audio_selector) {
1379 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1381 /* in case the source is changed, output can be changed. */
1382 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1383 LOGD("remove previous audiobin if it exist");
1385 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1386 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1388 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1389 MMPLAYER_FREEIF(player->pipeline->audiobin);
1392 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1393 _mmplayer_pipeline_complete(NULL, player);
1398 /* apply the audio track information */
1399 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1401 /* create audio sink path */
1402 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1403 LOGE("failed to create audio sink path");
1412 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1415 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1417 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1418 LOGD("text path is not supproted");
1422 /* apply the text track information */
1423 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1425 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1426 player->has_closed_caption = TRUE;
1428 /* create text decode path */
1429 player->no_more_pad = TRUE;
1431 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1432 LOGE("failed to create text sink path");
1441 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1443 gint64 dur_bytes = 0L;
1446 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1447 player->pipeline->mainbin && player->streamer, FALSE);
1449 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1450 LOGE("fail to get duration.");
1452 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1453 * use file information was already set on Q2 when it was created. */
1454 _mm_player_streaming_set_queue2(player->streamer,
1455 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1456 TRUE, /* use_buffering */
1457 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1458 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1465 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1467 mmplayer_t *player = NULL;
1468 GstElement *video_selector = NULL;
1469 GstElement *audio_selector = NULL;
1470 GstElement *text_selector = NULL;
1473 player = (mmplayer_t *)data;
1475 LOGD("no-more-pad signal handling");
1477 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1478 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1479 LOGW("player is shutting down");
1483 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1484 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1485 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1486 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1487 LOGE("failed to set queue2 buffering");
1492 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1493 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1494 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1496 if (!video_selector && !audio_selector && !text_selector) {
1497 LOGW("there is no selector");
1498 player->no_more_pad = TRUE;
1502 /* create video path followed by video-select */
1503 if (video_selector && !audio_selector && !text_selector)
1504 player->no_more_pad = TRUE;
1506 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1509 /* create audio path followed by audio-select */
1510 if (audio_selector && !text_selector)
1511 player->no_more_pad = TRUE;
1513 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1516 /* create text path followed by text-select */
1517 __mmplayer_create_text_sink_path(player, text_selector);
1520 _mmplayer_set_reconfigure_state(player, FALSE);
1525 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1527 gboolean ret = FALSE;
1528 GstElement *pipeline = NULL;
1529 GstPad *sinkpad = NULL;
1532 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1535 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1537 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1539 LOGE("failed to get pad from sinkbin");
1545 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1546 LOGE("failed to link sinkbin for reusing");
1547 goto EXIT; /* exit either pass or fail */
1551 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1552 LOGE("failed to set state(READY) to sinkbin");
1557 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1558 LOGE("failed to add sinkbin to pipeline");
1563 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1564 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1569 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1570 LOGE("failed to set state(PAUSED) to sinkbin");
1579 gst_object_unref(GST_OBJECT(sinkpad));
1587 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1589 mmplayer_t *player = NULL;
1590 GstCaps *caps = NULL;
1591 gchar *caps_str = NULL;
1592 GstStructure *str = NULL;
1593 const gchar *name = NULL;
1594 GstElement *sinkbin = NULL;
1595 gboolean reusing = FALSE;
1596 gboolean caps_ret = TRUE;
1597 gchar *sink_pad_name = "sink";
1600 player = (mmplayer_t *)data;
1603 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1606 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1610 caps_str = gst_caps_to_string(caps);
1612 LOGD("detected mimetype : %s", name);
1614 if (strstr(name, "audio")) {
1615 if (player->pipeline->audiobin == NULL) {
1616 const gchar *audio_format = gst_structure_get_string(str, "format");
1618 LOGD("original audio format %s", audio_format);
1619 mm_player_set_attribute((MMHandleType)player, NULL,
1620 "content_audio_format", audio_format, strlen(audio_format), NULL);
1623 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1624 LOGE("failed to create audiobin. continuing without audio");
1628 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1629 LOGD("creating audiobin success");
1632 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1633 LOGD("reusing audiobin");
1634 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1636 } else if (strstr(name, "video")) {
1637 /* 1. zero copy is updated at _decode_pad_added()
1638 * 2. NULL surface type is handled in _decode_pad_added() */
1639 LOGD("zero copy %d", player->set_mode.video_zc);
1640 if (player->pipeline->videobin == NULL) {
1641 int surface_type = 0;
1642 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1643 LOGD("display_surface_type (%d)", surface_type);
1645 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1646 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1647 LOGE("failed to acquire video overlay resource");
1651 player->interrupted_by_resource = FALSE;
1653 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1654 LOGE("failed to create videobin. continuing without video");
1658 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1659 LOGD("creating videosink bin success");
1662 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1663 LOGD("re-using videobin");
1664 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1666 } else if (strstr(name, "text")) {
1667 if (player->pipeline->textbin == NULL) {
1668 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1669 LOGE("failed to create text sink bin. continuing without text");
1673 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1674 player->textsink_linked = 1;
1675 LOGD("creating textsink bin success");
1677 if (!player->textsink_linked) {
1678 LOGD("re-using textbin");
1680 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1681 player->textsink_linked = 1;
1683 /* linked textbin exist which means that the external subtitle path exist already */
1684 LOGW("ignoring internal subtutle since external subtitle is available");
1687 sink_pad_name = "text_sink";
1689 LOGW("unknown mime type %s, ignoring it", name);
1693 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1696 LOGD("[handle: %p] success to create and link sink bin", player);
1698 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1699 * streaming task. if the task blocked, then buffer will not flow to the next element
1700 *(autoplugging element). so this is special hack for streaming. please try to remove it
1702 /* dec stream count. we can remove fakesink if it's zero */
1703 if (player->num_dynamic_pad)
1704 player->num_dynamic_pad--;
1706 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1708 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1709 _mmplayer_pipeline_complete(NULL, player);
1713 MMPLAYER_FREEIF(caps_str);
1716 gst_caps_unref(caps);
1722 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1724 int required_angle = 0; /* Angle required for straight view */
1725 int rotation_angle = 0;
1727 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1728 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1730 /* Counter clockwise */
1731 switch (orientation) {
1736 required_angle = 270;
1739 required_angle = 180;
1742 required_angle = 90;
1746 rotation_angle = display_angle + required_angle;
1747 if (rotation_angle >= 360)
1748 rotation_angle -= 360;
1750 /* chech if supported or not */
1751 if (rotation_angle % 90) {
1752 LOGD("not supported rotation angle = %d", rotation_angle);
1756 switch (rotation_angle) {
1758 *value = MM_DISPLAY_ROTATION_NONE;
1761 *value = MM_DISPLAY_ROTATION_90;
1764 *value = MM_DISPLAY_ROTATION_180;
1767 *value = MM_DISPLAY_ROTATION_270;
1771 LOGD("setting rotation property value : %d", *value);
1777 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1779 int display_rotation = 0;
1780 gchar *org_orient = NULL;
1781 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("cannot get content attribute");
1785 return MM_ERROR_PLAYER_INTERNAL;
1788 if (display_angle) {
1789 /* update user roation */
1790 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1792 /* Counter clockwise */
1793 switch (display_rotation) {
1794 case MM_DISPLAY_ROTATION_NONE:
1797 case MM_DISPLAY_ROTATION_90:
1798 *display_angle = 90;
1800 case MM_DISPLAY_ROTATION_180:
1801 *display_angle = 180;
1803 case MM_DISPLAY_ROTATION_270:
1804 *display_angle = 270;
1807 LOGW("wrong angle type : %d", display_rotation);
1810 LOGD("check user angle: %d", *display_angle);
1814 /* Counter clockwise */
1815 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1818 if (!strcmp(org_orient, "rotate-90"))
1820 else if (!strcmp(org_orient, "rotate-180"))
1822 else if (!strcmp(org_orient, "rotate-270"))
1825 LOGD("original rotation is %s", org_orient);
1827 LOGD("content_video_orientation get fail");
1830 LOGD("check orientation: %d", *orientation);
1833 return MM_ERROR_NONE;
1836 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1838 int rotation_value = 0;
1839 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1840 int display_angle = 0;
1843 /* check video sinkbin is created */
1844 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1847 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1849 /* get rotation value to set */
1850 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1851 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1852 LOGD("set video param : rotate %d", rotation_value);
1855 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1857 MMHandleType attrs = 0;
1861 /* check video sinkbin is created */
1862 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1865 attrs = MMPLAYER_GET_ATTRS(player);
1866 MMPLAYER_RETURN_IF_FAIL(attrs);
1868 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1869 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1870 LOGD("set video param : visible %d", visible);
1873 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1875 MMHandleType attrs = 0;
1876 int display_method = 0;
1879 /* check video sinkbin is created */
1880 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1883 attrs = MMPLAYER_GET_ATTRS(player);
1884 MMPLAYER_RETURN_IF_FAIL(attrs);
1886 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1887 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1888 LOGD("set video param : method %d", display_method);
1891 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1893 MMHandleType attrs = 0;
1897 /* check video sinkbin is created */
1898 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1901 attrs = MMPLAYER_GET_ATTRS(player);
1902 MMPLAYER_RETURN_IF_FAIL(attrs);
1904 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1905 MMPLAYER_RETURN_IF_FAIL(handle);
1907 gst_video_overlay_set_video_roi_area(
1908 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1910 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1914 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1916 MMHandleType attrs = 0;
1921 int win_roi_width = 0;
1922 int win_roi_height = 0;
1925 /* check video sinkbin is created */
1926 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1929 attrs = MMPLAYER_GET_ATTRS(player);
1930 MMPLAYER_RETURN_IF_FAIL(attrs);
1932 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1933 MMPLAYER_RETURN_IF_FAIL(handle);
1935 /* It should be set after setting window */
1936 mm_attrs_multiple_get(attrs, NULL,
1937 "display_win_roi_x", &win_roi_x,
1938 "display_win_roi_y", &win_roi_y,
1939 "display_win_roi_width", &win_roi_width,
1940 "display_win_roi_height", &win_roi_height, NULL);
1942 /* After setting window handle, set display roi area */
1943 gst_video_overlay_set_display_roi_area(
1944 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1945 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1946 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1950 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1952 MMHandleType attrs = 0;
1955 /* check video sinkbin is created */
1956 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1962 /* common case if using overlay surface */
1963 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1964 MMPLAYER_RETURN_IF_FAIL(handle);
1966 /* default is using wl_surface_id */
1967 LOGD("set video param : wl_surface_id %d", handle);
1968 gst_video_overlay_set_wl_window_wl_surface_id(
1969 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1976 gboolean update_all_param = FALSE;
1980 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1981 LOGW("videosink is not ready yet");
1982 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1985 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1986 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1987 return MM_ERROR_PLAYER_INTERNAL;
1990 LOGD("param_name : %s", param_name);
1991 if (!g_strcmp0(param_name, "update_all_param"))
1992 update_all_param = TRUE;
1994 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1995 __mmplayer_video_param_set_display_overlay(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1997 __mmplayer_video_param_set_display_method(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1999 __mmplayer_video_param_set_display_visible(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2001 __mmplayer_video_param_set_display_rotation(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2003 __mmplayer_video_param_set_roi_area(player);
2004 if (update_all_param)
2005 __mmplayer_video_param_set_video_roi_area(player);
2009 return MM_ERROR_NONE;
2013 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2015 gboolean disable_overlay = FALSE;
2016 mmplayer_t *player = (mmplayer_t *)hplayer;
2019 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2020 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2021 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2022 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2024 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2025 LOGW("Display control is not supported");
2026 return MM_ERROR_PLAYER_INTERNAL;
2029 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2031 if (audio_only == (bool)disable_overlay) {
2032 LOGE("It's the same with current setting: (%d)", audio_only);
2033 return MM_ERROR_NONE;
2037 LOGE("disable overlay");
2038 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2040 /* release overlay resource */
2041 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2042 LOGE("failed to release overlay resource");
2046 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2047 LOGE("failed to acquire video overlay resource");
2050 player->interrupted_by_resource = FALSE;
2052 LOGD("enable overlay");
2053 __mmplayer_video_param_set_display_overlay(player);
2054 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2059 return MM_ERROR_NONE;
2063 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2065 mmplayer_t *player = (mmplayer_t *)hplayer;
2066 gboolean disable_overlay = FALSE;
2070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2071 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2073 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2074 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2076 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2077 LOGW("Display control is not supported");
2078 return MM_ERROR_PLAYER_INTERNAL;
2081 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2083 *paudio_only = (bool)disable_overlay;
2085 LOGD("audio_only : %d", *paudio_only);
2089 return MM_ERROR_NONE;
2093 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2095 GList *bucket = element_bucket;
2096 mmplayer_gst_element_t *element = NULL;
2097 mmplayer_gst_element_t *prv_element = NULL;
2098 GstElement *tee_element = NULL;
2099 gint successful_link_count = 0;
2103 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2105 prv_element = (mmplayer_gst_element_t *)bucket->data;
2106 bucket = bucket->next;
2108 for (; bucket; bucket = bucket->next) {
2109 element = (mmplayer_gst_element_t *)bucket->data;
2111 if (element && element->gst) {
2112 if (prv_element && prv_element->gst) {
2113 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2115 prv_element->gst = tee_element;
2117 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2124 LOGD("linking [%s] to [%s] success",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2127 successful_link_count++;
2128 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2129 LOGD("keep audio-tee element for next audio pipeline branch");
2130 tee_element = prv_element->gst;
2133 LOGD("linking [%s] to [%s] failed",
2134 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2135 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2141 prv_element = element;
2146 return successful_link_count;
2150 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2152 GList *bucket = element_bucket;
2153 mmplayer_gst_element_t *element = NULL;
2154 int successful_add_count = 0;
2158 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2159 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2161 for (; bucket; bucket = bucket->next) {
2162 element = (mmplayer_gst_element_t *)bucket->data;
2164 if (element && element->gst) {
2165 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2166 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2167 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2168 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2171 successful_add_count++;
2177 return successful_add_count;
2181 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mmplayer_t *player = (mmplayer_t *)data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2217 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2219 LOGW("invalid caps info");
2224 gst_caps_unref(caps);
2232 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2237 MMPLAYER_RETURN_IF_FAIL(player);
2239 if (player->audio_stream_buff_list) {
2240 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2241 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2244 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2245 __mmplayer_audio_stream_send_data(player, tmp);
2247 MMPLAYER_FREEIF(tmp->pcm_data);
2248 MMPLAYER_FREEIF(tmp);
2251 g_list_free(player->audio_stream_buff_list);
2252 player->audio_stream_buff_list = NULL;
2259 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2261 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2264 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2266 audio_stream.bitrate = a_buffer->bitrate;
2267 audio_stream.channel = a_buffer->channel;
2268 audio_stream.channel_mask = a_buffer->channel_mask;
2269 audio_stream.data_size = a_buffer->data_size;
2270 audio_stream.data = a_buffer->pcm_data;
2271 audio_stream.pcm_format = a_buffer->pcm_format;
2273 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2275 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2281 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2283 mmplayer_t *player = (mmplayer_t *)data;
2284 const gchar *pcm_format = NULL;
2287 guint64 channel_mask = 0;
2288 void *a_data = NULL;
2290 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2291 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2295 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2297 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2298 a_data = mapinfo.data;
2299 a_size = mapinfo.size;
2301 GstCaps *caps = gst_pad_get_current_caps(pad);
2302 GstStructure *structure = gst_caps_get_structure(caps, 0);
2304 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2306 pcm_format = gst_structure_get_string(structure, "format");
2307 gst_structure_get_int(structure, "rate", &rate);
2308 gst_structure_get_int(structure, "channels", &channel);
2309 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2310 gst_caps_unref(GST_CAPS(caps));
2312 /* In case of the sync is false, use buffer list. *
2313 * The num of buffer list depends on the num of audio channels */
2314 if (player->audio_stream_buff_list) {
2315 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2316 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2318 if (channel_mask == tmp->channel_mask) {
2320 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2322 if (tmp->data_size + a_size < tmp->buff_size) {
2323 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2324 tmp->data_size += a_size;
2326 /* send data to client */
2327 __mmplayer_audio_stream_send_data(player, tmp);
2329 if (a_size > tmp->buff_size) {
2330 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2331 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2332 if (tmp->pcm_data == NULL) {
2333 LOGE("failed to realloc data.");
2336 tmp->buff_size = a_size;
2338 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2339 memcpy(tmp->pcm_data, a_data, a_size);
2340 tmp->data_size = a_size;
2345 LOGE("data is empty in list.");
2351 /* create new audio stream data for newly found audio channel */
2352 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2353 if (a_buffer == NULL) {
2354 LOGE("failed to alloc data.");
2357 a_buffer->bitrate = rate;
2358 a_buffer->channel = channel;
2359 a_buffer->channel_mask = channel_mask;
2360 a_buffer->data_size = a_size;
2361 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2363 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2364 /* If sync is FALSE, use buffer list to reduce the IPC. */
2365 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2366 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2367 if (a_buffer->pcm_data == NULL) {
2368 LOGE("failed to alloc data.");
2369 MMPLAYER_FREEIF(a_buffer);
2372 memcpy(a_buffer->pcm_data, a_data, a_size);
2374 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2376 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2378 /* If sync is TRUE, send data directly. */
2379 a_buffer->pcm_data = a_data;
2380 __mmplayer_audio_stream_send_data(player, a_buffer);
2381 MMPLAYER_FREEIF(a_buffer);
2385 gst_buffer_unmap(buffer, &mapinfo);
2390 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2392 mmplayer_t *player = (mmplayer_t *)data;
2393 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2394 GstPad *sinkpad = NULL;
2395 GstElement *queue = NULL, *sink = NULL;
2398 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2400 queue = gst_element_factory_make("queue", NULL);
2401 if (queue == NULL) {
2402 LOGD("fail make queue");
2406 sink = gst_element_factory_make("fakesink", NULL);
2408 LOGD("fail make fakesink");
2412 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2414 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2415 LOGW("failed to link queue & sink");
2419 sinkpad = gst_element_get_static_pad(queue, "sink");
2421 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2422 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2426 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2428 gst_object_unref(sinkpad);
2429 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2430 g_object_set(sink, "sync", TRUE, NULL);
2431 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2433 /* keep the first sink reference only */
2434 if (!audiobin[MMPLAYER_A_SINK].gst) {
2435 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2436 audiobin[MMPLAYER_A_SINK].gst = sink;
2440 _mmplayer_add_signal_connection(player,
2442 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2444 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2447 __mmplayer_add_sink(player, sink);
2449 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2450 LOGE("failed to sync state");
2454 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2455 LOGE("failed to sync state");
2463 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2465 gst_object_unref(GST_OBJECT(queue));
2469 gst_object_unref(GST_OBJECT(sink));
2473 gst_object_unref(GST_OBJECT(sinkpad));
2481 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2483 mmplayer_t *player = (mmplayer_t *)data;
2486 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2488 player->no_more_pad = TRUE;
2489 _mmplayer_pipeline_complete(NULL, player);
2496 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2498 #define MAX_PROPS_LEN 128
2499 mmplayer_gst_element_t *audiobin = NULL;
2500 gint latency_mode = 0;
2501 gchar *stream_type = NULL;
2502 gchar *latency = NULL;
2504 gchar stream_props[MAX_PROPS_LEN] = {0,};
2505 GstStructure *props = NULL;
2508 * It should be set after player creation through attribute.
2509 * But, it can not be changed during playing.
2512 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2514 audiobin = player->pipeline->audiobin;
2516 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2517 if (player->sound.mute) {
2518 LOGD("mute enabled");
2519 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2522 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2523 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2526 snprintf(stream_props, sizeof(stream_props) - 1,
2527 "props,application.process.id.origin=%d", player->client_pid);
2529 snprintf(stream_props, sizeof(stream_props) - 1,
2530 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2531 stream_type, stream_id, player->client_pid);
2533 props = gst_structure_from_string(stream_props, NULL);
2534 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2535 LOGI("props result[%s].", stream_props);
2536 gst_structure_free(props);
2538 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2540 switch (latency_mode) {
2541 case AUDIO_LATENCY_MODE_LOW:
2542 latency = g_strdup("low");
2544 case AUDIO_LATENCY_MODE_MID:
2545 latency = g_strdup("mid");
2547 case AUDIO_LATENCY_MODE_HIGH:
2548 latency = g_strdup("high");
2551 latency = g_strdup("mid");
2555 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2557 LOGD("audiosink property - latency=%s", latency);
2559 MMPLAYER_FREEIF(latency);
2565 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2567 mmplayer_gst_element_t *audiobin = NULL;
2570 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2571 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2573 audiobin = player->pipeline->audiobin;
2575 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2576 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2577 LOGE("failed to create media stream info");
2578 return MM_ERROR_PLAYER_INTERNAL;
2581 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2583 if (player->video360_yaw_radians <= M_PI &&
2584 player->video360_yaw_radians >= -M_PI &&
2585 player->video360_pitch_radians <= M_PI_2 &&
2586 player->video360_pitch_radians >= -M_PI_2) {
2587 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2588 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2589 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2590 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2591 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2592 "source-orientation-y", player->video360_metadata.init_view_heading,
2593 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2597 return MM_ERROR_NONE;
2601 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2603 mmplayer_gst_element_t *audiobin = NULL;
2604 GstPad *sink_pad = NULL;
2605 GstCaps *acaps = NULL;
2607 int pitch_control = 0;
2608 double pitch_value = 1.0;
2611 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2612 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2614 audiobin = player->pipeline->audiobin;
2616 LOGD("make element for normal audio playback");
2618 /* audio bin structure for playback. {} means optional.
2619 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2621 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2622 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2625 /* for pitch control */
2626 mm_attrs_multiple_get(player->attrs, NULL,
2627 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2628 MM_PLAYER_PITCH_VALUE, &pitch_value,
2631 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2632 if (pitch_control && (player->videodec_linked == 0)) {
2633 GstElementFactory *factory;
2635 factory = gst_element_factory_find("pitch");
2637 gst_object_unref(factory);
2640 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2643 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2644 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2646 LOGW("there is no pitch element");
2651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2653 /* replaygain volume */
2654 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2655 if (player->sound.rg_enable)
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2658 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2663 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2664 /* currently, only openalsink uses volume element */
2665 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2668 if (player->sound.mute) {
2669 LOGD("mute enabled");
2670 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2674 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2676 /* audio effect element. if audio effect is enabled */
2677 if ((strcmp(player->ini.audioeffect_element, ""))
2679 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2682 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2684 if ((!player->bypass_audio_effect)
2685 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2686 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2687 if (!_mmplayer_audio_effect_custom_apply(player))
2688 LOGI("apply audio effect(custom) setting success");
2692 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2693 && (player->set_mode.rich_audio)) {
2694 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2698 /* create audio sink */
2699 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2700 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2701 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2703 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2704 if (player->is_360_feature_enabled &&
2705 player->is_content_spherical &&
2707 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2708 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2709 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2711 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2716 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2718 gst_caps_unref(acaps);
2720 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2722 player->is_openal_plugin_used = TRUE;
2724 if (player->is_360_feature_enabled && player->is_content_spherical)
2725 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2726 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2729 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2730 (player->videodec_linked && player->ini.use_system_clock)) {
2731 LOGD("system clock will be used.");
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2735 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2736 __mmplayer_gst_set_pulsesink_property(player);
2737 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2738 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2743 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2744 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2746 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2747 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2748 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2749 gst_object_unref(GST_OBJECT(sink_pad));
2751 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2754 return MM_ERROR_NONE;
2756 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2758 return MM_ERROR_PLAYER_INTERNAL;
2762 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2764 mmplayer_gst_element_t *audiobin = NULL;
2765 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2767 gchar *dst_format = NULL;
2769 int dst_samplerate = 0;
2770 int dst_channels = 0;
2771 GstCaps *caps = NULL;
2772 char *caps_str = NULL;
2775 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2776 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2778 audiobin = player->pipeline->audiobin;
2780 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2782 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2784 [case 1] extract interleave audio pcm without playback
2785 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2786 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2788 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2790 [case 2] deinterleave for each channel without playback
2791 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2792 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2794 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2795 - fakesink (sync or not)
2798 [case 3] [case 1(sync only)] + playback
2799 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2801 * src - ... - tee - queue1 - playback path
2802 - queue2 - [case1 pipeline with sync]
2804 [case 4] [case 2(sync only)] + playback
2805 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2807 * src - ... - tee - queue1 - playback path
2808 - queue2 - [case2 pipeline with sync]
2812 /* 1. create tee and playback path
2813 'tee' should be added at first to copy the decoded stream
2815 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2816 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2817 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2819 /* tee - path 1 : for playback path */
2820 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2821 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2823 /* tee - path 2 : for extract path */
2824 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2825 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2828 /* if there is tee, 'tee - path 2' is linked here */
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2833 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2835 /* 2. decide the extract pcm format */
2836 mm_attrs_multiple_get(player->attrs, NULL,
2837 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2838 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2839 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2842 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2843 dst_format, dst_len, dst_samplerate, dst_channels);
2845 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2846 mm_attrs_multiple_get(player->attrs, NULL,
2847 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2848 "content_audio_samplerate", &dst_samplerate,
2849 "content_audio_channels", &dst_channels,
2852 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2853 dst_format, dst_len, dst_samplerate, dst_channels);
2855 /* If there is no enough information, set it to platform default value. */
2856 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2857 LOGD("set platform default format");
2858 dst_format = DEFAULT_PCM_OUT_FORMAT;
2860 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2861 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2864 /* 3. create capsfilter */
2865 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2866 caps = gst_caps_new_simple("audio/x-raw",
2867 "format", G_TYPE_STRING, dst_format,
2868 "rate", G_TYPE_INT, dst_samplerate,
2869 "channels", G_TYPE_INT, dst_channels,
2872 caps_str = gst_caps_to_string(caps);
2873 LOGD("new caps : %s", caps_str);
2875 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2878 gst_caps_unref(caps);
2879 MMPLAYER_FREEIF(caps_str);
2881 /* 4-1. create deinterleave to extract pcm for each channel */
2882 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2884 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2886 /* audiosink will be added after getting signal for each channel */
2887 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2888 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2889 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2890 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2891 player->no_more_pad = FALSE;
2893 /* 4-2. create fakesink to extract interlevaed pcm */
2894 LOGD("add audio fakesink for interleaved audio");
2895 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2896 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2897 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2898 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2900 _mmplayer_add_signal_connection(player,
2901 G_OBJECT(audiobin[extract_sink_id].gst),
2902 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2904 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2907 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2911 return MM_ERROR_NONE;
2913 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2915 return MM_ERROR_PLAYER_INTERNAL;
2919 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2921 int ret = MM_ERROR_NONE;
2922 mmplayer_gst_element_t *audiobin = NULL;
2923 GList *element_bucket = NULL;
2926 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2927 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2929 audiobin = player->pipeline->audiobin;
2931 if (player->build_audio_offload) { /* skip all the audio filters */
2932 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2934 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2935 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2936 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2938 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2942 /* FIXME: need to mention the supportable condition at API reference */
2943 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2944 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2946 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2948 if (ret != MM_ERROR_NONE)
2951 LOGD("success to make audio bin element");
2952 *bucket = element_bucket;
2955 return MM_ERROR_NONE;
2958 LOGE("failed to make audio bin element");
2959 g_list_free(element_bucket);
2963 return MM_ERROR_PLAYER_INTERNAL;
2967 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2969 mmplayer_gst_element_t *first_element = NULL;
2970 mmplayer_gst_element_t *audiobin = NULL;
2972 GstPad *ghostpad = NULL;
2973 GList *element_bucket = NULL;
2977 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2980 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2982 LOGE("failed to allocate memory for audiobin");
2983 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2987 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2988 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2989 if (!audiobin[MMPLAYER_A_BIN].gst) {
2990 LOGE("failed to create audiobin");
2995 player->pipeline->audiobin = audiobin;
2997 /* create audio filters and audiosink */
2998 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3001 /* adding created elements to bin */
3002 LOGD("adding created elements to bin");
3003 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3006 /* linking elements in the bucket by added order. */
3007 LOGD("Linking elements in the bucket by added order.");
3008 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3011 /* get first element's sinkpad for creating ghostpad */
3012 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3013 if (!first_element) {
3014 LOGE("failed to get first elem");
3018 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3020 LOGE("failed to get pad from first element of audiobin");
3024 ghostpad = gst_ghost_pad_new("sink", pad);
3026 LOGE("failed to create ghostpad");
3030 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3031 LOGE("failed to add ghostpad to audiobin");
3035 gst_object_unref(pad);
3037 g_list_free(element_bucket);
3040 return MM_ERROR_NONE;
3043 LOGD("ERROR : releasing audiobin");
3046 gst_object_unref(GST_OBJECT(pad));
3049 gst_object_unref(GST_OBJECT(ghostpad));
3052 g_list_free(element_bucket);
3054 /* release element which are not added to bin */
3055 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3056 /* NOTE : skip bin */
3057 if (audiobin[i].gst) {
3058 GstObject *parent = NULL;
3059 parent = gst_element_get_parent(audiobin[i].gst);
3062 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3063 audiobin[i].gst = NULL;
3065 gst_object_unref(GST_OBJECT(parent));
3069 /* release audiobin with it's childs */
3070 if (audiobin[MMPLAYER_A_BIN].gst)
3071 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3073 MMPLAYER_FREEIF(audiobin);
3075 player->pipeline->audiobin = NULL;
3077 return MM_ERROR_PLAYER_INTERNAL;
3081 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3083 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3087 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3089 int ret = MM_ERROR_NONE;
3091 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3092 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3094 MMPLAYER_VIDEO_BO_LOCK(player);
3096 if (player->video_bo_list) {
3097 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3098 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3099 if (tmp && tmp->bo == bo) {
3101 LOGD("release bo %p", bo);
3102 tbm_bo_unref(tmp->bo);
3103 MMPLAYER_VIDEO_BO_UNLOCK(player);
3104 MMPLAYER_VIDEO_BO_SIGNAL(player);
3109 /* hw codec is running or the list was reset for DRC. */
3110 LOGW("there is no bo list.");
3112 MMPLAYER_VIDEO_BO_UNLOCK(player);
3114 LOGW("failed to find bo %p", bo);
3119 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3124 MMPLAYER_RETURN_IF_FAIL(player);
3126 MMPLAYER_VIDEO_BO_LOCK(player);
3127 if (player->video_bo_list) {
3128 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3129 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3130 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3133 tbm_bo_unref(tmp->bo);
3137 g_list_free(player->video_bo_list);
3138 player->video_bo_list = NULL;
3140 player->video_bo_size = 0;
3141 MMPLAYER_VIDEO_BO_UNLOCK(player);
3148 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3151 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3152 gboolean ret = TRUE;
3154 /* check DRC, if it is, destroy the prev bo list to create again */
3155 if (player->video_bo_size != size) {
3156 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3157 __mmplayer_video_stream_destroy_bo_list(player);
3158 player->video_bo_size = size;
3161 MMPLAYER_VIDEO_BO_LOCK(player);
3163 if ((!player->video_bo_list) ||
3164 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3166 /* create bo list */
3168 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3170 if (player->video_bo_list) {
3171 /* if bo list did not created all, try it again. */
3172 idx = g_list_length(player->video_bo_list);
3173 LOGD("bo list exist(len: %d)", idx);
3176 for (; idx < player->ini.num_of_video_bo; idx++) {
3177 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3179 LOGE("Fail to alloc bo_info.");
3182 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3184 LOGE("Fail to tbm_bo_alloc.");
3185 MMPLAYER_FREEIF(bo_info);
3188 bo_info->used = FALSE;
3189 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3192 /* update video num buffers */
3193 LOGD("video_num_buffers : %d", idx);
3194 mm_player_set_attribute((MMHandleType)player, NULL,
3195 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3196 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3200 MMPLAYER_VIDEO_BO_UNLOCK(player);
3206 /* get bo from list*/
3207 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3208 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3209 if (tmp && (tmp->used == FALSE)) {
3210 LOGD("found bo %p to use", tmp->bo);
3212 MMPLAYER_VIDEO_BO_UNLOCK(player);
3213 return tbm_bo_ref(tmp->bo);
3217 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3218 MMPLAYER_VIDEO_BO_UNLOCK(player);
3222 if (player->ini.video_bo_timeout <= 0) {
3223 MMPLAYER_VIDEO_BO_WAIT(player);
3225 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3226 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3233 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3235 mmplayer_t *player = (mmplayer_t *)data;
3237 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3239 /* send prerolled pkt */
3240 player->video_stream_prerolled = false;
3242 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3244 /* not to send prerolled pkt again */
3245 player->video_stream_prerolled = true;
3249 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3251 mmplayer_t *player = (mmplayer_t *)data;
3252 mmplayer_video_decoded_data_info_t *stream = NULL;
3253 GstMemory *mem = NULL;
3256 MMPLAYER_RETURN_IF_FAIL(player);
3257 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3259 if (player->video_stream_prerolled) {
3260 player->video_stream_prerolled = false;
3261 LOGD("skip the prerolled pkt not to send it again");
3265 /* clear stream data structure */
3266 stream = __mmplayer_create_stream_from_pad(pad);
3268 LOGE("failed to alloc stream");
3272 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3274 /* set size and timestamp */
3275 mem = gst_buffer_peek_memory(buffer, 0);
3276 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3277 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3279 /* check zero-copy */
3280 if (player->set_mode.video_zc &&
3281 player->set_mode.video_export &&
3282 gst_is_tizen_memory(mem)) {
3283 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3284 stream->internal_buffer = gst_buffer_ref(buffer);
3285 } else { /* sw codec */
3286 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3289 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3293 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3294 LOGE("failed to send video decoded data.");
3301 LOGE("release video stream resource.");
3302 if (gst_is_tizen_memory(mem)) {
3304 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3306 tbm_bo_unref(stream->bo[i]);
3309 /* unref gst buffer */
3310 if (stream->internal_buffer)
3311 gst_buffer_unref(stream->internal_buffer);
3314 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3316 MMPLAYER_FREEIF(stream);
3321 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3323 mmplayer_gst_element_t *videobin = NULL;
3326 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3328 videobin = player->pipeline->videobin;
3330 /* Set spatial media metadata and/or user settings to the element.
3332 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3333 "projection-type", player->video360_metadata.projection_type, NULL);
3335 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3336 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3338 if (player->video360_metadata.full_pano_width_pixels &&
3339 player->video360_metadata.full_pano_height_pixels &&
3340 player->video360_metadata.cropped_area_image_width &&
3341 player->video360_metadata.cropped_area_image_height) {
3342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3344 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3345 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3346 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3347 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3348 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3352 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3353 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3354 "horizontal-fov", player->video360_horizontal_fov,
3355 "vertical-fov", player->video360_vertical_fov, NULL);
3358 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3359 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3360 "zoom", 1.0f / player->video360_zoom, NULL);
3363 if (player->video360_yaw_radians <= M_PI &&
3364 player->video360_yaw_radians >= -M_PI &&
3365 player->video360_pitch_radians <= M_PI_2 &&
3366 player->video360_pitch_radians >= -M_PI_2) {
3367 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3368 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3369 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3370 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3371 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3372 "pose-yaw", player->video360_metadata.init_view_heading,
3373 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3376 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3377 "passthrough", !player->is_video360_enabled, NULL);
3384 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3386 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3387 GList *element_bucket = NULL;
3390 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3392 /* create video360 filter */
3393 if (player->is_360_feature_enabled && player->is_content_spherical) {
3394 LOGD("create video360 element");
3395 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3396 __mmplayer_gst_set_video360_property(player);
3400 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3401 LOGD("skip creating the videoconv and rotator");
3402 return MM_ERROR_NONE;
3405 /* in case of sw codec & overlay surface type, except 360 playback.
3406 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3407 LOGD("create video converter: %s", video_csc);
3408 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3411 *bucket = element_bucket;
3413 return MM_ERROR_NONE;
3415 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3416 g_list_free(element_bucket);
3420 return MM_ERROR_PLAYER_INTERNAL;
3424 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3426 gchar *factory_name = NULL;
3428 switch (surface_type) {
3429 case MM_DISPLAY_SURFACE_OVERLAY:
3430 if (strlen(player->ini.videosink_element_overlay) > 0)
3431 factory_name = player->ini.videosink_element_overlay;
3433 case MM_DISPLAY_SURFACE_REMOTE:
3434 case MM_DISPLAY_SURFACE_NULL:
3435 if (strlen(player->ini.videosink_element_fake) > 0)
3436 factory_name = player->ini.videosink_element_fake;
3439 LOGE("unidentified surface type");
3443 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3444 return factory_name;
3448 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3450 gchar *factory_name = NULL;
3451 mmplayer_gst_element_t *videobin = NULL;
3456 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3458 videobin = player->pipeline->videobin;
3459 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3461 attrs = MMPLAYER_GET_ATTRS(player);
3463 LOGE("cannot get content attribute");
3464 return MM_ERROR_PLAYER_INTERNAL;
3467 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3468 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3469 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3470 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3471 "use-tbm", use_tbm, NULL);
3474 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3475 return MM_ERROR_PLAYER_INTERNAL;
3477 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3480 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3481 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3484 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3486 LOGD("disable last-sample");
3487 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3490 if (player->set_mode.video_export) {
3492 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3493 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3494 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3496 _mmplayer_add_signal_connection(player,
3497 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3498 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3500 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3503 _mmplayer_add_signal_connection(player,
3504 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3505 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3507 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3511 if (videobin[MMPLAYER_V_SINK].gst) {
3512 GstPad *sink_pad = NULL;
3513 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3515 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3516 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3517 gst_object_unref(GST_OBJECT(sink_pad));
3519 LOGE("failed to get sink pad from videosink");
3523 return MM_ERROR_NONE;
3528 * - video overlay surface(arm/x86) : tizenwlsink
3531 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3534 GList *element_bucket = NULL;
3535 mmplayer_gst_element_t *first_element = NULL;
3536 mmplayer_gst_element_t *videobin = NULL;
3537 gchar *videosink_factory_name = NULL;
3540 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3543 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3545 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3547 player->pipeline->videobin = videobin;
3550 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3551 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3552 if (!videobin[MMPLAYER_V_BIN].gst) {
3553 LOGE("failed to create videobin");
3557 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3560 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3561 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3563 /* additional setting for sink plug-in */
3564 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3565 LOGE("failed to set video property");
3569 /* store it as it's sink element */
3570 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3572 /* adding created elements to bin */
3573 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3574 LOGE("failed to add elements");
3578 /* Linking elements in the bucket by added order */
3579 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3580 LOGE("failed to link elements");
3584 /* get first element's sinkpad for creating ghostpad */
3585 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3586 if (!first_element) {
3587 LOGE("failed to get first element from bucket");
3591 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3593 LOGE("failed to get pad from first element");
3597 /* create ghostpad */
3598 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3599 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3600 LOGE("failed to add ghostpad to videobin");
3603 gst_object_unref(pad);
3605 /* done. free allocated variables */
3606 g_list_free(element_bucket);
3610 return MM_ERROR_NONE;
3613 LOGE("ERROR : releasing videobin");
3614 g_list_free(element_bucket);
3617 gst_object_unref(GST_OBJECT(pad));
3619 /* release videobin with it's childs */
3620 if (videobin[MMPLAYER_V_BIN].gst)
3621 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3623 MMPLAYER_FREEIF(videobin);
3624 player->pipeline->videobin = NULL;
3626 return MM_ERROR_PLAYER_INTERNAL;
3630 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3632 GList *element_bucket = NULL;
3633 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3635 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3636 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3637 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3638 "signal-handoffs", FALSE,
3641 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3642 _mmplayer_add_signal_connection(player,
3643 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3644 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3646 G_CALLBACK(__mmplayer_update_subtitle),
3649 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3650 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3652 if (!player->play_subtitle) {
3653 LOGD("add textbin sink as sink element of whole pipeline.");
3654 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3657 /* adding created elements to bin */
3658 LOGD("adding created elements to bin");
3659 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3660 LOGE("failed to add elements");
3664 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3665 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3666 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3668 /* linking elements in the bucket by added order. */
3669 LOGD("Linking elements in the bucket by added order.");
3670 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3671 LOGE("failed to link elements");
3675 /* done. free allocated variables */
3676 g_list_free(element_bucket);
3678 if (textbin[MMPLAYER_T_QUEUE].gst) {
3680 GstPad *ghostpad = NULL;
3682 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3684 LOGE("failed to get sink pad of text queue");
3688 ghostpad = gst_ghost_pad_new("text_sink", pad);
3689 gst_object_unref(pad);
3692 LOGE("failed to create ghostpad of textbin");
3696 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3697 LOGE("failed to add ghostpad to textbin");
3698 gst_object_unref(ghostpad);
3703 return MM_ERROR_NONE;
3706 g_list_free(element_bucket);
3708 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3709 LOGE("remove textbin sink from sink list");
3710 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3713 /* release element at __mmplayer_gst_create_text_sink_bin */
3714 return MM_ERROR_PLAYER_INTERNAL;
3718 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3720 mmplayer_gst_element_t *textbin = NULL;
3721 GList *element_bucket = NULL;
3722 int surface_type = 0;
3727 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3730 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3732 LOGE("failed to allocate memory for textbin");
3733 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3737 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3738 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3739 if (!textbin[MMPLAYER_T_BIN].gst) {
3740 LOGE("failed to create textbin");
3745 player->pipeline->textbin = textbin;
3748 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3749 LOGD("surface type for subtitle : %d", surface_type);
3750 switch (surface_type) {
3751 case MM_DISPLAY_SURFACE_OVERLAY:
3752 case MM_DISPLAY_SURFACE_NULL:
3753 case MM_DISPLAY_SURFACE_REMOTE:
3754 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3755 LOGE("failed to make plain text elements");
3766 return MM_ERROR_NONE;
3770 LOGD("ERROR : releasing textbin");
3772 g_list_free(element_bucket);
3774 /* release signal */
3775 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3777 /* release element which are not added to bin */
3778 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3779 /* NOTE : skip bin */
3780 if (textbin[i].gst) {
3781 GstObject *parent = NULL;
3782 parent = gst_element_get_parent(textbin[i].gst);
3785 gst_object_unref(GST_OBJECT(textbin[i].gst));
3786 textbin[i].gst = NULL;
3788 gst_object_unref(GST_OBJECT(parent));
3793 /* release textbin with it's childs */
3794 if (textbin[MMPLAYER_T_BIN].gst)
3795 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3797 MMPLAYER_FREEIF(textbin);
3798 player->pipeline->textbin = NULL;
3801 return MM_ERROR_PLAYER_INTERNAL;
3805 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3807 mmplayer_gst_element_t *mainbin = NULL;
3808 mmplayer_gst_element_t *textbin = NULL;
3809 MMHandleType attrs = 0;
3810 GstElement *subsrc = NULL;
3811 GstElement *subparse = NULL;
3812 gchar *subtitle_uri = NULL;
3813 const gchar *charset = NULL;
3819 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3821 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3823 mainbin = player->pipeline->mainbin;
3825 attrs = MMPLAYER_GET_ATTRS(player);
3827 LOGE("cannot get content attribute");
3828 return MM_ERROR_PLAYER_INTERNAL;
3831 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3832 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3833 LOGE("subtitle uri is not proper filepath.");
3834 return MM_ERROR_PLAYER_INVALID_URI;
3837 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3838 LOGE("failed to get storage info of subtitle path");
3839 return MM_ERROR_PLAYER_INVALID_URI;
3842 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3844 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3845 player->subtitle_language_list = NULL;
3846 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3848 /* create the subtitle source */
3849 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3851 LOGE("failed to create filesrc element");
3854 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3856 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3857 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3859 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3860 LOGW("failed to add queue");
3861 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3862 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3863 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3868 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3870 LOGE("failed to create subparse element");
3874 charset = _mmplayer_get_charset(subtitle_uri);
3876 LOGD("detected charset is %s", charset);
3877 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3880 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3881 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3883 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3884 LOGW("failed to add subparse");
3885 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3886 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3887 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3891 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3892 LOGW("failed to link subsrc and subparse");
3896 player->play_subtitle = TRUE;
3897 player->adjust_subtitle_pos = 0;
3899 LOGD("play subtitle using subtitle file");
3901 if (player->pipeline->textbin == NULL) {
3902 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3903 LOGE("failed to create text sink bin. continuing without text");
3907 textbin = player->pipeline->textbin;
3909 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3910 LOGW("failed to add textbin");
3912 /* release signal */
3913 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3915 /* release textbin with it's childs */
3916 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3917 MMPLAYER_FREEIF(player->pipeline->textbin);
3918 player->pipeline->textbin = textbin = NULL;
3922 LOGD("link text input selector and textbin ghost pad");
3924 player->textsink_linked = 1;
3925 player->external_text_idx = 0;
3926 LOGI("textsink is linked");
3928 textbin = player->pipeline->textbin;
3929 LOGD("text bin has been created. reuse it.");
3930 player->external_text_idx = 1;
3933 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3934 LOGW("failed to link subparse and textbin");
3938 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3940 LOGE("failed to get sink pad from textsink to probe data");
3944 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3945 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3947 gst_object_unref(pad);
3950 /* create dot. for debugging */
3951 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3954 return MM_ERROR_NONE;
3957 /* release text pipeline resource */
3958 player->textsink_linked = 0;
3960 /* release signal */
3961 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3963 if (player->pipeline->textbin) {
3964 LOGE("remove textbin");
3966 /* release textbin with it's childs */
3967 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3968 MMPLAYER_FREEIF(player->pipeline->textbin);
3969 player->pipeline->textbin = NULL;
3973 /* release subtitle elem */
3974 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3975 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3977 return MM_ERROR_PLAYER_INTERNAL;
3981 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3983 mmplayer_t *player = (mmplayer_t *)data;
3984 MMMessageParamType msg = {0, };
3985 GstClockTime duration = 0;
3986 gpointer text = NULL;
3987 guint text_size = 0;
3988 gboolean ret = TRUE;
3989 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3993 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3994 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3996 if (player->is_subtitle_force_drop) {
3997 LOGW("subtitle is dropped forcedly.");
4001 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4002 text = mapinfo.data;
4003 text_size = mapinfo.size;
4005 if (player->set_mode.subtitle_off) {
4006 LOGD("subtitle is OFF.");
4010 if (!text || (text_size == 0)) {
4011 LOGD("There is no subtitle to be displayed.");
4015 msg.data = (void *)text;
4017 duration = GST_BUFFER_DURATION(buffer);
4019 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4020 if (player->duration > GST_BUFFER_PTS(buffer))
4021 duration = player->duration - GST_BUFFER_PTS(buffer);
4024 LOGI("subtitle duration is invalid, subtitle duration change "
4025 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4027 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4029 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4031 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4032 gst_buffer_unmap(buffer, &mapinfo);
4039 static GstPadProbeReturn
4040 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4042 mmplayer_t *player = (mmplayer_t *)u_data;
4043 GstClockTime cur_timestamp = 0;
4044 gint64 adjusted_timestamp = 0;
4045 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4047 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4049 if (player->set_mode.subtitle_off) {
4050 LOGD("subtitle is OFF.");
4054 if (player->adjust_subtitle_pos == 0) {
4055 LOGD("nothing to do");
4059 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4060 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4062 if (adjusted_timestamp < 0) {
4063 LOGD("adjusted_timestamp under zero");
4068 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4069 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4070 GST_TIME_ARGS(cur_timestamp),
4071 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4073 return GST_PAD_PROBE_OK;
4077 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4081 /* check player and subtitlebin are created */
4082 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4083 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4085 if (position == 0) {
4086 LOGD("nothing to do");
4088 return MM_ERROR_NONE;
4091 /* check current postion */
4092 player->adjust_subtitle_pos = position;
4094 LOGD("save adjust_subtitle_pos in player");
4098 return MM_ERROR_NONE;
4102 * This function is to create audio or video pipeline for playing.
4104 * @param player [in] handle of player
4106 * @return This function returns zero on success.
4111 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4113 int ret = MM_ERROR_NONE;
4114 mmplayer_gst_element_t *mainbin = NULL;
4115 MMHandleType attrs = 0;
4118 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4120 /* get profile attribute */
4121 attrs = MMPLAYER_GET_ATTRS(player);
4123 LOGE("failed to get content attribute");
4127 /* create pipeline handles */
4128 if (player->pipeline) {
4129 LOGE("pipeline should be released before create new one");
4133 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4135 /* create mainbin */
4136 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4137 if (mainbin == NULL)
4140 /* create pipeline */
4141 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4142 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4143 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4144 LOGE("failed to create pipeline");
4149 player->pipeline->mainbin = mainbin;
4151 /* create the source and decoder elements */
4152 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4153 ret = _mmplayer_gst_build_es_pipeline(player);
4155 ret = _mmplayer_gst_build_pipeline(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to create some elements");
4162 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4163 if (__mmplayer_check_subtitle(player)
4164 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4165 LOGE("failed to create text pipeline");
4168 ret = _mmplayer_gst_add_bus_watch(player);
4169 if (ret != MM_ERROR_NONE) {
4170 LOGE("failed to add bus watch");
4175 return MM_ERROR_NONE;
4178 __mmplayer_gst_destroy_pipeline(player);
4179 return MM_ERROR_PLAYER_INTERNAL;
4183 __mmplayer_reset_gapless_state(mmplayer_t *player)
4186 MMPLAYER_RETURN_IF_FAIL(player
4188 && player->pipeline->audiobin
4189 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4191 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4198 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4201 int ret = MM_ERROR_NONE;
4205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4207 /* cleanup stuffs */
4208 MMPLAYER_FREEIF(player->type);
4209 player->no_more_pad = FALSE;
4210 player->num_dynamic_pad = 0;
4211 player->demux_pad_index = 0;
4213 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4214 player->subtitle_language_list = NULL;
4215 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4217 MMPLAYER_RECONFIGURE_LOCK(player);
4218 __mmplayer_reset_gapless_state(player);
4219 MMPLAYER_RECONFIGURE_UNLOCK(player);
4221 if (player->streamer) {
4222 _mm_player_streaming_initialize(player->streamer, FALSE);
4223 _mm_player_streaming_destroy(player->streamer);
4224 player->streamer = NULL;
4227 /* cleanup unlinked mime type */
4228 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4229 MMPLAYER_FREEIF(player->unlinked_video_mime);
4230 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4232 /* cleanup running stuffs */
4233 _mmplayer_cancel_eos_timer(player);
4235 /* cleanup gst stuffs */
4236 if (player->pipeline) {
4237 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4238 GstTagList *tag_list = player->pipeline->tag_list;
4240 /* first we need to disconnect all signal hander */
4241 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4244 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4245 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4246 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4247 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4248 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4249 gst_object_unref(bus);
4251 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4252 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4253 if (ret != MM_ERROR_NONE) {
4254 LOGE("fail to change state to NULL");
4255 return MM_ERROR_PLAYER_INTERNAL;
4258 LOGW("succeeded in changing state to NULL");
4260 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4263 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4264 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4266 /* free avsysaudiosink
4267 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4268 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4270 MMPLAYER_FREEIF(audiobin);
4271 MMPLAYER_FREEIF(videobin);
4272 MMPLAYER_FREEIF(textbin);
4273 MMPLAYER_FREEIF(mainbin);
4277 gst_tag_list_unref(tag_list);
4279 MMPLAYER_FREEIF(player->pipeline);
4281 MMPLAYER_FREEIF(player->album_art);
4283 if (player->v_stream_caps) {
4284 gst_caps_unref(player->v_stream_caps);
4285 player->v_stream_caps = NULL;
4288 if (player->a_stream_caps) {
4289 gst_caps_unref(player->a_stream_caps);
4290 player->a_stream_caps = NULL;
4293 if (player->s_stream_caps) {
4294 gst_caps_unref(player->s_stream_caps);
4295 player->s_stream_caps = NULL;
4297 _mmplayer_track_destroy(player);
4299 if (player->sink_elements)
4300 g_list_free(player->sink_elements);
4301 player->sink_elements = NULL;
4303 if (player->bufmgr) {
4304 tbm_bufmgr_deinit(player->bufmgr);
4305 player->bufmgr = NULL;
4308 LOGW("finished destroy pipeline");
4316 __mmplayer_gst_realize(mmplayer_t *player)
4319 int ret = MM_ERROR_NONE;
4323 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4325 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4327 ret = __mmplayer_gst_create_pipeline(player);
4329 LOGE("failed to create pipeline");
4333 /* set pipeline state to READY */
4334 /* NOTE : state change to READY must be performed sync. */
4335 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4336 ret = _mmplayer_gst_set_state(player,
4337 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4339 if (ret != MM_ERROR_NONE) {
4340 /* return error if failed to set state */
4341 LOGE("failed to set READY state");
4345 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4347 /* create dot before error-return. for debugging */
4348 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4356 __mmplayer_gst_unrealize(mmplayer_t *player)
4358 int ret = MM_ERROR_NONE;
4362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4364 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4365 MMPLAYER_PRINT_STATE(player);
4367 /* release miscellaneous information */
4368 __mmplayer_release_misc(player);
4370 /* destroy pipeline */
4371 ret = __mmplayer_gst_destroy_pipeline(player);
4372 if (ret != MM_ERROR_NONE) {
4373 LOGE("failed to destory pipeline");
4377 /* release miscellaneous information.
4378 these info needs to be released after pipeline is destroyed. */
4379 __mmplayer_release_misc_post(player);
4381 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4389 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4394 LOGW("set_message_callback is called with invalid player handle");
4395 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4398 player->msg_cb = callback;
4399 player->msg_cb_param = user_param;
4401 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4405 return MM_ERROR_NONE;
4409 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4411 int ret = MM_ERROR_NONE;
4416 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4417 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4418 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4420 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4422 if (strstr(uri, "es_buff://")) {
4423 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4424 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4425 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4426 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4428 tmp = g_ascii_strdown(uri, strlen(uri));
4429 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4430 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4432 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4434 } else if (strstr(uri, "mms://")) {
4435 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4436 } else if ((path = strstr(uri, "mem://"))) {
4437 ret = __mmplayer_set_mem_uri(data, path, param);
4439 ret = __mmplayer_set_file_uri(data, uri);
4442 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4443 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4444 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4445 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4447 /* dump parse result */
4448 SECURE_LOGW("incoming uri : %s", uri);
4449 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4450 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4458 __mmplayer_can_do_interrupt(mmplayer_t *player)
4460 if (!player || !player->pipeline || !player->attrs) {
4461 LOGW("not initialized");
4465 if (player->audio_decoded_cb) {
4466 LOGW("not support in pcm extraction mode");
4470 /* check if seeking */
4471 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4472 MMMessageParamType msg_param;
4473 memset(&msg_param, 0, sizeof(MMMessageParamType));
4474 msg_param.code = MM_ERROR_PLAYER_SEEK;
4475 player->seek_state = MMPLAYER_SEEK_NONE;
4476 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4480 /* check other thread */
4481 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4482 LOGW("locked already, cmd state : %d", player->cmd);
4484 /* check application command */
4485 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4486 LOGW("playing.. should wait cmd lock then, will be interrupted");
4488 /* lock will be released at mrp_resource_release_cb() */
4489 MMPLAYER_CMD_LOCK(player);
4492 LOGW("nothing to do");
4495 LOGW("can interrupt immediately");
4499 FAILED: /* with CMD UNLOCKED */
4502 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4507 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4510 mmplayer_t *player = NULL;
4511 MMMessageParamType msg = {0, };
4513 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4518 LOGE("user_data is null");
4521 player = (mmplayer_t *)user_data;
4523 if (!__mmplayer_can_do_interrupt(player)) {
4524 LOGW("no need to interrupt, so leave");
4525 /* FIXME: there is no way to avoid releasing resource. */
4529 player->interrupted_by_resource = TRUE;
4531 /* get last play position */
4532 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4533 msg.union_type = MM_MSG_UNION_TIME;
4534 msg.time.elapsed = pos;
4535 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4537 LOGW("failed to get play position.");
4540 LOGD("video resource conflict so, resource will be freed by unrealizing");
4541 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4542 LOGE("failed to unrealize");
4544 /* lock is called in __mmplayer_can_do_interrupt() */
4545 MMPLAYER_CMD_UNLOCK(player);
4547 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4548 player->hw_resource[res_idx] = NULL;
4552 return TRUE; /* release all the resources */
4556 __mmplayer_initialize_video_roi(mmplayer_t *player)
4558 player->video_roi.scale_x = 0.0;
4559 player->video_roi.scale_y = 0.0;
4560 player->video_roi.scale_width = 1.0;
4561 player->video_roi.scale_height = 1.0;
4565 _mmplayer_create_player(MMHandleType handle)
4567 int ret = MM_ERROR_PLAYER_INTERNAL;
4568 bool enabled = false;
4570 mmplayer_t *player = MM_PLAYER_CAST(handle);
4574 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4576 /* initialize player state */
4577 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4578 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4579 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4580 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4582 /* check current state */
4583 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4585 /* construct attributes */
4586 player->attrs = _mmplayer_construct_attribute(handle);
4588 if (!player->attrs) {
4589 LOGE("Failed to construct attributes");
4593 /* initialize gstreamer with configured parameter */
4594 if (!__mmplayer_init_gstreamer(player)) {
4595 LOGE("Initializing gstreamer failed");
4596 _mmplayer_deconstruct_attribute(handle);
4600 /* create lock. note that g_tread_init() has already called in gst_init() */
4601 g_mutex_init(&player->fsink_lock);
4603 /* create update tag lock */
4604 g_mutex_init(&player->update_tag_lock);
4606 /* create gapless play mutex */
4607 g_mutex_init(&player->gapless_play_thread_mutex);
4609 /* create gapless play cond */
4610 g_cond_init(&player->gapless_play_thread_cond);
4612 /* create gapless play thread */
4613 player->gapless_play_thread =
4614 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4615 if (!player->gapless_play_thread) {
4616 LOGE("failed to create gapless play thread");
4617 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4618 g_mutex_clear(&player->gapless_play_thread_mutex);
4619 g_cond_clear(&player->gapless_play_thread_cond);
4623 player->bus_msg_q = g_queue_new();
4624 if (!player->bus_msg_q) {
4625 LOGE("failed to create queue for bus_msg");
4626 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4630 ret = _mmplayer_initialize_video_capture(player);
4631 if (ret != MM_ERROR_NONE) {
4632 LOGE("failed to initialize video capture");
4636 /* initialize resource manager */
4637 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4638 __resource_release_cb, player, &player->resource_manager)
4639 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4640 LOGE("failed to initialize resource manager");
4641 ret = MM_ERROR_PLAYER_INTERNAL;
4645 /* create video bo lock and cond */
4646 g_mutex_init(&player->video_bo_mutex);
4647 g_cond_init(&player->video_bo_cond);
4649 /* create subtitle info lock and cond */
4650 g_mutex_init(&player->subtitle_info_mutex);
4651 g_cond_init(&player->subtitle_info_cond);
4653 player->streaming_type = STREAMING_SERVICE_NONE;
4655 /* give default value of audio effect setting */
4656 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4657 player->sound.rg_enable = false;
4658 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4660 player->play_subtitle = FALSE;
4661 player->has_closed_caption = FALSE;
4662 player->pending_resume = FALSE;
4663 if (player->ini.dump_element_keyword[0][0] == '\0')
4664 player->ini.set_dump_element_flag = FALSE;
4666 player->ini.set_dump_element_flag = TRUE;
4668 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4669 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4670 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4672 /* Set video360 settings to their defaults for just-created player.
4675 player->is_360_feature_enabled = FALSE;
4676 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4677 LOGI("spherical feature info: %d", enabled);
4679 player->is_360_feature_enabled = TRUE;
4681 LOGE("failed to get spherical feature info");
4684 player->is_content_spherical = FALSE;
4685 player->is_video360_enabled = TRUE;
4686 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4687 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4688 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4689 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4690 player->video360_zoom = 1.0f;
4691 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4692 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4694 __mmplayer_initialize_video_roi(player);
4696 /* set player state to null */
4697 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4698 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4702 return MM_ERROR_NONE;
4706 g_mutex_clear(&player->fsink_lock);
4707 /* free update tag lock */
4708 g_mutex_clear(&player->update_tag_lock);
4709 g_queue_free(player->bus_msg_q);
4710 player->bus_msg_q = NULL;
4711 /* free gapless play thread */
4712 if (player->gapless_play_thread) {
4713 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4714 player->gapless_play_thread_exit = TRUE;
4715 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4716 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4718 g_thread_join(player->gapless_play_thread);
4719 player->gapless_play_thread = NULL;
4721 g_mutex_clear(&player->gapless_play_thread_mutex);
4722 g_cond_clear(&player->gapless_play_thread_cond);
4725 /* release attributes */
4726 _mmplayer_deconstruct_attribute(handle);
4734 __mmplayer_init_gstreamer(mmplayer_t *player)
4736 static gboolean initialized = FALSE;
4737 static const int max_argc = 50;
4739 gchar **argv = NULL;
4740 gchar **argv2 = NULL;
4746 LOGD("gstreamer already initialized.");
4751 argc = malloc(sizeof(int));
4752 argv = malloc(sizeof(gchar *) * max_argc);
4753 argv2 = malloc(sizeof(gchar *) * max_argc);
4755 if (!argc || !argv || !argv2)
4758 memset(argv, 0, sizeof(gchar *) * max_argc);
4759 memset(argv2, 0, sizeof(gchar *) * max_argc);
4763 argv[0] = g_strdup("mmplayer");
4766 for (i = 0; i < 5; i++) {
4767 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4768 if (strlen(player->ini.gst_param[i]) > 0) {
4769 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4774 /* we would not do fork for scanning plugins */
4775 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4778 /* check disable registry scan */
4779 if (player->ini.skip_rescan) {
4780 argv[*argc] = g_strdup("--gst-disable-registry-update");
4784 /* check disable segtrap */
4785 if (player->ini.disable_segtrap) {
4786 argv[*argc] = g_strdup("--gst-disable-segtrap");
4790 LOGD("initializing gstreamer with following parameter");
4791 LOGD("argc : %d", *argc);
4794 for (i = 0; i < arg_count; i++) {
4796 LOGD("argv[%d] : %s", i, argv2[i]);
4799 /* initializing gstreamer */
4800 if (!gst_init_check(argc, &argv, &err)) {
4801 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4808 for (i = 0; i < arg_count; i++) {
4810 LOGD("release - argv[%d] : %s", i, argv2[i]);
4812 MMPLAYER_FREEIF(argv2[i]);
4815 MMPLAYER_FREEIF(argv);
4816 MMPLAYER_FREEIF(argv2);
4817 MMPLAYER_FREEIF(argc);
4827 for (i = 0; i < arg_count; i++) {
4828 LOGD("free[%d] : %s", i, argv2[i]);
4829 MMPLAYER_FREEIF(argv2[i]);
4832 MMPLAYER_FREEIF(argv);
4833 MMPLAYER_FREEIF(argv2);
4834 MMPLAYER_FREEIF(argc);
4840 __mmplayer_check_async_state_transition(mmplayer_t *player)
4842 GstState element_state = GST_STATE_VOID_PENDING;
4843 GstState element_pending_state = GST_STATE_VOID_PENDING;
4844 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4845 GstElement *element = NULL;
4846 gboolean async = FALSE;
4848 /* check player handle */
4849 MMPLAYER_RETURN_IF_FAIL(player &&
4851 player->pipeline->mainbin &&
4852 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4855 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4857 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4858 LOGD("don't need to check the pipeline state");
4862 MMPLAYER_PRINT_STATE(player);
4864 /* wait for state transition */
4865 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4866 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4868 if (ret == GST_STATE_CHANGE_FAILURE) {
4869 LOGE(" [%s] state : %s pending : %s",
4870 GST_ELEMENT_NAME(element),
4871 gst_element_state_get_name(element_state),
4872 gst_element_state_get_name(element_pending_state));
4874 /* dump state of all element */
4875 _mmplayer_dump_pipeline_state(player);
4880 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4885 _mmplayer_destroy(MMHandleType handle)
4887 mmplayer_t *player = MM_PLAYER_CAST(handle);
4891 /* check player handle */
4892 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4894 /* destroy can called at anytime */
4895 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4897 /* check async state transition */
4898 __mmplayer_check_async_state_transition(player);
4900 /* release gapless play thread */
4901 if (player->gapless_play_thread) {
4902 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4903 player->gapless_play_thread_exit = TRUE;
4904 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4905 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4907 LOGD("waitting for gapless play thread exit");
4908 g_thread_join(player->gapless_play_thread);
4909 g_mutex_clear(&player->gapless_play_thread_mutex);
4910 g_cond_clear(&player->gapless_play_thread_cond);
4911 LOGD("gapless play thread released");
4914 _mmplayer_release_video_capture(player);
4916 /* de-initialize resource manager */
4917 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4918 player->resource_manager))
4919 LOGE("failed to deinitialize resource manager");
4921 /* release miscellaneous information */
4922 __mmplayer_release_misc(player);
4924 /* release pipeline */
4925 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4926 LOGE("failed to destory pipeline");
4927 return MM_ERROR_PLAYER_INTERNAL;
4930 g_queue_free(player->bus_msg_q);
4932 /* release subtitle info lock and cond */
4933 g_mutex_clear(&player->subtitle_info_mutex);
4934 g_cond_clear(&player->subtitle_info_cond);
4936 __mmplayer_release_dump_list(player->dump_list);
4938 /* release miscellaneous information.
4939 these info needs to be released after pipeline is destroyed. */
4940 __mmplayer_release_misc_post(player);
4942 /* release attributes */
4943 _mmplayer_deconstruct_attribute(handle);
4945 if (player->uri_info.uri_list) {
4946 GList *uri_list = player->uri_info.uri_list;
4947 for (; uri_list; uri_list = g_list_next(uri_list)) {
4948 gchar *uri = uri_list->data;
4949 MMPLAYER_FREEIF(uri);
4951 g_list_free(player->uri_info.uri_list);
4952 player->uri_info.uri_list = NULL;
4956 g_mutex_clear(&player->fsink_lock);
4959 g_mutex_clear(&player->update_tag_lock);
4961 /* release video bo lock and cond */
4962 g_mutex_clear(&player->video_bo_mutex);
4963 g_cond_clear(&player->video_bo_cond);
4967 return MM_ERROR_NONE;
4971 _mmplayer_realize(MMHandleType hplayer)
4973 mmplayer_t *player = (mmplayer_t *)hplayer;
4974 int ret = MM_ERROR_NONE;
4977 MMHandleType attrs = 0;
4978 int video_codec_type = 0;
4979 int audio_codec_type = 0;
4980 int default_codec_type = 0;
4983 /* check player handle */
4984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4986 /* check current state */
4987 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4989 attrs = MMPLAYER_GET_ATTRS(player);
4991 LOGE("fail to get attributes.");
4992 return MM_ERROR_PLAYER_INTERNAL;
4994 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4995 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4997 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4998 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5000 if (ret != MM_ERROR_NONE) {
5001 LOGE("failed to parse profile");
5006 if (uri && (strstr(uri, "es_buff://"))) {
5007 if (strstr(uri, "es_buff://push_mode"))
5008 player->es_player_push_mode = TRUE;
5010 player->es_player_push_mode = FALSE;
5013 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5014 LOGW("mms protocol is not supported format.");
5015 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5018 if (MMPLAYER_IS_STREAMING(player))
5019 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5021 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5023 player->smooth_streaming = FALSE;
5024 player->videodec_linked = 0;
5025 player->audiodec_linked = 0;
5026 player->textsink_linked = 0;
5027 player->is_external_subtitle_present = FALSE;
5028 player->is_external_subtitle_added_now = FALSE;
5029 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5030 player->video360_metadata.is_spherical = -1;
5031 player->is_openal_plugin_used = FALSE;
5032 player->demux_pad_index = 0;
5033 player->subtitle_language_list = NULL;
5034 player->is_subtitle_force_drop = FALSE;
5036 _mmplayer_track_initialize(player);
5037 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5039 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5040 gint prebuffer_ms = 0, rebuffer_ms = 0;
5042 player->streamer = _mm_player_streaming_create();
5043 _mm_player_streaming_initialize(player->streamer, TRUE);
5045 mm_attrs_multiple_get(player->attrs, NULL,
5046 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5047 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5049 if (prebuffer_ms > 0) {
5050 prebuffer_ms = MAX(prebuffer_ms, 1000);
5051 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5054 if (rebuffer_ms > 0) {
5055 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5056 rebuffer_ms = MAX(rebuffer_ms, 1000);
5057 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5060 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5061 player->streamer->buffering_req.rebuffer_time);
5064 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5065 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5066 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5068 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5070 if (audio_codec_type != default_codec_type) {
5071 LOGD("audio dec sorting is required");
5072 player->need_audio_dec_sorting = TRUE;
5075 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5076 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5077 LOGD("video dec sorting is required");
5078 player->need_video_dec_sorting = TRUE;
5081 /* realize pipeline */
5082 ret = __mmplayer_gst_realize(player);
5083 if (ret != MM_ERROR_NONE)
5084 LOGE("fail to realize the player.");
5086 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5094 _mmplayer_unrealize(MMHandleType hplayer)
5096 mmplayer_t *player = (mmplayer_t *)hplayer;
5097 int ret = MM_ERROR_NONE;
5101 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5103 MMPLAYER_CMD_UNLOCK(player);
5104 /* destroy the gst bus msg thread which is created during realize.
5105 this funct have to be called before getting cmd lock. */
5106 _mmplayer_bus_msg_thread_destroy(player);
5107 MMPLAYER_CMD_LOCK(player);
5109 /* check current state */
5110 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5112 /* check async state transition */
5113 __mmplayer_check_async_state_transition(player);
5115 /* unrealize pipeline */
5116 ret = __mmplayer_gst_unrealize(player);
5118 if (!player->interrupted_by_resource) {
5119 int rm_ret = MM_ERROR_NONE;
5120 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5122 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5123 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5124 if (rm_ret != MM_ERROR_NONE)
5125 LOGE("failed to release [%d] resources", res_idx);
5134 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5136 mmplayer_t *player = (mmplayer_t *)hplayer;
5138 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5140 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5144 _mmplayer_get_state(MMHandleType hplayer, int *state)
5146 mmplayer_t *player = (mmplayer_t *)hplayer;
5148 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5150 *state = MMPLAYER_CURRENT_STATE(player);
5152 return MM_ERROR_NONE;
5156 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5158 GstElement *vol_element = NULL;
5159 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5162 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5163 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5165 /* check pipeline handle */
5166 if (!player->pipeline || !player->pipeline->audiobin) {
5167 LOGD("'%s' will be applied when audiobin is created", prop_name);
5169 /* NOTE : stored value will be used in create_audiobin
5170 * returning MM_ERROR_NONE here makes application to able to
5171 * set audio volume or mute at anytime.
5173 return MM_ERROR_NONE;
5176 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5177 volume_elem_id = MMPLAYER_A_SINK;
5179 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5181 LOGE("failed to get vol element %d", volume_elem_id);
5182 return MM_ERROR_PLAYER_INTERNAL;
5185 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5187 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5188 LOGE("there is no '%s' property", prop_name);
5189 return MM_ERROR_PLAYER_INTERNAL;
5192 if (!strcmp(prop_name, "volume")) {
5193 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5194 } else if (!strcmp(prop_name, "mute")) {
5195 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5197 LOGE("invalid property %s", prop_name);
5198 return MM_ERROR_PLAYER_INTERNAL;
5201 return MM_ERROR_NONE;
5205 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5207 int ret = MM_ERROR_NONE;
5208 mmplayer_t *player = (mmplayer_t *)hplayer;
5211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5213 LOGD("volume = %f", volume);
5215 /* invalid factor range or not */
5216 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5217 LOGE("Invalid volume value");
5218 return MM_ERROR_INVALID_ARGUMENT;
5221 player->sound.volume = volume;
5223 ret = __mmplayer_gst_set_volume_property(player, "volume");
5230 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5232 mmplayer_t *player = (mmplayer_t *)hplayer;
5236 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5237 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5239 *volume = player->sound.volume;
5241 LOGD("current vol = %f", *volume);
5244 return MM_ERROR_NONE;
5248 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5250 int ret = MM_ERROR_NONE;
5251 mmplayer_t *player = (mmplayer_t *)hplayer;
5254 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5256 LOGD("mute = %d", mute);
5258 player->sound.mute = mute;
5260 ret = __mmplayer_gst_set_volume_property(player, "mute");
5267 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5269 mmplayer_t *player = (mmplayer_t *)hplayer;
5273 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5274 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5276 *mute = player->sound.mute;
5278 LOGD("current mute = %d", *mute);
5282 return MM_ERROR_NONE;
5286 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5288 mmplayer_t *player = (mmplayer_t *)hplayer;
5292 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5294 player->audio_stream_changed_cb = callback;
5295 player->audio_stream_changed_cb_user_param = user_param;
5296 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5300 return MM_ERROR_NONE;
5304 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5306 mmplayer_t *player = (mmplayer_t *)hplayer;
5310 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5312 player->audio_decoded_cb = callback;
5313 player->audio_decoded_cb_user_param = user_param;
5314 player->audio_extract_opt = opt;
5315 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5319 return MM_ERROR_NONE;
5323 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5325 mmplayer_t *player = (mmplayer_t *)hplayer;
5329 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5331 if (callback && !player->bufmgr)
5332 player->bufmgr = tbm_bufmgr_init(-1);
5334 player->set_mode.video_export = (callback) ? true : false;
5335 player->video_decoded_cb = callback;
5336 player->video_decoded_cb_user_param = user_param;
5338 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5342 return MM_ERROR_NONE;
5346 _mmplayer_start(MMHandleType hplayer)
5348 mmplayer_t *player = (mmplayer_t *)hplayer;
5349 gint ret = MM_ERROR_NONE;
5353 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5355 /* check current state */
5356 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5358 /* start pipeline */
5359 ret = _mmplayer_gst_start(player);
5360 if (ret != MM_ERROR_NONE)
5361 LOGE("failed to start player.");
5363 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5364 LOGD("force playing start even during buffering");
5365 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5373 /* NOTE: post "not supported codec message" to application
5374 * when one codec is not found during AUTOPLUGGING in MSL.
5375 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5376 * And, if any codec is not found, don't send message here.
5377 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5380 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5382 MMMessageParamType msg_param;
5383 memset(&msg_param, 0, sizeof(MMMessageParamType));
5384 gboolean post_msg_direct = FALSE;
5388 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5390 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5391 player->not_supported_codec, player->can_support_codec);
5393 if (player->not_found_demuxer) {
5394 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5395 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5397 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5398 MMPLAYER_FREEIF(msg_param.data);
5400 return MM_ERROR_NONE;
5403 if (player->not_supported_codec) {
5404 if (player->can_support_codec) {
5405 // There is one codec to play
5406 post_msg_direct = TRUE;
5408 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5409 post_msg_direct = TRUE;
5412 if (post_msg_direct) {
5413 MMMessageParamType msg_param;
5414 memset(&msg_param, 0, sizeof(MMMessageParamType));
5416 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5417 LOGW("not found AUDIO codec, posting error code to application.");
5419 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5420 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5421 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5422 LOGW("not found VIDEO codec, posting error code to application.");
5424 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5425 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5428 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5430 MMPLAYER_FREEIF(msg_param.data);
5432 return MM_ERROR_NONE;
5434 // no any supported codec case
5435 LOGW("not found any codec, posting error code to application.");
5437 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5438 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5439 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5441 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5442 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5445 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5447 MMPLAYER_FREEIF(msg_param.data);
5453 return MM_ERROR_NONE;
5456 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5458 GstState element_state = GST_STATE_VOID_PENDING;
5459 GstState element_pending_state = GST_STATE_VOID_PENDING;
5460 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5461 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5463 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5465 MMPLAYER_RECONFIGURE_LOCK(player);
5466 if (!player->gapless.reconfigure) {
5467 MMPLAYER_RECONFIGURE_UNLOCK(player);
5471 LOGI("reconfigure is under process");
5472 MMPLAYER_RECONFIGURE_WAIT(player);
5473 MMPLAYER_RECONFIGURE_UNLOCK(player);
5474 LOGI("reconfigure is completed.");
5476 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5477 &element_state, &element_pending_state, timeout * GST_SECOND);
5478 if (result == GST_STATE_CHANGE_FAILURE)
5479 LOGW("failed to get pipeline state in %d sec", timeout);
5484 /* NOTE : it should be able to call 'stop' anytime*/
5486 _mmplayer_stop(MMHandleType hplayer)
5488 mmplayer_t *player = (mmplayer_t *)hplayer;
5489 int ret = MM_ERROR_NONE;
5493 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5495 /* check current state */
5496 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5498 /* need to wait till the rebuilding pipeline is completed */
5499 __mmplayer_check_pipeline_reconfigure_state(player);
5500 MMPLAYER_RECONFIGURE_LOCK(player);
5501 __mmplayer_reset_gapless_state(player);
5502 MMPLAYER_RECONFIGURE_UNLOCK(player);
5504 /* NOTE : application should not wait for EOS after calling STOP */
5505 _mmplayer_cancel_eos_timer(player);
5508 player->seek_state = MMPLAYER_SEEK_NONE;
5511 ret = _mmplayer_gst_stop(player);
5513 if (ret != MM_ERROR_NONE)
5514 LOGE("failed to stop player.");
5522 _mmplayer_pause(MMHandleType hplayer)
5524 mmplayer_t *player = (mmplayer_t *)hplayer;
5525 gint64 pos_nsec = 0;
5526 gboolean async = FALSE;
5527 gint ret = MM_ERROR_NONE;
5531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5533 /* check current state */
5534 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5536 /* check pipline reconfigure state */
5537 __mmplayer_check_pipeline_reconfigure_state(player);
5539 switch (MMPLAYER_CURRENT_STATE(player)) {
5540 case MM_PLAYER_STATE_READY:
5542 /* check prepare async or not.
5543 * In the case of streaming playback, it's recommned to avoid blocking wait.
5545 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5546 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5548 /* Changing back sync of rtspsrc to async */
5549 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5550 LOGD("async prepare working mode for rtsp");
5556 case MM_PLAYER_STATE_PLAYING:
5558 /* NOTE : store current point to overcome some bad operation
5559 *(returning zero when getting current position in paused state) of some
5562 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5563 LOGW("getting current position failed in paused");
5565 player->last_position = pos_nsec;
5567 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5568 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5569 This causes problem is position calculation during normal pause resume scenarios also.
5570 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5571 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5572 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5573 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5579 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5580 LOGD("doing async pause in case of ms buff src");
5584 /* pause pipeline */
5585 ret = _mmplayer_gst_pause(player, async);
5587 if (ret != MM_ERROR_NONE)
5588 LOGE("failed to pause player. ret : 0x%x", ret);
5590 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5591 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5592 LOGE("failed to update display_rotation");
5600 /* in case of streaming, pause could take long time.*/
5602 _mmplayer_abort_pause(MMHandleType hplayer)
5604 mmplayer_t *player = (mmplayer_t *)hplayer;
5605 int ret = MM_ERROR_NONE;
5609 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5611 player->pipeline->mainbin,
5612 MM_ERROR_PLAYER_NOT_INITIALIZED);
5614 LOGD("set the pipeline state to READY");
5616 /* set state to READY */
5617 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5618 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5619 if (ret != MM_ERROR_NONE) {
5620 LOGE("fail to change state to READY");
5621 return MM_ERROR_PLAYER_INTERNAL;
5624 LOGD("succeeded in changing state to READY");
5629 _mmplayer_resume(MMHandleType hplayer)
5631 mmplayer_t *player = (mmplayer_t *)hplayer;
5632 int ret = MM_ERROR_NONE;
5633 gboolean async = FALSE;
5637 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5639 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5640 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5641 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5645 /* Changing back sync mode rtspsrc to async */
5646 LOGD("async resume for rtsp case");
5650 /* check current state */
5651 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5653 ret = _mmplayer_gst_resume(player, async);
5654 if (ret != MM_ERROR_NONE)
5655 LOGE("failed to resume player.");
5657 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5658 LOGD("force resume even during buffering");
5659 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5668 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5670 mmplayer_t *player = (mmplayer_t *)hplayer;
5671 gint64 pos_nsec = 0;
5672 int ret = MM_ERROR_NONE;
5674 signed long long start = 0, stop = 0;
5675 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5678 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5679 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5681 /* The sound of video is not supported under 0.0 and over 2.0. */
5682 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5683 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5686 _mmplayer_set_mute(hplayer, mute);
5688 if (player->playback_rate == rate)
5689 return MM_ERROR_NONE;
5691 /* If the position is reached at start potion during fast backward, EOS is posted.
5692 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5694 player->playback_rate = rate;
5696 current_state = MMPLAYER_CURRENT_STATE(player);
5698 if (current_state != MM_PLAYER_STATE_PAUSED)
5699 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5701 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5703 if ((current_state == MM_PLAYER_STATE_PAUSED)
5704 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5705 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5706 pos_nsec = player->last_position;
5711 stop = GST_CLOCK_TIME_NONE;
5713 start = GST_CLOCK_TIME_NONE;
5717 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5718 player->playback_rate,
5720 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5721 GST_SEEK_TYPE_SET, start,
5722 GST_SEEK_TYPE_SET, stop)) {
5723 LOGE("failed to set speed playback");
5724 return MM_ERROR_PLAYER_SEEK;
5727 LOGD("succeeded to set speed playback as %0.1f", rate);
5731 return MM_ERROR_NONE;;
5735 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5737 mmplayer_t *player = (mmplayer_t *)hplayer;
5738 int ret = MM_ERROR_NONE;
5742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5744 /* check pipline reconfigure state */
5745 __mmplayer_check_pipeline_reconfigure_state(player);
5747 ret = _mmplayer_gst_set_position(player, position, FALSE);
5755 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5757 mmplayer_t *player = (mmplayer_t *)hplayer;
5758 int ret = MM_ERROR_NONE;
5760 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5761 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5763 if (g_strrstr(player->type, "video/mpegts"))
5764 __mmplayer_update_duration_value(player);
5766 *duration = player->duration;
5771 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5773 mmplayer_t *player = (mmplayer_t *)hplayer;
5774 int ret = MM_ERROR_NONE;
5776 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5778 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5784 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5786 mmplayer_t *player = (mmplayer_t *)hplayer;
5787 int ret = MM_ERROR_NONE;
5791 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5793 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5801 __mmplayer_is_midi_type(gchar *str_caps)
5803 if ((g_strrstr(str_caps, "audio/midi")) ||
5804 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5805 (g_strrstr(str_caps, "application/x-smaf")) ||
5806 (g_strrstr(str_caps, "audio/x-imelody")) ||
5807 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5808 (g_strrstr(str_caps, "audio/xmf")) ||
5809 (g_strrstr(str_caps, "audio/mxmf"))) {
5818 __mmplayer_is_only_mp3_type(gchar *str_caps)
5820 if (g_strrstr(str_caps, "application/x-id3") ||
5821 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5827 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5829 GstStructure *caps_structure = NULL;
5830 gint samplerate = 0;
5834 MMPLAYER_RETURN_IF_FAIL(player && caps);
5836 caps_structure = gst_caps_get_structure(caps, 0);
5838 /* set stream information */
5839 gst_structure_get_int(caps_structure, "rate", &samplerate);
5840 gst_structure_get_int(caps_structure, "channels", &channels);
5842 mm_player_set_attribute((MMHandleType)player, NULL,
5843 "content_audio_samplerate", samplerate,
5844 "content_audio_channels", channels, NULL);
5846 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5850 __mmplayer_update_content_type_info(mmplayer_t *player)
5853 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5855 if (__mmplayer_is_midi_type(player->type)) {
5856 player->bypass_audio_effect = TRUE;
5860 if (!player->streamer) {
5861 LOGD("no need to check streaming type");
5865 if (g_strrstr(player->type, "application/x-hls")) {
5866 /* If it can't know exact type when it parses uri because of redirection case,
5867 * it will be fixed by typefinder or when doing autoplugging.
5869 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5870 player->streamer->is_adaptive_streaming = TRUE;
5871 } else if (g_strrstr(player->type, "application/dash+xml")) {
5872 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5873 player->streamer->is_adaptive_streaming = TRUE;
5876 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5877 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5878 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5880 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5881 if (player->streamer->is_adaptive_streaming)
5882 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5884 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5888 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5893 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5894 GstCaps *caps, gpointer data)
5896 mmplayer_t *player = (mmplayer_t *)data;
5901 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5903 /* store type string */
5904 MMPLAYER_FREEIF(player->type);
5905 player->type = gst_caps_to_string(caps);
5907 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5908 player, player->type, probability, gst_caps_get_size(caps));
5910 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5911 (g_strrstr(player->type, "audio/x-raw-int"))) {
5912 LOGE("not support media format");
5914 if (player->msg_posted == FALSE) {
5915 MMMessageParamType msg_param;
5916 memset(&msg_param, 0, sizeof(MMMessageParamType));
5918 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5919 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5921 /* don't post more if one was sent already */
5922 player->msg_posted = TRUE;
5927 __mmplayer_update_content_type_info(player);
5929 pad = gst_element_get_static_pad(tf, "src");
5931 LOGE("fail to get typefind src pad.");
5935 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5936 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5937 gboolean async = FALSE;
5938 LOGE("failed to autoplug %s", player->type);
5940 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5942 if (async && player->msg_posted == FALSE)
5943 __mmplayer_handle_missed_plugin(player);
5947 gst_object_unref(GST_OBJECT(pad));
5953 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5955 GstElement *decodebin = NULL;
5959 /* create decodebin */
5960 decodebin = gst_element_factory_make("decodebin", NULL);
5963 LOGE("fail to create decodebin");
5967 /* raw pad handling signal */
5968 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5969 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5971 /* no-more-pad pad handling signal */
5972 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5973 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5975 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5976 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
5978 /* This signal is emitted when a pad for which there is no further possible
5979 decoding is added to the decodebin.*/
5980 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5981 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
5983 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5984 before looking for any elements that can handle that stream.*/
5985 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5986 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5988 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5989 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5990 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5992 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5993 before looking for any elements that can handle that stream.*/
5994 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5995 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5997 /* This signal is emitted once decodebin has finished decoding all the data.*/
5998 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5999 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6001 /* This signal is emitted when a element is added to the bin.*/
6002 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6003 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6010 __mmplayer_gst_make_queue2(mmplayer_t *player)
6012 GstElement *queue2 = NULL;
6013 gint64 dur_bytes = 0L;
6014 mmplayer_gst_element_t *mainbin = NULL;
6015 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6018 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6020 mainbin = player->pipeline->mainbin;
6022 queue2 = gst_element_factory_make("queue2", "queue2");
6024 LOGE("failed to create buffering queue element");
6028 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6029 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6031 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6033 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6034 * skip the pull mode(file or ring buffering) setting. */
6035 if (dur_bytes > 0) {
6036 if (!g_strrstr(player->type, "video/mpegts")) {
6037 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6038 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6044 _mm_player_streaming_set_queue2(player->streamer,
6048 (guint64)dur_bytes); /* no meaning at the moment */
6054 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6056 mmplayer_gst_element_t *mainbin = NULL;
6057 GstElement *decodebin = NULL;
6058 GstElement *queue2 = NULL;
6059 GstPad *sinkpad = NULL;
6060 GstPad *qsrcpad = NULL;
6063 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6065 mainbin = player->pipeline->mainbin;
6067 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6069 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6070 LOGW("need to check: muxed buffer is not null");
6073 queue2 = __mmplayer_gst_make_queue2(player);
6075 LOGE("failed to make queue2");
6079 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6080 LOGE("failed to add buffering queue");
6084 sinkpad = gst_element_get_static_pad(queue2, "sink");
6085 qsrcpad = gst_element_get_static_pad(queue2, "src");
6087 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6088 LOGE("failed to link [%s:%s]-[%s:%s]",
6089 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6093 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6094 LOGE("failed to sync queue2 state with parent");
6098 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6099 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6103 gst_object_unref(GST_OBJECT(sinkpad));
6107 /* create decodebin */
6108 decodebin = _mmplayer_gst_make_decodebin(player);
6110 LOGE("failed to make decodebin");
6114 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6115 LOGE("failed to add decodebin");
6119 /* to force caps on the decodebin element and avoid reparsing stuff by
6120 * typefind. It also avoids a deadlock in the way typefind activates pads in
6121 * the state change */
6122 g_object_set(decodebin, "sink-caps", caps, NULL);
6124 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6126 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6127 LOGE("failed to link [%s:%s]-[%s:%s]",
6128 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6132 gst_object_unref(GST_OBJECT(sinkpad));
6134 gst_object_unref(GST_OBJECT(qsrcpad));
6137 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6138 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6140 /* set decodebin property about buffer in streaming playback. *
6141 * in case of HLS/DASH, it does not need to have big buffer *
6142 * because it is kind of adaptive streaming. */
6143 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6144 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6145 gint high_percent = 0;
6147 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6148 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6150 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6152 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6154 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6155 "high-percent", high_percent,
6156 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6157 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6158 "max-size-buffers", 0, NULL); // disable or automatic
6161 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6162 LOGE("failed to sync decodebin state with parent");
6173 gst_object_unref(GST_OBJECT(sinkpad));
6176 gst_object_unref(GST_OBJECT(qsrcpad));
6179 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6180 * You need to explicitly set elements to the NULL state before
6181 * dropping the final reference, to allow them to clean up.
6183 gst_element_set_state(queue2, GST_STATE_NULL);
6185 /* And, it still has a parent "player".
6186 * You need to let the parent manage the object instead of unreffing the object directly.
6188 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6189 gst_object_unref(queue2);
6194 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6195 * You need to explicitly set elements to the NULL state before
6196 * dropping the final reference, to allow them to clean up.
6198 gst_element_set_state(decodebin, GST_STATE_NULL);
6200 /* And, it still has a parent "player".
6201 * You need to let the parent manage the object instead of unreffing the object directly.
6204 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6205 gst_object_unref(decodebin);
6213 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6217 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6218 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6220 LOGD("class : %s, mime : %s", factory_class, mime);
6222 /* add missing plugin */
6223 /* NOTE : msl should check missing plugin for image mime type.
6224 * Some motion jpeg clips can have playable audio track.
6225 * So, msl have to play audio after displaying popup written video format not supported.
6227 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6228 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6229 LOGD("not found demuxer");
6230 player->not_found_demuxer = TRUE;
6231 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6237 if (!g_strrstr(factory_class, "Demuxer")) {
6238 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6239 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6240 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6242 /* check that clip have multi tracks or not */
6243 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6244 LOGD("video plugin is already linked");
6246 LOGW("add VIDEO to missing plugin");
6247 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6248 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6250 } else if (g_str_has_prefix(mime, "audio")) {
6251 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6252 LOGD("audio plugin is already linked");
6254 LOGW("add AUDIO to missing plugin");
6255 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6256 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6264 return MM_ERROR_NONE;
6268 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6270 mmplayer_t *player = (mmplayer_t *)data;
6274 MMPLAYER_RETURN_IF_FAIL(player);
6276 /* remove fakesink. */
6277 if (!_mmplayer_gst_remove_fakesink(player,
6278 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6279 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6280 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6281 * source element are not same. To overcome this situation, this function will called
6282 * several places and several times. Therefore, this is not an error case.
6287 LOGD("[handle: %p] pipeline has completely constructed", player);
6289 if ((player->msg_posted == FALSE) &&
6290 (player->cmd >= MMPLAYER_COMMAND_START))
6291 __mmplayer_handle_missed_plugin(player);
6293 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6297 __mmplayer_check_profile(void)
6300 static int profile_tv = -1;
6302 if (__builtin_expect(profile_tv != -1, 1))
6305 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6306 switch (*profileName) {
6321 __mmplayer_get_next_uri(mmplayer_t *player)
6323 mmplayer_parse_profile_t profile;
6325 guint num_of_list = 0;
6328 num_of_list = g_list_length(player->uri_info.uri_list);
6329 uri_idx = player->uri_info.uri_idx;
6331 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6332 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6333 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6335 LOGW("next uri does not exist");
6339 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6340 LOGE("failed to parse profile");
6344 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6345 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6346 LOGW("uri type is not supported(%d)", profile.uri_type);
6350 LOGD("success to find next uri %d", uri_idx);
6354 if (!uri || uri_idx == num_of_list) {
6355 LOGE("failed to find next uri");
6359 player->uri_info.uri_idx = uri_idx;
6360 if (mm_player_set_attribute((MMHandleType)player, NULL,
6361 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6362 LOGE("failed to set attribute");
6366 SECURE_LOGD("next playback uri: %s", uri);
6371 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6373 #define REPEAT_COUNT_INFINITE -1
6374 #define REPEAT_COUNT_MIN 2
6375 #define ORIGINAL_URI_ONLY 1
6377 MMHandleType attrs = 0;
6381 guint num_of_uri = 0;
6382 int profile_tv = -1;
6386 LOGD("checking for gapless play option");
6388 if (player->build_audio_offload) {
6389 LOGE("offload path is not supportable.");
6393 if (player->pipeline->textbin) {
6394 LOGE("subtitle path is enabled. gapless play is not supported.");
6398 attrs = MMPLAYER_GET_ATTRS(player);
6400 LOGE("fail to get attributes.");
6404 mm_attrs_multiple_get(player->attrs, NULL,
6405 "content_video_found", &video,
6406 "profile_play_count", &count,
6407 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6409 /* gapless playback is not supported in case of video at TV profile. */
6410 profile_tv = __mmplayer_check_profile();
6411 if (profile_tv && video) {
6412 LOGW("not support video gapless playback");
6416 /* check repeat count in case of audio */
6418 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6419 LOGW("gapless is disabled");
6423 num_of_uri = g_list_length(player->uri_info.uri_list);
6425 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6427 if (num_of_uri == ORIGINAL_URI_ONLY) {
6428 /* audio looping path */
6429 if (count >= REPEAT_COUNT_MIN) {
6430 /* decrease play count */
6431 /* we succeeded to rewind. update play count and then wait for next EOS */
6433 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6434 } else if (count != REPEAT_COUNT_INFINITE) {
6435 LOGD("there is no next uri and no repeat");
6438 LOGD("looping cnt %d", count);
6440 /* gapless playback path */
6441 if (!__mmplayer_get_next_uri(player)) {
6442 LOGE("failed to get next uri");
6449 LOGE("unable to play gapless path. EOS will be posted soon");
6454 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6456 mmplayer_selector_t *selector = &player->selector[type];
6457 mmplayer_gst_element_t *sinkbin = NULL;
6458 main_element_id_e selectorId = MMPLAYER_M_NUM;
6459 main_element_id_e sinkId = MMPLAYER_M_NUM;
6460 GstPad *srcpad = NULL;
6461 GstPad *sinkpad = NULL;
6462 gboolean send_notice = FALSE;
6465 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6467 LOGD("type %d", type);
6470 case MM_PLAYER_TRACK_TYPE_AUDIO:
6471 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6472 sinkId = MMPLAYER_A_BIN;
6473 sinkbin = player->pipeline->audiobin;
6475 case MM_PLAYER_TRACK_TYPE_VIDEO:
6476 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6477 sinkId = MMPLAYER_V_BIN;
6478 sinkbin = player->pipeline->videobin;
6481 case MM_PLAYER_TRACK_TYPE_TEXT:
6482 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6483 sinkId = MMPLAYER_T_BIN;
6484 sinkbin = player->pipeline->textbin;
6487 LOGE("requested type is not supportable");
6492 if (player->pipeline->mainbin[selectorId].gst) {
6495 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6497 if (selector->event_probe_id != 0)
6498 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6499 selector->event_probe_id = 0;
6501 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6502 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6504 if (srcpad && sinkpad) {
6505 /* after getting drained signal there is no data flows, so no need to do pad_block */
6506 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6507 gst_pad_unlink(srcpad, sinkpad);
6509 /* send custom event to sink pad to handle it at video sink */
6511 LOGD("send custom event to sinkpad");
6512 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6513 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6514 gst_pad_send_event(sinkpad, event);
6518 gst_object_unref(sinkpad);
6521 gst_object_unref(srcpad);
6524 LOGD("selector release");
6526 /* release and unref requests pad from the selector */
6527 for (n = 0; n < selector->channels->len; n++) {
6528 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6529 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6531 g_ptr_array_set_size(selector->channels, 0);
6533 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6534 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6536 player->pipeline->mainbin[selectorId].gst = NULL;
6544 __mmplayer_deactivate_old_path(mmplayer_t *player)
6547 MMPLAYER_RETURN_IF_FAIL(player);
6549 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6550 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6551 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6552 LOGE("deactivate selector error");
6556 _mmplayer_track_destroy(player);
6557 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6559 if (player->streamer) {
6560 _mm_player_streaming_initialize(player->streamer, FALSE);
6561 _mm_player_streaming_destroy(player->streamer);
6562 player->streamer = NULL;
6565 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6571 if (!player->msg_posted) {
6572 MMMessageParamType msg = {0,};
6575 msg.code = MM_ERROR_PLAYER_INTERNAL;
6576 LOGE("gapless_uri_play> deactivate error");
6578 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6579 player->msg_posted = TRUE;
6585 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6587 int result = MM_ERROR_NONE;
6588 mmplayer_t *player = (mmplayer_t *)hplayer;
6591 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6592 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6594 if (mm_player_set_attribute(hplayer, NULL,
6595 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6596 LOGE("failed to set attribute");
6597 result = MM_ERROR_PLAYER_INTERNAL;
6599 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6600 LOGE("failed to add the original uri in the uri list.");
6608 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6610 mmplayer_t *player = (mmplayer_t *)hplayer;
6611 guint num_of_list = 0;
6615 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6616 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6618 if (player->pipeline && player->pipeline->textbin) {
6619 LOGE("subtitle path is enabled.");
6620 return MM_ERROR_PLAYER_INVALID_STATE;
6623 num_of_list = g_list_length(player->uri_info.uri_list);
6625 if (is_first_path) {
6626 if (num_of_list == 0) {
6627 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6628 SECURE_LOGD("add original path : %s", uri);
6630 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6631 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6633 SECURE_LOGD("change original path : %s", uri);
6636 MMHandleType attrs = 0;
6637 attrs = MMPLAYER_GET_ATTRS(player);
6639 if (num_of_list == 0) {
6640 char *original_uri = NULL;
6643 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6645 if (!original_uri) {
6646 LOGE("there is no original uri.");
6647 return MM_ERROR_PLAYER_INVALID_STATE;
6650 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6651 player->uri_info.uri_idx = 0;
6653 SECURE_LOGD("add original path at first : %s", original_uri);
6657 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6658 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6662 return MM_ERROR_NONE;
6666 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6668 mmplayer_t *player = (mmplayer_t *)hplayer;
6669 char *next_uri = NULL;
6670 guint num_of_list = 0;
6673 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6675 num_of_list = g_list_length(player->uri_info.uri_list);
6677 if (num_of_list > 0) {
6678 gint uri_idx = player->uri_info.uri_idx;
6680 if (uri_idx < num_of_list-1)
6685 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6686 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6688 *uri = g_strdup(next_uri);
6692 return MM_ERROR_NONE;
6696 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6697 GstCaps *caps, gpointer data)
6699 mmplayer_t *player = (mmplayer_t *)data;
6700 const gchar *klass = NULL;
6701 const gchar *mime = NULL;
6702 gchar *caps_str = NULL;
6704 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6705 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6706 caps_str = gst_caps_to_string(caps);
6708 LOGW("unknown type of caps : %s from %s",
6709 caps_str, GST_ELEMENT_NAME(elem));
6711 MMPLAYER_FREEIF(caps_str);
6713 /* There is no available codec. */
6714 __mmplayer_check_not_supported_codec(player, klass, mime);
6718 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6719 GstCaps *caps, gpointer data)
6721 mmplayer_t *player = (mmplayer_t *)data;
6722 const char *mime = NULL;
6723 gboolean ret = TRUE;
6725 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6726 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6728 if (g_str_has_prefix(mime, "audio")) {
6729 GstStructure *caps_structure = NULL;
6730 gint samplerate = 0;
6732 gchar *caps_str = NULL;
6734 caps_structure = gst_caps_get_structure(caps, 0);
6735 gst_structure_get_int(caps_structure, "rate", &samplerate);
6736 gst_structure_get_int(caps_structure, "channels", &channels);
6738 if ((channels > 0 && samplerate == 0)) {
6739 LOGD("exclude audio...");
6743 caps_str = gst_caps_to_string(caps);
6744 /* set it directly because not sent by TAG */
6745 if (g_strrstr(caps_str, "mobile-xmf"))
6746 mm_player_set_attribute((MMHandleType)player, NULL,
6747 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6749 MMPLAYER_FREEIF(caps_str);
6750 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6751 LOGD("already video linked");
6754 LOGD("found new stream");
6761 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6763 gboolean ret = FALSE;
6764 GDBusConnection *conn = NULL;
6766 GVariant *result = NULL;
6767 const gchar *dbus_device_type = NULL;
6768 const gchar *dbus_ret = NULL;
6771 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6773 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6778 result = g_dbus_connection_call_sync(conn,
6779 "org.pulseaudio.Server",
6780 "/org/pulseaudio/StreamManager",
6781 "org.pulseaudio.StreamManager",
6782 "GetCurrentMediaRoutingPath",
6783 g_variant_new("(s)", "out"),
6784 G_VARIANT_TYPE("(ss)"),
6785 G_DBUS_CALL_FLAGS_NONE,
6789 if (!result || err) {
6790 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6795 /* device type is listed in stream-map.json at mmfw-sysconf */
6796 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6798 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6799 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6802 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6803 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6804 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6805 LOGD("audio offload is supportable");
6811 LOGD("audio offload is not supportable");
6814 g_variant_unref(result);
6816 g_object_unref(conn);
6821 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6823 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6824 gint64 position = 0;
6826 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6827 player->pipeline && player->pipeline->mainbin);
6829 MMPLAYER_CMD_LOCK(player);
6830 current_state = MMPLAYER_CURRENT_STATE(player);
6832 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6833 LOGW("getting current position failed in paused");
6835 _mmplayer_unrealize((MMHandleType)player);
6836 _mmplayer_realize((MMHandleType)player);
6838 _mmplayer_set_position((MMHandleType)player, position);
6840 /* async not to be blocked in streaming case */
6841 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6843 _mmplayer_pause((MMHandleType)player);
6845 if (current_state == MM_PLAYER_STATE_PLAYING)
6846 _mmplayer_start((MMHandleType)player);
6847 MMPLAYER_CMD_UNLOCK(player);
6849 LOGD("rebuilding audio pipeline is completed.");
6852 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6854 mmplayer_t *player = (mmplayer_t *)user_data;
6855 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6856 gboolean is_supportable = FALSE;
6858 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6859 LOGW("failed to get device type");
6861 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6863 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6864 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6865 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6866 LOGD("ignore this dev connected info");
6870 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6871 if (player->build_audio_offload == is_supportable) {
6872 LOGD("keep current pipeline without re-building");
6876 /* rebuild pipeline */
6877 LOGD("re-build pipeline - offload: %d", is_supportable);
6878 player->build_audio_offload = FALSE;
6879 __mmplayer_rebuild_audio_pipeline(player);
6885 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6887 unsigned int id = 0;
6889 if (player->audio_device_cb_id != 0) {
6890 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6894 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6895 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6896 LOGD("added device connected cb (%u)", id);
6897 player->audio_device_cb_id = id;
6899 LOGW("failed to add device connected cb");
6906 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6908 mmplayer_t *player = (mmplayer_t *)hplayer;
6911 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6912 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6914 *activated = player->build_audio_offload;
6916 LOGD("offload activated : %d", (int)*activated);
6919 return MM_ERROR_NONE;
6923 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6926 this function need to be updated according to the supported media format
6927 @see player->ini.audio_offload_media_format */
6929 if (__mmplayer_is_only_mp3_type(player->type)) {
6930 LOGD("offload supportable media format type");
6938 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6940 gboolean ret = FALSE;
6941 GstElementFactory *factory = NULL;
6944 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6946 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6947 if (!__mmplayer_is_offload_supported_type(player))
6950 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6951 LOGD("there is no audio offload sink");
6955 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6956 LOGW("there is no audio device type to support offload");
6960 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6962 LOGW("there is no installed audio offload sink element");
6965 gst_object_unref(factory);
6967 if (__mmplayer_acquire_hw_resource(player,
6968 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6969 LOGE("failed to acquire audio offload decoder resource");
6973 if (!__mmplayer_add_audio_device_connected_cb(player))
6976 if (!__mmplayer_is_audio_offload_device_type(player))
6979 LOGD("audio offload can be built");
6984 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6990 static GstAutoplugSelectResult
6991 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6993 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6994 int audio_offload = 0;
6996 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6997 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6999 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7000 LOGD("expose audio path to build offload output path");
7001 player->build_audio_offload = TRUE;
7002 /* update codec info */
7003 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7004 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7005 player->audiodec_linked = 1;
7007 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7011 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7012 And need to consider the multi-track audio content.
7013 There is no HW audio decoder in public. */
7015 /* set stream information */
7016 if (!player->audiodec_linked)
7017 __mmplayer_set_audio_attrs(player, caps);
7019 /* update codec info */
7020 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7021 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7022 player->audiodec_linked = 1;
7024 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7026 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7027 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7029 /* mark video decoder for acquire */
7030 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7031 LOGW("video decoder resource is already acquired, skip it.");
7032 ret = GST_AUTOPLUG_SELECT_SKIP;
7036 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7037 LOGE("failed to acquire video decoder resource");
7038 ret = GST_AUTOPLUG_SELECT_SKIP;
7041 player->interrupted_by_resource = FALSE;
7044 /* update codec info */
7045 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7046 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7047 player->videodec_linked = 1;
7055 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7056 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7058 #define DEFAULT_IDX 0xFFFF
7059 #define MIN_FACTORY_NUM 2
7060 mmplayer_t *player = (mmplayer_t *)data;
7061 GValueArray *new_factories = NULL;
7062 GValue val = { 0, };
7063 GstElementFactory *factory = NULL;
7064 const gchar *klass = NULL;
7065 gchar *factory_name = NULL;
7066 guint hw_dec_idx = DEFAULT_IDX;
7067 guint first_sw_dec_idx = DEFAULT_IDX;
7068 guint last_sw_dec_idx = DEFAULT_IDX;
7069 guint new_pos = DEFAULT_IDX;
7070 guint rm_pos = DEFAULT_IDX;
7071 int audio_codec_type;
7072 int video_codec_type;
7073 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7075 if (factories->n_values < MIN_FACTORY_NUM)
7078 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7079 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7082 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7084 for (int i = 0 ; i < factories->n_values ; i++) {
7085 gchar *hw_dec_info = NULL;
7086 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7088 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7090 LOGW("failed to get factory object");
7093 klass = gst_element_factory_get_klass(factory);
7094 factory_name = GST_OBJECT_NAME(factory);
7097 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7099 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7100 if (!player->need_audio_dec_sorting) {
7101 LOGD("sorting is not required");
7104 codec_type = audio_codec_type;
7105 hw_dec_info = player->ini.audiocodec_element_hw;
7106 sw_dec_info = player->ini.audiocodec_element_sw;
7107 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7108 if (!player->need_video_dec_sorting) {
7109 LOGD("sorting is not required");
7112 codec_type = video_codec_type;
7113 hw_dec_info = player->ini.videocodec_element_hw;
7114 sw_dec_info = player->ini.videocodec_element_sw;
7119 if (g_strrstr(factory_name, hw_dec_info)) {
7122 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7123 if (strstr(factory_name, sw_dec_info[j])) {
7124 last_sw_dec_idx = i;
7125 if (first_sw_dec_idx == DEFAULT_IDX) {
7126 first_sw_dec_idx = i;
7131 if (first_sw_dec_idx == DEFAULT_IDX)
7132 LOGW("unknown codec %s", factory_name);
7136 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7139 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7140 if (hw_dec_idx < first_sw_dec_idx)
7142 new_pos = first_sw_dec_idx;
7143 rm_pos = hw_dec_idx + 1;
7144 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7145 if (last_sw_dec_idx < hw_dec_idx)
7147 new_pos = last_sw_dec_idx + 1;
7148 rm_pos = hw_dec_idx;
7153 /* change position - insert H/W decoder according to the new position */
7154 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7156 LOGW("failed to get factory object");
7159 new_factories = g_value_array_copy(factories);
7160 g_value_init (&val, G_TYPE_OBJECT);
7161 g_value_set_object (&val, factory);
7162 g_value_array_insert(new_factories, new_pos, &val);
7163 g_value_unset (&val);
7164 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7166 for (int i = 0 ; i < new_factories->n_values ; i++) {
7167 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7169 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7170 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7172 LOGE("[Re-arranged] failed to get factory object");
7175 return new_factories;
7179 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7180 GstCaps *caps, GstElementFactory *factory, gpointer data)
7182 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7183 mmplayer_t *player = (mmplayer_t *)data;
7185 gchar *factory_name = NULL;
7186 gchar *caps_str = NULL;
7187 const gchar *klass = NULL;
7190 factory_name = GST_OBJECT_NAME(factory);
7191 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7192 caps_str = gst_caps_to_string(caps);
7194 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7196 /* store type string */
7197 if (player->type == NULL) {
7198 player->type = gst_caps_to_string(caps);
7199 __mmplayer_update_content_type_info(player);
7202 /* filtering exclude keyword */
7203 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7204 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7205 LOGW("skipping [%s] by exculde keyword [%s]",
7206 factory_name, player->ini.exclude_element_keyword[idx]);
7208 result = GST_AUTOPLUG_SELECT_SKIP;
7213 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7214 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7215 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7216 factory_name, player->ini.unsupported_codec_keyword[idx]);
7217 result = GST_AUTOPLUG_SELECT_SKIP;
7222 /* exclude webm format */
7223 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7224 * because webm format is not supportable.
7225 * If webm is disabled in "autoplug-continue", there is no state change
7226 * failure or error because the decodebin will expose the pad directly.
7227 * It make MSL invoke _prepare_async_callback.
7228 * So, we need to disable webm format in "autoplug-select" */
7229 if (caps_str && strstr(caps_str, "webm")) {
7230 LOGW("webm is not supported");
7231 result = GST_AUTOPLUG_SELECT_SKIP;
7235 /* check factory class for filtering */
7236 /* NOTE : msl don't need to use image plugins.
7237 * So, those plugins should be skipped for error handling.
7239 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7240 LOGD("skipping [%s] by not required", factory_name);
7241 result = GST_AUTOPLUG_SELECT_SKIP;
7245 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7246 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7247 // TO CHECK : subtitle if needed, add subparse exception.
7248 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7249 result = GST_AUTOPLUG_SELECT_SKIP;
7253 if (g_strrstr(factory_name, "mpegpsdemux")) {
7254 LOGD("skipping PS container - not support");
7255 result = GST_AUTOPLUG_SELECT_SKIP;
7259 if (g_strrstr(factory_name, "mssdemux"))
7260 player->smooth_streaming = TRUE;
7262 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7263 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7266 GstStructure *str = NULL;
7267 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7269 /* don't make video because of not required */
7270 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7271 (!player->set_mode.video_export)) {
7272 LOGD("no need video decoding, expose pad");
7273 result = GST_AUTOPLUG_SELECT_EXPOSE;
7277 /* get w/h for omx state-tune */
7278 /* FIXME: deprecated? */
7279 str = gst_caps_get_structure(caps, 0);
7280 gst_structure_get_int(str, "width", &width);
7283 if (player->v_stream_caps) {
7284 gst_caps_unref(player->v_stream_caps);
7285 player->v_stream_caps = NULL;
7288 player->v_stream_caps = gst_caps_copy(caps);
7289 LOGD("take caps for video state tune");
7290 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7294 if (g_strrstr(klass, "Codec/Decoder")) {
7295 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7296 if (result != GST_AUTOPLUG_SELECT_TRY) {
7297 LOGW("skip add decoder");
7303 MMPLAYER_FREEIF(caps_str);
7309 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7312 //mmplayer_t *player = (mmplayer_t *)data;
7313 GstCaps *caps = NULL;
7315 LOGD("[Decodebin2] pad-removed signal");
7317 caps = gst_pad_query_caps(new_pad, NULL);
7319 LOGW("query caps is NULL");
7323 gchar *caps_str = NULL;
7324 caps_str = gst_caps_to_string(caps);
7326 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7328 MMPLAYER_FREEIF(caps_str);
7329 gst_caps_unref(caps);
7333 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7335 mmplayer_t *player = (mmplayer_t *)data;
7336 GstIterator *iter = NULL;
7337 GValue item = { 0, };
7339 gboolean done = FALSE;
7340 gboolean is_all_drained = TRUE;
7343 MMPLAYER_RETURN_IF_FAIL(player);
7345 LOGD("got drained signal");
7347 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7348 LOGW("Fail to get cmd lock");
7352 if (!__mmplayer_verify_gapless_play_path(player)) {
7353 LOGD("decoding is finished.");
7354 MMPLAYER_CMD_UNLOCK(player);
7358 _mmplayer_set_reconfigure_state(player, TRUE);
7359 MMPLAYER_CMD_UNLOCK(player);
7361 /* check decodebin src pads whether they received EOS or not */
7362 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7365 switch (gst_iterator_next(iter, &item)) {
7366 case GST_ITERATOR_OK:
7367 pad = g_value_get_object(&item);
7368 if (pad && !GST_PAD_IS_EOS(pad)) {
7369 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7370 is_all_drained = FALSE;
7373 g_value_reset(&item);
7375 case GST_ITERATOR_RESYNC:
7376 gst_iterator_resync(iter);
7378 case GST_ITERATOR_ERROR:
7379 case GST_ITERATOR_DONE:
7384 g_value_unset(&item);
7385 gst_iterator_free(iter);
7387 if (!is_all_drained) {
7388 LOGD("Wait util the all pads get EOS.");
7393 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7394 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7396 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7397 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7398 __mmplayer_deactivate_old_path(player);
7404 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7406 mmplayer_t *player = (mmplayer_t *)data;
7407 const gchar *klass = NULL;
7408 gchar *factory_name = NULL;
7410 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7411 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7413 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7415 if (__mmplayer_add_dump_buffer_probe(player, element))
7416 LOGD("add buffer probe");
7418 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7419 gchar *selected = NULL;
7420 selected = g_strdup(GST_ELEMENT_NAME(element));
7421 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7424 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7425 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7426 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7428 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7429 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7431 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7432 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7433 "max-video-width", player->adaptive_info.limit.width,
7434 "max-video-height", player->adaptive_info.limit.height, NULL);
7436 } else if (g_strrstr(klass, "Demuxer")) {
7438 LOGD("plugged element is demuxer. take it");
7440 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7441 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7444 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7445 int surface_type = 0;
7447 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7450 // to support trust-zone only
7451 if (g_strrstr(factory_name, "asfdemux")) {
7452 LOGD("set file-location %s", player->profile.uri);
7453 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7454 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7455 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7456 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7457 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7458 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7459 (__mmplayer_is_only_mp3_type(player->type))) {
7460 LOGD("[mpegaudioparse] set streaming pull mode.");
7461 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7463 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7464 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7467 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7468 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7469 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7471 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7472 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7474 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7475 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7476 (MMPLAYER_IS_DASH_STREAMING(player))) {
7477 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7478 _mm_player_streaming_set_multiqueue(player->streamer, element);
7479 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7488 __mmplayer_release_misc(mmplayer_t *player)
7491 bool cur_mode = player->set_mode.rich_audio;
7494 MMPLAYER_RETURN_IF_FAIL(player);
7496 player->sent_bos = FALSE;
7497 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7499 player->seek_state = MMPLAYER_SEEK_NONE;
7501 player->total_bitrate = 0;
7502 player->total_maximum_bitrate = 0;
7504 player->not_found_demuxer = 0;
7506 player->last_position = 0;
7507 player->duration = 0;
7508 player->http_content_size = 0;
7509 player->not_supported_codec = MISSING_PLUGIN_NONE;
7510 player->can_support_codec = FOUND_PLUGIN_NONE;
7511 player->pending_seek.is_pending = false;
7512 player->pending_seek.pos = 0;
7513 player->msg_posted = FALSE;
7514 player->has_many_types = FALSE;
7515 player->is_subtitle_force_drop = FALSE;
7516 player->play_subtitle = FALSE;
7517 player->adjust_subtitle_pos = 0;
7518 player->has_closed_caption = FALSE;
7519 player->set_mode.video_export = false;
7520 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7521 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7523 player->set_mode.rich_audio = cur_mode;
7525 if (player->audio_device_cb_id > 0 &&
7526 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7527 LOGW("failed to remove audio device_connected_callback");
7528 player->audio_device_cb_id = 0;
7530 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7531 player->bitrate[i] = 0;
7532 player->maximum_bitrate[i] = 0;
7535 /* free memory related to audio effect */
7536 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7538 if (player->adaptive_info.var_list) {
7539 g_list_free_full(player->adaptive_info.var_list, g_free);
7540 player->adaptive_info.var_list = NULL;
7543 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7544 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7545 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7547 /* Reset video360 settings to their defaults in case if the pipeline is to be
7550 player->video360_metadata.is_spherical = -1;
7551 player->is_openal_plugin_used = FALSE;
7553 player->is_content_spherical = FALSE;
7554 player->is_video360_enabled = TRUE;
7555 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7556 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7557 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7558 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7559 player->video360_zoom = 1.0f;
7560 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7561 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7563 player->sound.rg_enable = false;
7565 __mmplayer_initialize_video_roi(player);
7570 __mmplayer_release_misc_post(mmplayer_t *player)
7572 char *original_uri = NULL;
7575 /* player->pipeline is already released before. */
7576 MMPLAYER_RETURN_IF_FAIL(player);
7578 player->video_decoded_cb = NULL;
7579 player->video_decoded_cb_user_param = NULL;
7580 player->video_stream_prerolled = false;
7582 player->audio_decoded_cb = NULL;
7583 player->audio_decoded_cb_user_param = NULL;
7584 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7586 player->audio_stream_changed_cb = NULL;
7587 player->audio_stream_changed_cb_user_param = NULL;
7589 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7591 /* clean found audio decoders */
7592 if (player->audio_decoders) {
7593 GList *a_dec = player->audio_decoders;
7594 for (; a_dec; a_dec = g_list_next(a_dec)) {
7595 gchar *name = a_dec->data;
7596 MMPLAYER_FREEIF(name);
7598 g_list_free(player->audio_decoders);
7599 player->audio_decoders = NULL;
7602 /* clean the uri list except original uri */
7603 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7604 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7606 LOGW("failed to get original uri info");
7608 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7609 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7611 GList *uri_list = player->uri_info.uri_list;
7612 for (; uri_list; uri_list = g_list_next(uri_list)) {
7613 gchar *uri = uri_list->data;
7614 if (original_uri != uri)
7615 MMPLAYER_FREEIF(uri);
7619 /* clear the audio stream buffer list */
7620 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7622 /* clear the video stream bo list */
7623 __mmplayer_video_stream_destroy_bo_list(player);
7624 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7626 if (player->profile.input_mem.buf) {
7627 free(player->profile.input_mem.buf);
7628 player->profile.input_mem.buf = NULL;
7630 player->profile.input_mem.len = 0;
7631 player->profile.input_mem.offset = 0;
7633 player->uri_info.uri_idx = 0;
7638 __mmplayer_check_subtitle(mmplayer_t *player)
7640 MMHandleType attrs = 0;
7641 char *subtitle_uri = NULL;
7645 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7647 /* get subtitle attribute */
7648 attrs = MMPLAYER_GET_ATTRS(player);
7652 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7653 if (!subtitle_uri || !strlen(subtitle_uri))
7656 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7657 player->is_external_subtitle_present = TRUE;
7665 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7667 MMPLAYER_RETURN_IF_FAIL(player);
7669 if (player->eos_timer) {
7670 LOGD("cancel eos timer");
7671 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7672 player->eos_timer = 0;
7679 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7683 MMPLAYER_RETURN_IF_FAIL(player);
7684 MMPLAYER_RETURN_IF_FAIL(sink);
7686 player->sink_elements = g_list_append(player->sink_elements, sink);
7692 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7696 MMPLAYER_RETURN_IF_FAIL(player);
7697 MMPLAYER_RETURN_IF_FAIL(sink);
7699 player->sink_elements = g_list_remove(player->sink_elements, sink);
7705 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7706 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7708 mmplayer_signal_item_t *item = NULL;
7711 MMPLAYER_RETURN_IF_FAIL(player);
7713 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7714 LOGE("invalid signal type [%d]", type);
7718 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7720 LOGE("cannot connect signal [%s]", signal);
7725 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7726 player->signals[type] = g_list_append(player->signals[type], item);
7732 /* NOTE : be careful with calling this api. please refer to below glib comment
7733 * glib comment : Note that there is a bug in GObject that makes this function much
7734 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7735 * will no longer be called, but, the signal handler is not currently disconnected.
7736 * If the instance is itself being freed at the same time than this doesn't matter,
7737 * since the signal will automatically be removed, but if instance persists,
7738 * then the signal handler will leak. You should not remove the signal yourself
7739 * because in a future versions of GObject, the handler will automatically be
7742 * It's possible to work around this problem in a way that will continue to work
7743 * with future versions of GObject by checking that the signal handler is still
7744 * connected before disconnected it:
7746 * if (g_signal_handler_is_connected(instance, id))
7747 * g_signal_handler_disconnect(instance, id);
7750 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7752 GList *sig_list = NULL;
7753 mmplayer_signal_item_t *item = NULL;
7757 MMPLAYER_RETURN_IF_FAIL(player);
7759 LOGD("release signals type : %d", type);
7761 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7762 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7764 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7765 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7766 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7770 sig_list = player->signals[type];
7772 for (; sig_list; sig_list = sig_list->next) {
7773 item = sig_list->data;
7775 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7776 if (g_signal_handler_is_connected(item->obj, item->sig))
7777 g_signal_handler_disconnect(item->obj, item->sig);
7780 MMPLAYER_FREEIF(item);
7783 g_list_free(player->signals[type]);
7784 player->signals[type] = NULL;
7792 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7794 mmplayer_t *player = 0;
7795 int prev_display_surface_type = 0;
7799 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7801 player = MM_PLAYER_CAST(handle);
7803 /* check video sinkbin is created */
7804 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7805 LOGW("Videosink is already created");
7806 return MM_ERROR_NONE;
7809 LOGD("videosink element is not yet ready");
7811 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7812 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7814 return MM_ERROR_INVALID_ARGUMENT;
7817 /* load previous attributes */
7818 if (player->attrs) {
7819 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7820 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7821 if (prev_display_surface_type == surface_type) {
7822 LOGD("incoming display surface type is same as previous one, do nothing..");
7824 return MM_ERROR_NONE;
7827 LOGE("failed to load attributes");
7829 return MM_ERROR_PLAYER_INTERNAL;
7832 /* videobin is not created yet, so we just set attributes related to display surface */
7833 LOGD("store display attribute for given surface type(%d)", surface_type);
7834 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7835 "display_overlay", wl_surface_id, NULL);
7838 return MM_ERROR_NONE;
7841 /* Note : if silent is true, then subtitle would not be displayed. :*/
7843 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7845 mmplayer_t *player = (mmplayer_t *)hplayer;
7849 /* check player handle */
7850 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7852 player->set_mode.subtitle_off = silent;
7854 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7858 return MM_ERROR_NONE;
7862 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7864 mmplayer_gst_element_t *mainbin = NULL;
7865 mmplayer_gst_element_t *textbin = NULL;
7866 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7867 GstState current_state = GST_STATE_VOID_PENDING;
7868 GstState element_state = GST_STATE_VOID_PENDING;
7869 GstState element_pending_state = GST_STATE_VOID_PENDING;
7871 GstEvent *event = NULL;
7872 int result = MM_ERROR_NONE;
7874 GstClock *curr_clock = NULL;
7875 GstClockTime base_time, start_time, curr_time;
7880 /* check player handle */
7881 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7883 player->pipeline->mainbin &&
7884 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7886 mainbin = player->pipeline->mainbin;
7887 textbin = player->pipeline->textbin;
7889 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7891 // sync clock with current pipeline
7892 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7893 curr_time = gst_clock_get_time(curr_clock);
7895 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7896 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7898 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7899 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7901 if (current_state > GST_STATE_READY) {
7902 // sync state with current pipeline
7903 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7904 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7905 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7907 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7908 if (GST_STATE_CHANGE_FAILURE == ret) {
7909 LOGE("fail to state change.");
7910 result = MM_ERROR_PLAYER_INTERNAL;
7914 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7915 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7918 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7919 gst_object_unref(curr_clock);
7922 // seek to current position
7923 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7924 result = MM_ERROR_PLAYER_INVALID_STATE;
7925 LOGE("gst_element_query_position failed, invalid state");
7929 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7930 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);
7932 _mmplayer_gst_send_event_to_sink(player, event);
7934 result = MM_ERROR_PLAYER_INTERNAL;
7935 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7939 /* sync state with current pipeline */
7940 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7941 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7942 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7944 return MM_ERROR_NONE;
7947 /* release text pipeline resource */
7948 player->textsink_linked = 0;
7950 /* release signal */
7951 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7953 /* release textbin with it's childs */
7954 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7955 MMPLAYER_FREEIF(player->pipeline->textbin);
7956 player->pipeline->textbin = NULL;
7958 /* release subtitle elem */
7959 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7960 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7966 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7968 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7969 GstState current_state = GST_STATE_VOID_PENDING;
7971 MMHandleType attrs = 0;
7972 mmplayer_gst_element_t *mainbin = NULL;
7973 mmplayer_gst_element_t *textbin = NULL;
7975 gchar *subtitle_uri = NULL;
7976 int result = MM_ERROR_NONE;
7977 const gchar *charset = NULL;
7981 /* check player handle */
7982 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7984 player->pipeline->mainbin &&
7985 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7986 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7988 mainbin = player->pipeline->mainbin;
7989 textbin = player->pipeline->textbin;
7991 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7992 if (current_state < GST_STATE_READY) {
7993 result = MM_ERROR_PLAYER_INVALID_STATE;
7994 LOGE("Pipeline is not in proper state");
7998 attrs = MMPLAYER_GET_ATTRS(player);
8000 LOGE("cannot get content attribute");
8001 result = MM_ERROR_PLAYER_INTERNAL;
8005 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8006 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8007 LOGE("subtitle uri is not proper filepath");
8008 result = MM_ERROR_PLAYER_INVALID_URI;
8012 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8013 LOGE("failed to get storage info of subtitle path");
8014 result = MM_ERROR_PLAYER_INVALID_URI;
8018 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8019 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8021 if (!strcmp(filepath, subtitle_uri)) {
8022 LOGD("subtitle path is not changed");
8025 if (mm_player_set_attribute((MMHandleType)player, NULL,
8026 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8027 LOGE("failed to set attribute");
8032 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8033 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8034 player->subtitle_language_list = NULL;
8035 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8037 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8038 if (ret != GST_STATE_CHANGE_SUCCESS) {
8039 LOGE("failed to change state of textbin to READY");
8040 result = MM_ERROR_PLAYER_INTERNAL;
8044 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8045 if (ret != GST_STATE_CHANGE_SUCCESS) {
8046 LOGE("failed to change state of subparse to READY");
8047 result = MM_ERROR_PLAYER_INTERNAL;
8051 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8052 if (ret != GST_STATE_CHANGE_SUCCESS) {
8053 LOGE("failed to change state of filesrc to READY");
8054 result = MM_ERROR_PLAYER_INTERNAL;
8058 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8060 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8062 charset = _mmplayer_get_charset(filepath);
8064 LOGD("detected charset is %s", charset);
8065 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8068 result = _mmplayer_sync_subtitle_pipeline(player);
8075 /* API to switch between external subtitles */
8077 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8079 int result = MM_ERROR_NONE;
8080 mmplayer_t *player = (mmplayer_t *)hplayer;
8085 /* check player handle */
8086 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8088 /* filepath can be null in idle state */
8090 /* check file path */
8091 if ((path = strstr(filepath, "file://")))
8092 result = _mmplayer_exist_file_path(path + 7);
8094 result = _mmplayer_exist_file_path(filepath);
8096 if (result != MM_ERROR_NONE) {
8097 LOGE("invalid subtitle path 0x%X", result);
8098 return result; /* file not found or permission denied */
8102 if (!player->pipeline) {
8104 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8105 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8106 LOGE("failed to set attribute");
8107 return MM_ERROR_PLAYER_INTERNAL;
8110 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8111 /* check filepath */
8112 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8114 if (!__mmplayer_check_subtitle(player)) {
8115 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8116 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8117 LOGE("failed to set attribute");
8118 return MM_ERROR_PLAYER_INTERNAL;
8121 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8122 LOGE("fail to create text pipeline");
8123 return MM_ERROR_PLAYER_INTERNAL;
8126 result = _mmplayer_sync_subtitle_pipeline(player);
8128 result = __mmplayer_change_external_subtitle_language(player, filepath);
8131 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8132 player->is_external_subtitle_added_now = TRUE;
8134 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8135 if (!player->subtitle_language_list) {
8136 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8137 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8138 LOGW("subtitle language list is not updated yet");
8140 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8148 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8150 int result = MM_ERROR_NONE;
8151 gchar *change_pad_name = NULL;
8152 GstPad *sinkpad = NULL;
8153 mmplayer_gst_element_t *mainbin = NULL;
8154 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8155 GstCaps *caps = NULL;
8156 gint total_track_num = 0;
8160 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8161 MM_ERROR_PLAYER_NOT_INITIALIZED);
8163 LOGD("Change Track(%d) to %d", type, index);
8165 mainbin = player->pipeline->mainbin;
8167 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8168 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8169 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8170 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8172 /* Changing Video Track is not supported. */
8173 LOGE("Track Type Error");
8177 if (mainbin[elem_idx].gst == NULL) {
8178 result = MM_ERROR_PLAYER_NO_OP;
8179 LOGD("Req track doesn't exist");
8183 total_track_num = player->selector[type].total_track_num;
8184 if (total_track_num <= 0) {
8185 result = MM_ERROR_PLAYER_NO_OP;
8186 LOGD("Language list is not available");
8190 if ((index < 0) || (index >= total_track_num)) {
8191 result = MM_ERROR_INVALID_ARGUMENT;
8192 LOGD("Not a proper index : %d", index);
8196 /*To get the new pad from the selector*/
8197 change_pad_name = g_strdup_printf("sink_%u", index);
8198 if (change_pad_name == NULL) {
8199 result = MM_ERROR_PLAYER_INTERNAL;
8200 LOGD("Pad does not exists");
8204 LOGD("new active pad name: %s", change_pad_name);
8206 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8207 if (sinkpad == NULL) {
8208 LOGD("sinkpad is NULL");
8209 result = MM_ERROR_PLAYER_INTERNAL;
8213 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8214 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8216 caps = gst_pad_get_current_caps(sinkpad);
8217 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8220 gst_object_unref(sinkpad);
8222 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8223 __mmplayer_set_audio_attrs(player, caps);
8226 MMPLAYER_FREEIF(change_pad_name);
8231 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8233 int result = MM_ERROR_NONE;
8234 mmplayer_t *player = NULL;
8235 mmplayer_gst_element_t *mainbin = NULL;
8237 gint current_active_index = 0;
8239 GstState current_state = GST_STATE_VOID_PENDING;
8240 GstEvent *event = NULL;
8245 player = (mmplayer_t *)hplayer;
8246 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8248 if (!player->pipeline) {
8249 LOGE("Track %d pre setting -> %d", type, index);
8251 player->selector[type].active_pad_index = index;
8255 mainbin = player->pipeline->mainbin;
8257 current_active_index = player->selector[type].active_pad_index;
8259 /*If index is same as running index no need to change the pad*/
8260 if (current_active_index == index)
8263 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8264 result = MM_ERROR_PLAYER_INVALID_STATE;
8268 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8269 if (current_state < GST_STATE_PAUSED) {
8270 result = MM_ERROR_PLAYER_INVALID_STATE;
8271 LOGW("Pipeline not in porper state");
8275 result = __mmplayer_change_selector_pad(player, type, index);
8276 if (result != MM_ERROR_NONE) {
8277 LOGE("change selector pad error");
8281 player->selector[type].active_pad_index = index;
8283 if (current_state == GST_STATE_PLAYING) {
8284 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8285 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8286 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8288 _mmplayer_gst_send_event_to_sink(player, event);
8290 result = MM_ERROR_PLAYER_INTERNAL;
8300 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8302 mmplayer_t *player = (mmplayer_t *)hplayer;
8306 /* check player handle */
8307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8309 *silent = player->set_mode.subtitle_off;
8311 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8315 return MM_ERROR_NONE;
8319 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8321 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8322 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8324 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8325 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8329 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8330 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8331 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8332 mmplayer_dump_t *dump_s;
8333 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8334 if (dump_s == NULL) {
8335 LOGE("malloc fail");
8339 dump_s->dump_element_file = NULL;
8340 dump_s->dump_pad = NULL;
8341 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8343 if (dump_s->dump_pad) {
8344 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8345 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]);
8346 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8347 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);
8348 /* add list for removed buffer probe and close FILE */
8349 player->dump_list = g_list_append(player->dump_list, dump_s);
8350 LOGD("%s sink pad added buffer probe for dump", factory_name);
8353 MMPLAYER_FREEIF(dump_s);
8354 LOGE("failed to get %s sink pad added", factory_name);
8361 static GstPadProbeReturn
8362 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8364 FILE *dump_data = (FILE *)u_data;
8366 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8367 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8369 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8371 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8373 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8375 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8377 gst_buffer_unmap(buffer, &probe_info);
8379 return GST_PAD_PROBE_OK;
8383 __mmplayer_release_dump_list(GList *dump_list)
8385 GList *d_list = dump_list;
8390 for (; d_list; d_list = g_list_next(d_list)) {
8391 mmplayer_dump_t *dump_s = d_list->data;
8392 if (dump_s->dump_pad) {
8393 if (dump_s->probe_handle_id)
8394 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8395 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8397 if (dump_s->dump_element_file) {
8398 fclose(dump_s->dump_element_file);
8399 dump_s->dump_element_file = NULL;
8401 MMPLAYER_FREEIF(dump_s);
8403 g_list_free(dump_list);
8408 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8410 mmplayer_t *player = (mmplayer_t *)hplayer;
8414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8415 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8417 *exist = (bool)player->has_closed_caption;
8421 return MM_ERROR_NONE;
8425 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8430 LOGD("unref internal gst buffer %p", buffer);
8432 gst_buffer_unref((GstBuffer *)buffer);
8439 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8441 mmplayer_t *player = (mmplayer_t *)hplayer;
8445 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8446 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8448 if (MMPLAYER_IS_STREAMING(player))
8449 *timeout = (int)player->ini.live_state_change_timeout;
8451 *timeout = (int)player->ini.localplayback_state_change_timeout;
8453 LOGD("timeout = %d", *timeout);
8456 return MM_ERROR_NONE;
8460 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8464 MMPLAYER_RETURN_IF_FAIL(player);
8466 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8468 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8469 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8470 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8471 player->storage_info[i].id = -1;
8472 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8474 if (path_type != MMPLAYER_PATH_MAX)
8483 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8485 int ret = MM_ERROR_NONE;
8486 mmplayer_t *player = (mmplayer_t *)hplayer;
8487 MMMessageParamType msg_param = {0, };
8490 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8492 LOGW("state changed storage %d:%d", id, state);
8494 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8495 return MM_ERROR_NONE;
8497 /* FIXME: text path should be handled seperately. */
8498 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8499 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8500 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8501 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8502 LOGW("external storage is removed");
8504 if (player->msg_posted == FALSE) {
8505 memset(&msg_param, 0, sizeof(MMMessageParamType));
8506 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8507 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8508 player->msg_posted = TRUE;
8511 /* unrealize the player */
8512 ret = _mmplayer_unrealize(hplayer);
8513 if (ret != MM_ERROR_NONE)
8514 LOGE("failed to unrealize");
8522 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8524 int ret = MM_ERROR_NONE;
8525 mmplayer_t *player = (mmplayer_t *)hplayer;
8526 int idx = 0, total = 0;
8527 gchar *result = NULL, *tmp = NULL;
8530 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8531 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8533 total = *num = g_list_length(player->adaptive_info.var_list);
8535 LOGW("There is no stream variant info.");
8539 result = g_strdup("");
8540 for (idx = 0 ; idx < total ; idx++) {
8541 stream_variant_t *v_data = NULL;
8542 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8545 gchar data[64] = {0};
8546 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8548 tmp = g_strconcat(result, data, NULL);
8552 LOGW("There is no variant data in %d", idx);
8557 *var_info = (char *)result;
8559 LOGD("variant info %d:%s", *num, *var_info);
8565 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8567 int ret = MM_ERROR_NONE;
8568 mmplayer_t *player = (mmplayer_t *)hplayer;
8571 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8573 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8575 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8576 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8577 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8579 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8580 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8581 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8582 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8584 /* FIXME: seek to current position for applying new variant limitation */
8593 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8595 int ret = MM_ERROR_NONE;
8596 mmplayer_t *player = (mmplayer_t *)hplayer;
8599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8600 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8602 *bandwidth = player->adaptive_info.limit.bandwidth;
8603 *width = player->adaptive_info.limit.width;
8604 *height = player->adaptive_info.limit.height;
8606 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8613 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8615 int ret = MM_ERROR_NONE;
8616 mmplayer_t *player = (mmplayer_t *)hplayer;
8619 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8620 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8621 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8623 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8625 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8626 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8627 else /* live case */
8628 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8630 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8637 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8639 #define IDX_FIRST_SW_CODEC 0
8640 mmplayer_t *player = (mmplayer_t *)hplayer;
8641 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8644 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8646 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8647 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8648 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8650 switch (stream_type) {
8651 case MM_PLAYER_STREAM_TYPE_AUDIO:
8652 /* to support audio codec selection, codec info have to be added in ini file as below.
8653 audio codec element hw = xxxx
8654 audio codec element sw = avdec
8655 and in case of audio hw codec is supported and selected,
8656 audio filter elements should be applied depending on the hw capabilities.
8658 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8659 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8660 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8661 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8662 LOGE("There is no audio codec info for codec_type %d", codec_type);
8663 return MM_ERROR_PLAYER_NO_OP;
8666 case MM_PLAYER_STREAM_TYPE_VIDEO:
8667 /* to support video codec selection, codec info have to be added in ini file as below.
8668 video codec element hw = omx
8669 video codec element sw = avdec */
8670 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8671 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8672 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8673 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8674 LOGE("There is no video codec info for codec_type %d", codec_type);
8675 return MM_ERROR_PLAYER_NO_OP;
8679 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8680 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8684 LOGD("update %s codec_type to %d", attr_name, codec_type);
8685 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8688 return MM_ERROR_NONE;
8692 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8694 mmplayer_t *player = (mmplayer_t *)hplayer;
8695 GstElement *rg_vol_element = NULL;
8699 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8701 player->sound.rg_enable = enabled;
8703 /* just hold rgvolume enable value if pipeline is not ready */
8704 if (!player->pipeline || !player->pipeline->audiobin) {
8705 LOGD("pipeline is not ready. holding rgvolume enable value");
8706 return MM_ERROR_NONE;
8709 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8711 if (!rg_vol_element) {
8712 LOGD("rgvolume element is not created");
8713 return MM_ERROR_PLAYER_INTERNAL;
8717 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8719 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8723 return MM_ERROR_NONE;
8727 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8729 mmplayer_t *player = (mmplayer_t *)hplayer;
8730 GstElement *rg_vol_element = NULL;
8731 gboolean enable = FALSE;
8735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8738 /* just hold enable_rg value if pipeline is not ready */
8739 if (!player->pipeline || !player->pipeline->audiobin) {
8740 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8741 *enabled = player->sound.rg_enable;
8742 return MM_ERROR_NONE;
8745 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8747 if (!rg_vol_element) {
8748 LOGD("rgvolume element is not created");
8749 return MM_ERROR_PLAYER_INTERNAL;
8752 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8753 *enabled = (bool)enable;
8757 return MM_ERROR_NONE;
8761 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8763 mmplayer_t *player = (mmplayer_t *)hplayer;
8764 MMHandleType attrs = 0;
8766 int ret = MM_ERROR_NONE;
8770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8772 attrs = MMPLAYER_GET_ATTRS(player);
8773 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8775 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8777 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8778 return MM_ERROR_PLAYER_INTERNAL;
8781 player->video_roi.scale_x = scale_x;
8782 player->video_roi.scale_y = scale_y;
8783 player->video_roi.scale_width = scale_width;
8784 player->video_roi.scale_height = scale_height;
8786 /* check video sinkbin is created */
8787 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8788 return MM_ERROR_NONE;
8790 if (!gst_video_overlay_set_video_roi_area(
8791 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8792 scale_x, scale_y, scale_width, scale_height))
8793 ret = MM_ERROR_PLAYER_INTERNAL;
8795 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8796 scale_x, scale_y, scale_width, scale_height);
8804 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8806 mmplayer_t *player = (mmplayer_t *)hplayer;
8807 int ret = MM_ERROR_NONE;
8811 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8814 *scale_x = player->video_roi.scale_x;
8815 *scale_y = player->video_roi.scale_y;
8816 *scale_width = player->video_roi.scale_width;
8817 *scale_height = player->video_roi.scale_height;
8819 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8820 *scale_x, *scale_y, *scale_width, *scale_height);
8826 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8828 mmplayer_t *player = (mmplayer_t *)hplayer;
8832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8834 player->client_pid = pid;
8836 LOGD("client pid[%d] %p", pid, player);
8840 return MM_ERROR_NONE;
8844 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8846 mmplayer_t *player = (mmplayer_t *)hplayer;
8847 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8848 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8852 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8853 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8856 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8858 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8860 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8861 return MM_ERROR_NONE;
8863 /* in case of audio codec default type is HW */
8865 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8866 if (player->ini.support_audio_effect)
8867 return MM_ERROR_NONE;
8868 elem_id = MMPLAYER_A_FILTER;
8870 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8871 if (player->ini.support_replaygain_control)
8872 return MM_ERROR_NONE;
8873 elem_id = MMPLAYER_A_RGVOL;
8875 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8876 if (player->ini.support_pitch_control)
8877 return MM_ERROR_NONE;
8878 elem_id = MMPLAYER_A_PITCH;
8880 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8881 if (player->ini.support_audio_effect)
8882 return MM_ERROR_NONE;
8884 /* default case handling is not required */
8887 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8888 LOGW("audio control option [%d] is not available", opt);
8891 /* setting pcm exporting option is allowed before READY state */
8892 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8893 return MM_ERROR_PLAYER_INVALID_STATE;
8895 /* check whether the audio filter exist or not after READY state,
8896 because the sw codec could be added during auto-plugging in some cases */
8897 if (!player->pipeline ||
8898 !player->pipeline->audiobin ||
8899 !player->pipeline->audiobin[elem_id].gst) {
8900 LOGW("there is no audio elem [%d]", elem_id);
8905 LOGD("audio control opt %d, available %d", opt, *available);
8909 return MM_ERROR_NONE;
8913 __mmplayer_update_duration_value(mmplayer_t *player)
8915 gboolean ret = FALSE;
8916 gint64 dur_nsec = 0;
8917 LOGD("try to update duration");
8919 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8920 player->duration = dur_nsec;
8921 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8925 if (player->duration < 0) {
8926 LOGW("duration is Non-Initialized !!!");
8927 player->duration = 0;
8930 /* update streaming service type */
8931 player->streaming_type = _mmplayer_get_stream_service_type(player);
8933 /* check duration is OK */
8934 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8935 /* FIXIT : find another way to get duration here. */
8936 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8942 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8944 /* update audio params
8945 NOTE : We need original audio params and it can be only obtained from src pad of audio
8946 decoder. Below code only valid when we are not using 'resampler' just before
8947 'audioconverter'. */
8948 GstCaps *caps_a = NULL;
8950 gint samplerate = 0, channels = 0;
8951 GstStructure *p = NULL;
8952 GstElement *aconv = NULL;
8954 LOGD("try to update audio attrs");
8956 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8958 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8959 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8960 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8961 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8963 LOGE("there is no audio converter");
8967 pad = gst_element_get_static_pad(aconv, "sink");
8970 LOGW("failed to get pad from audio converter");
8974 caps_a = gst_pad_get_current_caps(pad);
8976 LOGW("not ready to get audio caps");
8977 gst_object_unref(pad);
8981 p = gst_caps_get_structure(caps_a, 0);
8983 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8985 gst_structure_get_int(p, "rate", &samplerate);
8986 gst_structure_get_int(p, "channels", &channels);
8988 mm_player_set_attribute((MMHandleType)player, NULL,
8989 "content_audio_samplerate", samplerate,
8990 "content_audio_channels", channels, NULL);
8992 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8994 gst_caps_unref(caps_a);
8995 gst_object_unref(pad);
9001 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9003 LOGD("try to update video attrs");
9005 GstCaps *caps_v = NULL;
9009 GstStructure *p = NULL;
9011 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9012 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9014 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9016 LOGD("no videosink sink pad");
9020 caps_v = gst_pad_get_current_caps(pad);
9021 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9022 if (!caps_v && player->v_stream_caps) {
9023 caps_v = player->v_stream_caps;
9024 gst_caps_ref(caps_v);
9028 LOGD("no negitiated caps from videosink");
9029 gst_object_unref(pad);
9033 p = gst_caps_get_structure(caps_v, 0);
9034 gst_structure_get_int(p, "width", &width);
9035 gst_structure_get_int(p, "height", &height);
9037 mm_player_set_attribute((MMHandleType)player, NULL,
9038 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9040 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9042 SECURE_LOGD("width : %d height : %d", width, height);
9044 gst_caps_unref(caps_v);
9045 gst_object_unref(pad);
9048 mm_player_set_attribute((MMHandleType)player, NULL,
9049 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9050 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9057 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9059 gboolean ret = FALSE;
9060 guint64 data_size = 0;
9064 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9065 if (!player->duration)
9068 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9069 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9070 if (stat(path, &sb) == 0)
9071 data_size = (guint64)sb.st_size;
9073 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9074 data_size = player->http_content_size;
9077 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9080 guint64 bitrate = 0;
9081 guint64 msec_dur = 0;
9083 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9085 bitrate = data_size * 8 * 1000 / msec_dur;
9086 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9087 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9088 mm_player_set_attribute((MMHandleType)player, NULL,
9089 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9092 LOGD("player duration is less than 0");
9096 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9097 if (player->total_bitrate) {
9098 mm_player_set_attribute((MMHandleType)player, NULL,
9099 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9108 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9110 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9111 data->uri_type = uri_type;
9115 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9117 int ret = MM_ERROR_PLAYER_INVALID_URI;
9119 char *buffer = NULL;
9120 char *seperator = strchr(path, ',');
9121 char ext[100] = {0,}, size[100] = {0,};
9124 if ((buffer = strstr(path, "ext="))) {
9125 buffer += strlen("ext=");
9127 if (strlen(buffer)) {
9128 strncpy(ext, buffer, 99);
9130 if ((seperator = strchr(ext, ','))
9131 || (seperator = strchr(ext, ' '))
9132 || (seperator = strchr(ext, '\0'))) {
9133 seperator[0] = '\0';
9138 if ((buffer = strstr(path, "size="))) {
9139 buffer += strlen("size=");
9141 if (strlen(buffer) > 0) {
9142 strncpy(size, buffer, 99);
9144 if ((seperator = strchr(size, ','))
9145 || (seperator = strchr(size, ' '))
9146 || (seperator = strchr(size, '\0'))) {
9147 seperator[0] = '\0';
9150 mem_size = atoi(size);
9155 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9157 if (mem_size && param) {
9158 if (data->input_mem.buf)
9159 free(data->input_mem.buf);
9160 data->input_mem.buf = malloc(mem_size);
9162 if (data->input_mem.buf) {
9163 memcpy(data->input_mem.buf, param, mem_size);
9164 data->input_mem.len = mem_size;
9165 ret = MM_ERROR_NONE;
9167 LOGE("failed to alloc mem %d", mem_size);
9168 ret = MM_ERROR_PLAYER_INTERNAL;
9171 data->input_mem.offset = 0;
9172 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9179 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9181 gchar *location = NULL;
9184 int ret = MM_ERROR_NONE;
9186 if ((path = strstr(uri, "file://"))) {
9187 location = g_filename_from_uri(uri, NULL, &err);
9188 if (!location || (err != NULL)) {
9189 LOGE("Invalid URI '%s' for filesrc: %s", path,
9190 (err != NULL) ? err->message : "unknown error");
9194 MMPLAYER_FREEIF(location);
9196 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9197 return MM_ERROR_PLAYER_INVALID_URI;
9199 LOGD("path from uri: %s", location);
9202 path = (location != NULL) ? (location) : ((char *)uri);
9205 ret = _mmplayer_exist_file_path(path);
9207 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9208 if (ret == MM_ERROR_NONE) {
9209 if (_mmplayer_is_sdp_file(path)) {
9210 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9211 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9212 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9214 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9215 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9217 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9218 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9220 LOGE("invalid uri, could not play..");
9221 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9224 MMPLAYER_FREEIF(location);
9229 static mmplayer_video_decoded_data_info_t *
9230 __mmplayer_create_stream_from_pad(GstPad *pad)
9232 GstCaps *caps = NULL;
9233 GstStructure *structure = NULL;
9234 unsigned int fourcc = 0;
9235 const gchar *string_format = NULL;
9236 mmplayer_video_decoded_data_info_t *stream = NULL;
9238 MMPixelFormatType format;
9241 caps = gst_pad_get_current_caps(pad);
9243 LOGE("Caps is NULL.");
9248 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9250 structure = gst_caps_get_structure(caps, 0);
9251 gst_structure_get_int(structure, "width", &width);
9252 gst_structure_get_int(structure, "height", &height);
9253 string_format = gst_structure_get_string(structure, "format");
9256 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9257 format = _mmplayer_get_pixtype(fourcc);
9258 gst_video_info_from_caps(&info, caps);
9259 gst_caps_unref(caps);
9262 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9263 LOGE("Wrong condition!!");
9267 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9269 LOGE("failed to alloc mem for video data");
9273 stream->width = width;
9274 stream->height = height;
9275 stream->format = format;
9276 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9282 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9284 unsigned int pitch = 0;
9285 unsigned int size = 0;
9287 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9290 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9291 bo = gst_tizen_memory_get_bos(mem, index);
9293 stream->bo[index] = tbm_bo_ref(bo);
9295 LOGE("failed to get bo for index %d", index);
9298 for (index = 0; index < stream->plane_num; index++) {
9299 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9300 stream->stride[index] = pitch;
9302 stream->elevation[index] = size / pitch;
9304 stream->elevation[index] = stream->height;
9309 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9311 if (stream->format == MM_PIXEL_FORMAT_I420) {
9312 int ret = TBM_SURFACE_ERROR_NONE;
9313 tbm_surface_h surface;
9314 tbm_surface_info_s info;
9316 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9318 ret = tbm_surface_get_info(surface, &info);
9319 if (ret != TBM_SURFACE_ERROR_NONE) {
9320 tbm_surface_destroy(surface);
9324 tbm_surface_destroy(surface);
9325 stream->stride[0] = info.planes[0].stride;
9326 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9327 stream->stride[1] = info.planes[1].stride;
9328 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9329 stream->stride[2] = info.planes[2].stride;
9330 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9331 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9332 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9333 stream->stride[0] = stream->width * 4;
9334 stream->elevation[0] = stream->height;
9335 stream->bo_size = stream->stride[0] * stream->height;
9337 LOGE("Not support format %d", stream->format);
9345 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9347 tbm_bo_handle thandle;
9349 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9350 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9351 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9355 unsigned char *src = NULL;
9356 unsigned char *dest = NULL;
9357 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9359 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9361 LOGE("fail to gst_memory_map");
9365 if (!mapinfo.data) {
9366 LOGE("data pointer is wrong");
9370 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9371 if (!stream->bo[0]) {
9372 LOGE("Fail to tbm_bo_alloc!!");
9376 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9378 LOGE("thandle pointer is wrong");
9382 if (stream->format == MM_PIXEL_FORMAT_I420) {
9383 src_stride[0] = GST_ROUND_UP_4(stream->width);
9384 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9385 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9386 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9389 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9390 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9392 for (i = 0; i < 3; i++) {
9393 src = mapinfo.data + src_offset[i];
9394 dest = thandle.ptr + dest_offset[i];
9399 for (j = 0; j < stream->height >> k; j++) {
9400 memcpy(dest, src, stream->width>>k);
9401 src += src_stride[i];
9402 dest += stream->stride[i];
9405 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9406 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9408 LOGE("Not support format %d", stream->format);
9412 tbm_bo_unmap(stream->bo[0]);
9413 gst_memory_unmap(mem, &mapinfo);
9419 tbm_bo_unmap(stream->bo[0]);
9422 gst_memory_unmap(mem, &mapinfo);
9428 __mmplayer_set_pause_state(mmplayer_t *player)
9430 if (player->sent_bos)
9433 /* rtsp case, get content attrs by GstMessage */
9434 if (MMPLAYER_IS_RTSP_STREAMING(player))
9437 /* it's first time to update all content attrs. */
9438 _mmplayer_update_content_attrs(player, ATTR_ALL);
9442 __mmplayer_set_playing_state(mmplayer_t *player)
9444 gchar *audio_codec = NULL;
9446 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9447 /* initialize because auto resume is done well. */
9448 player->resumed_by_rewind = FALSE;
9449 player->playback_rate = 1.0;
9452 if (player->sent_bos)
9455 /* try to get content metadata */
9457 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9458 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9459 * legacy mmfw-player api
9461 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9463 if ((player->cmd == MMPLAYER_COMMAND_START)
9464 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9465 __mmplayer_handle_missed_plugin(player);
9468 /* check audio codec field is set or not
9469 * we can get it from typefinder or codec's caps.
9471 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9473 /* The codec format can't be sent for audio only case like amr, mid etc.
9474 * Because, parser don't make related TAG.
9475 * So, if it's not set yet, fill it with found data.
9478 if (g_strrstr(player->type, "audio/midi"))
9479 audio_codec = "MIDI";
9480 else if (g_strrstr(player->type, "audio/x-amr"))
9481 audio_codec = "AMR";
9482 else if (g_strrstr(player->type, "audio/mpeg")
9483 && !g_strrstr(player->type, "mpegversion=(int)1"))
9484 audio_codec = "AAC";
9486 audio_codec = "unknown";
9488 if (mm_player_set_attribute((MMHandleType)player, NULL,
9489 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9490 LOGE("failed to set attribute");
9492 LOGD("set audio codec type with caps");