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;
1174 gboolean caps_ret = TRUE;
1176 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1177 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1180 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1181 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1183 LOGD("pad-added signal handling");
1185 /* get mimetype from caps */
1186 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1190 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1192 LOGD("detected mimetype : %s", name);
1195 if (strstr(name, "video")) {
1197 gchar *caps_str = NULL;
1199 caps_str = gst_caps_to_string(caps);
1200 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1201 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1202 player->set_mode.video_zc = true;
1204 MMPLAYER_FREEIF(caps_str);
1206 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1209 LOGD("surface type : %d", stype);
1211 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player)) {
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 /* in case of exporting video frame, it requires the 360 video filter.
1217 * it will be handled in _no_more_pads(). */
1218 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1219 __mmplayer_gst_make_fakesink(player, pad, name);
1223 LOGD("video selector is required");
1224 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1225 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1226 } else if (strstr(name, "audio")) {
1227 gint samplerate = 0;
1230 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player) || player->build_audio_offload) {
1231 if (player->build_audio_offload)
1232 player->no_more_pad = TRUE; /* remove state holder */
1233 __mmplayer_gst_create_sinkbin(elem, pad, player);
1237 gst_structure_get_int(str, "rate", &samplerate);
1238 gst_structure_get_int(str, "channels", &channels);
1240 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1241 __mmplayer_gst_make_fakesink(player, pad, name);
1245 LOGD("audio selector is required");
1246 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1247 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1249 } else if (strstr(name, "text")) {
1250 LOGD("text selector is required");
1251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1254 LOGE("invalid caps info");
1258 /* check selector and create it */
1259 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1260 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1265 LOGD("input-selector is already created.");
1269 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1271 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1273 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1274 LOGE("failed to link selector");
1275 gst_object_unref(GST_OBJECT(selector));
1280 LOGD("this track will be activated");
1281 g_object_set(selector, "active-pad", sinkpad, NULL);
1284 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1290 gst_caps_unref(caps);
1293 gst_object_unref(GST_OBJECT(sinkpad));
1301 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1303 GstPad *srcpad = NULL;
1306 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1308 LOGD("type %d", type);
1311 LOGD("there is no %d track", type);
1315 srcpad = gst_element_get_static_pad(selector, "src");
1317 LOGE("failed to get srcpad from selector");
1321 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1323 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1325 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1326 if (player->selector[type].block_id) {
1327 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1328 player->selector[type].block_id = 0;
1332 gst_object_unref(GST_OBJECT(srcpad));
1341 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1343 gint active_index = 0;
1346 MMPLAYER_RETURN_IF_FAIL(player);
1348 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1350 /* change track to active pad */
1351 active_index = player->selector[type].active_pad_index;
1352 if ((active_index != DEFAULT_TRACK) &&
1353 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1354 LOGW("failed to change %d type track to %d", type, active_index);
1355 player->selector[type].active_pad_index = DEFAULT_TRACK;
1359 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1360 mm_player_set_attribute((MMHandleType)player, NULL,
1361 "content_text_track_num", player->selector[type].total_track_num,
1362 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1369 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1372 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1374 if (!audio_selector) {
1375 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1377 /* in case the source is changed, output can be changed. */
1378 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1379 LOGD("remove previous audiobin if it exist");
1381 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1382 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1384 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1385 MMPLAYER_FREEIF(player->pipeline->audiobin);
1388 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1389 _mmplayer_pipeline_complete(NULL, player);
1394 /* apply the audio track information */
1395 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1397 /* create audio sink path */
1398 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1399 LOGE("failed to create audio sink path");
1408 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1411 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1413 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1414 LOGD("text path is not supproted");
1418 /* apply the text track information */
1419 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1421 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1422 player->has_closed_caption = TRUE;
1424 /* create text decode path */
1425 player->no_more_pad = TRUE;
1427 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1428 LOGE("failed to create text sink path");
1437 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1439 gint64 dur_bytes = 0L;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1443 player->pipeline->mainbin && player->streamer, FALSE);
1445 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1446 LOGE("fail to get duration.");
1448 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1449 * use file information was already set on Q2 when it was created. */
1450 _mm_player_streaming_set_queue2(player->streamer,
1451 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1452 TRUE, /* use_buffering */
1453 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1454 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1461 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1463 mmplayer_t *player = NULL;
1464 GstElement *video_selector = NULL;
1465 GstElement *audio_selector = NULL;
1466 GstElement *text_selector = NULL;
1469 player = (mmplayer_t *)data;
1471 LOGD("no-more-pad signal handling");
1473 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1474 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1475 LOGW("player is shutting down");
1479 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1480 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1481 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1482 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1483 LOGE("failed to set queue2 buffering");
1488 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1489 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1490 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1492 if (!video_selector && !audio_selector && !text_selector) {
1493 LOGW("there is no selector");
1494 player->no_more_pad = TRUE;
1498 /* create video path followed by video-select */
1499 if (video_selector && !audio_selector && !text_selector)
1500 player->no_more_pad = TRUE;
1502 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1505 /* create audio path followed by audio-select */
1506 if (audio_selector && !text_selector)
1507 player->no_more_pad = TRUE;
1509 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1512 /* create text path followed by text-select */
1513 __mmplayer_create_text_sink_path(player, text_selector);
1516 _mmplayer_set_reconfigure_state(player, FALSE);
1521 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1523 gboolean ret = FALSE;
1524 GstElement *pipeline = NULL;
1525 GstPad *sinkpad = NULL;
1528 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1529 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1531 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1533 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1535 LOGE("failed to get pad from sinkbin");
1541 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1542 LOGE("failed to link sinkbin for reusing");
1543 goto EXIT; /* exit either pass or fail */
1547 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1548 LOGE("failed to set state(READY) to sinkbin");
1553 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1554 LOGE("failed to add sinkbin to pipeline");
1559 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1560 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1565 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1566 LOGE("failed to set state(PAUSED) to sinkbin");
1575 gst_object_unref(GST_OBJECT(sinkpad));
1583 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1585 mmplayer_t *player = NULL;
1586 GstCaps *caps = NULL;
1587 gchar *caps_str = NULL;
1588 GstStructure *str = NULL;
1589 const gchar *name = NULL;
1590 GstElement *sinkbin = NULL;
1591 gboolean reusing = FALSE;
1592 gboolean caps_ret = TRUE;
1593 gchar *sink_pad_name = "sink";
1596 player = (mmplayer_t *)data;
1599 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1600 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1602 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1606 caps_str = gst_caps_to_string(caps);
1608 LOGD("detected mimetype : %s", name);
1610 if (strstr(name, "audio")) {
1611 if (player->pipeline->audiobin == NULL) {
1612 const gchar *audio_format = gst_structure_get_string(str, "format");
1614 LOGD("original audio format %s", audio_format);
1615 mm_player_set_attribute((MMHandleType)player, NULL,
1616 "content_audio_format", audio_format, strlen(audio_format), NULL);
1619 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1620 LOGE("failed to create audiobin. continuing without audio");
1624 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1625 LOGD("creating audiobin success");
1628 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1629 LOGD("reusing audiobin");
1630 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1632 } else if (strstr(name, "video")) {
1633 /* 1. zero copy is updated at _decode_pad_added()
1634 * 2. NULL surface type is handled in _decode_pad_added() */
1635 LOGD("zero copy %d", player->set_mode.video_zc);
1636 if (player->pipeline->videobin == NULL) {
1637 int surface_type = 0;
1638 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1639 LOGD("display_surface_type (%d)", surface_type);
1641 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1642 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1643 LOGE("failed to acquire video overlay resource");
1647 player->interrupted_by_resource = FALSE;
1649 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1650 LOGE("failed to create videobin. continuing without video");
1654 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1655 LOGD("creating videosink bin success");
1658 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1659 LOGD("re-using videobin");
1660 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1662 } else if (strstr(name, "text")) {
1663 if (player->pipeline->textbin == NULL) {
1664 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1665 LOGE("failed to create text sink bin. continuing without text");
1669 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1670 player->textsink_linked = 1;
1671 LOGD("creating textsink bin success");
1673 if (!player->textsink_linked) {
1674 LOGD("re-using textbin");
1676 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1677 player->textsink_linked = 1;
1679 /* linked textbin exist which means that the external subtitle path exist already */
1680 LOGW("ignoring internal subtutle since external subtitle is available");
1683 sink_pad_name = "text_sink";
1685 LOGW("unknown mime type %s, ignoring it", name);
1689 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1692 LOGD("[handle: %p] success to create and link sink bin", player);
1694 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1695 * streaming task. if the task blocked, then buffer will not flow to the next element
1696 *(autoplugging element). so this is special hack for streaming. please try to remove it
1698 /* dec stream count. we can remove fakesink if it's zero */
1699 if (player->num_dynamic_pad)
1700 player->num_dynamic_pad--;
1702 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1704 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1705 _mmplayer_pipeline_complete(NULL, player);
1709 MMPLAYER_FREEIF(caps_str);
1712 gst_caps_unref(caps);
1718 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1720 int required_angle = 0; /* Angle required for straight view */
1721 int rotation_angle = 0;
1723 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1724 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1726 /* Counter clockwise */
1727 switch (orientation) {
1732 required_angle = 270;
1735 required_angle = 180;
1738 required_angle = 90;
1742 rotation_angle = display_angle + required_angle;
1743 if (rotation_angle >= 360)
1744 rotation_angle -= 360;
1746 /* chech if supported or not */
1747 if (rotation_angle % 90) {
1748 LOGD("not supported rotation angle = %d", rotation_angle);
1752 switch (rotation_angle) {
1754 *value = MM_DISPLAY_ROTATION_NONE;
1757 *value = MM_DISPLAY_ROTATION_90;
1760 *value = MM_DISPLAY_ROTATION_180;
1763 *value = MM_DISPLAY_ROTATION_270;
1767 LOGD("setting rotation property value : %d", *value);
1773 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1775 int display_rotation = 0;
1776 gchar *org_orient = NULL;
1777 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1780 LOGE("cannot get content attribute");
1781 return MM_ERROR_PLAYER_INTERNAL;
1784 if (display_angle) {
1785 /* update user roation */
1786 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1788 /* Counter clockwise */
1789 switch (display_rotation) {
1790 case MM_DISPLAY_ROTATION_NONE:
1793 case MM_DISPLAY_ROTATION_90:
1794 *display_angle = 90;
1796 case MM_DISPLAY_ROTATION_180:
1797 *display_angle = 180;
1799 case MM_DISPLAY_ROTATION_270:
1800 *display_angle = 270;
1803 LOGW("wrong angle type : %d", display_rotation);
1806 LOGD("check user angle: %d", *display_angle);
1810 /* Counter clockwise */
1811 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1814 if (!strcmp(org_orient, "rotate-90"))
1816 else if (!strcmp(org_orient, "rotate-180"))
1818 else if (!strcmp(org_orient, "rotate-270"))
1821 LOGD("original rotation is %s", org_orient);
1823 LOGD("content_video_orientation get fail");
1826 LOGD("check orientation: %d", *orientation);
1829 return MM_ERROR_NONE;
1832 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1834 int rotation_value = 0;
1835 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1836 int display_angle = 0;
1839 /* check video sinkbin is created */
1840 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1843 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1845 /* get rotation value to set */
1846 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1847 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1848 LOGD("set video param : rotate %d", rotation_value);
1851 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1853 MMHandleType attrs = 0;
1857 /* check video sinkbin is created */
1858 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1861 attrs = MMPLAYER_GET_ATTRS(player);
1862 MMPLAYER_RETURN_IF_FAIL(attrs);
1864 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1865 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1866 LOGD("set video param : visible %d", visible);
1869 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1871 MMHandleType attrs = 0;
1872 int display_method = 0;
1875 /* check video sinkbin is created */
1876 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1879 attrs = MMPLAYER_GET_ATTRS(player);
1880 MMPLAYER_RETURN_IF_FAIL(attrs);
1882 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1883 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1884 LOGD("set video param : method %d", display_method);
1887 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1889 MMHandleType attrs = 0;
1893 /* check video sinkbin is created */
1894 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1897 attrs = MMPLAYER_GET_ATTRS(player);
1898 MMPLAYER_RETURN_IF_FAIL(attrs);
1900 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1901 MMPLAYER_RETURN_IF_FAIL(handle);
1903 gst_video_overlay_set_video_roi_area(
1904 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1905 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1906 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1907 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1910 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1912 MMHandleType attrs = 0;
1917 int win_roi_width = 0;
1918 int win_roi_height = 0;
1921 /* check video sinkbin is created */
1922 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1925 attrs = MMPLAYER_GET_ATTRS(player);
1926 MMPLAYER_RETURN_IF_FAIL(attrs);
1928 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1929 MMPLAYER_RETURN_IF_FAIL(handle);
1931 /* It should be set after setting window */
1932 mm_attrs_multiple_get(attrs, NULL,
1933 "display_win_roi_x", &win_roi_x,
1934 "display_win_roi_y", &win_roi_y,
1935 "display_win_roi_width", &win_roi_width,
1936 "display_win_roi_height", &win_roi_height, NULL);
1938 /* After setting window handle, set display roi area */
1939 gst_video_overlay_set_display_roi_area(
1940 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1941 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1942 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1943 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1946 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1948 MMHandleType attrs = 0;
1951 /* check video sinkbin is created */
1952 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1955 attrs = MMPLAYER_GET_ATTRS(player);
1956 MMPLAYER_RETURN_IF_FAIL(attrs);
1958 /* common case if using overlay surface */
1959 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1960 MMPLAYER_RETURN_IF_FAIL(handle);
1962 /* default is using wl_surface_id */
1963 LOGD("set video param : wl_surface_id %d", handle);
1964 gst_video_overlay_set_wl_window_wl_surface_id(
1965 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1970 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1972 gboolean update_all_param = FALSE;
1976 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1977 LOGW("videosink is not ready yet");
1978 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1981 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1982 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1983 return MM_ERROR_PLAYER_INTERNAL;
1986 LOGD("param_name : %s", param_name);
1987 if (!g_strcmp0(param_name, "update_all_param"))
1988 update_all_param = TRUE;
1990 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1991 __mmplayer_video_param_set_display_overlay(player);
1992 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1993 __mmplayer_video_param_set_display_method(player);
1994 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1995 __mmplayer_video_param_set_display_visible(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
1997 __mmplayer_video_param_set_display_rotation(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
1999 __mmplayer_video_param_set_roi_area(player);
2000 if (update_all_param)
2001 __mmplayer_video_param_set_video_roi_area(player);
2005 return MM_ERROR_NONE;
2009 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2011 gboolean disable_overlay = FALSE;
2012 mmplayer_t *player = (mmplayer_t *)hplayer;
2015 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2016 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2017 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2018 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2020 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2021 LOGW("Display control is not supported");
2022 return MM_ERROR_PLAYER_INTERNAL;
2025 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2027 if (audio_only == (bool)disable_overlay) {
2028 LOGE("It's the same with current setting: (%d)", audio_only);
2029 return MM_ERROR_NONE;
2033 LOGE("disable overlay");
2034 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2036 /* release overlay resource */
2037 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2038 LOGE("failed to release overlay resource");
2042 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2043 LOGE("failed to acquire video overlay resource");
2046 player->interrupted_by_resource = FALSE;
2048 LOGD("enable overlay");
2049 __mmplayer_video_param_set_display_overlay(player);
2050 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2055 return MM_ERROR_NONE;
2059 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2061 mmplayer_t *player = (mmplayer_t *)hplayer;
2062 gboolean disable_overlay = FALSE;
2066 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2067 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2068 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2069 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2070 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2072 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2073 LOGW("Display control is not supported");
2074 return MM_ERROR_PLAYER_INTERNAL;
2077 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2079 *paudio_only = (bool)disable_overlay;
2081 LOGD("audio_only : %d", *paudio_only);
2085 return MM_ERROR_NONE;
2089 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2091 GList *bucket = element_bucket;
2092 mmplayer_gst_element_t *element = NULL;
2093 mmplayer_gst_element_t *prv_element = NULL;
2094 GstElement *tee_element = NULL;
2095 gint successful_link_count = 0;
2099 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2101 prv_element = (mmplayer_gst_element_t *)bucket->data;
2102 bucket = bucket->next;
2104 for (; bucket; bucket = bucket->next) {
2105 element = (mmplayer_gst_element_t *)bucket->data;
2107 if (element && element->gst) {
2108 if (prv_element && prv_element->gst) {
2109 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2111 prv_element->gst = tee_element;
2113 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2114 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2115 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2119 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2120 LOGD("linking [%s] to [%s] success",
2121 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2122 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 successful_link_count++;
2124 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2125 LOGD("keep audio-tee element for next audio pipeline branch");
2126 tee_element = prv_element->gst;
2129 LOGD("linking [%s] to [%s] failed",
2130 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2131 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2137 prv_element = element;
2142 return successful_link_count;
2146 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2148 GList *bucket = element_bucket;
2149 mmplayer_gst_element_t *element = NULL;
2150 int successful_add_count = 0;
2154 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2155 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2157 for (; bucket; bucket = bucket->next) {
2158 element = (mmplayer_gst_element_t *)bucket->data;
2160 if (element && element->gst) {
2161 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2162 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2163 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2164 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2167 successful_add_count++;
2173 return successful_add_count;
2177 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2179 mmplayer_t *player = (mmplayer_t *)data;
2180 GstCaps *caps = NULL;
2181 GstStructure *str = NULL;
2183 gboolean caps_ret = TRUE;
2187 MMPLAYER_RETURN_IF_FAIL(pad);
2188 MMPLAYER_RETURN_IF_FAIL(unused);
2189 MMPLAYER_RETURN_IF_FAIL(data);
2191 caps = gst_pad_get_current_caps(pad);
2195 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2199 LOGD("name = %s", name);
2201 if (strstr(name, "audio")) {
2202 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2204 if (player->audio_stream_changed_cb) {
2205 LOGE("call the audio stream changed cb");
2206 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2208 } else if (strstr(name, "video")) {
2209 if ((name = gst_structure_get_string(str, "format")))
2210 player->set_mode.video_zc = name[0] == 'S';
2212 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2213 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2215 LOGW("invalid caps info");
2220 gst_caps_unref(caps);
2228 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2233 MMPLAYER_RETURN_IF_FAIL(player);
2235 if (player->audio_stream_buff_list) {
2236 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2237 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2240 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2241 __mmplayer_audio_stream_send_data(player, tmp);
2243 MMPLAYER_FREEIF(tmp->pcm_data);
2244 MMPLAYER_FREEIF(tmp);
2247 g_list_free(player->audio_stream_buff_list);
2248 player->audio_stream_buff_list = NULL;
2255 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2257 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2260 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2262 audio_stream.bitrate = a_buffer->bitrate;
2263 audio_stream.channel = a_buffer->channel;
2264 audio_stream.channel_mask = a_buffer->channel_mask;
2265 audio_stream.data_size = a_buffer->data_size;
2266 audio_stream.data = a_buffer->pcm_data;
2267 audio_stream.pcm_format = a_buffer->pcm_format;
2269 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2271 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2277 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2279 mmplayer_t *player = (mmplayer_t *)data;
2280 const gchar *pcm_format = NULL;
2283 guint64 channel_mask = 0;
2284 void *a_data = NULL;
2286 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2287 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2291 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2293 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2294 a_data = mapinfo.data;
2295 a_size = mapinfo.size;
2297 GstCaps *caps = gst_pad_get_current_caps(pad);
2298 GstStructure *structure = gst_caps_get_structure(caps, 0);
2300 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2302 pcm_format = gst_structure_get_string(structure, "format");
2303 gst_structure_get_int(structure, "rate", &rate);
2304 gst_structure_get_int(structure, "channels", &channel);
2305 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2306 gst_caps_unref(GST_CAPS(caps));
2308 /* In case of the sync is false, use buffer list. *
2309 * The num of buffer list depends on the num of audio channels */
2310 if (player->audio_stream_buff_list) {
2311 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2312 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2314 if (channel_mask == tmp->channel_mask) {
2316 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2318 if (tmp->data_size + a_size < tmp->buff_size) {
2319 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2320 tmp->data_size += a_size;
2322 /* send data to client */
2323 __mmplayer_audio_stream_send_data(player, tmp);
2325 if (a_size > tmp->buff_size) {
2326 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2327 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2328 if (tmp->pcm_data == NULL) {
2329 LOGE("failed to realloc data.");
2332 tmp->buff_size = a_size;
2334 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2335 memcpy(tmp->pcm_data, a_data, a_size);
2336 tmp->data_size = a_size;
2341 LOGE("data is empty in list.");
2347 /* create new audio stream data for newly found audio channel */
2348 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2349 if (a_buffer == NULL) {
2350 LOGE("failed to alloc data.");
2353 a_buffer->bitrate = rate;
2354 a_buffer->channel = channel;
2355 a_buffer->channel_mask = channel_mask;
2356 a_buffer->data_size = a_size;
2357 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2359 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2360 /* If sync is FALSE, use buffer list to reduce the IPC. */
2361 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2362 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2363 if (a_buffer->pcm_data == NULL) {
2364 LOGE("failed to alloc data.");
2365 MMPLAYER_FREEIF(a_buffer);
2368 memcpy(a_buffer->pcm_data, a_data, a_size);
2370 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2372 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2374 /* If sync is TRUE, send data directly. */
2375 a_buffer->pcm_data = a_data;
2376 __mmplayer_audio_stream_send_data(player, a_buffer);
2377 MMPLAYER_FREEIF(a_buffer);
2381 gst_buffer_unmap(buffer, &mapinfo);
2386 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2388 mmplayer_t *player = (mmplayer_t *)data;
2389 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2390 GstPad *sinkpad = NULL;
2391 GstElement *queue = NULL, *sink = NULL;
2394 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2396 queue = gst_element_factory_make("queue", NULL);
2397 if (queue == NULL) {
2398 LOGD("fail make queue");
2402 sink = gst_element_factory_make("fakesink", NULL);
2404 LOGD("fail make fakesink");
2408 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2410 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2411 LOGW("failed to link queue & sink");
2415 sinkpad = gst_element_get_static_pad(queue, "sink");
2417 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2418 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2422 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2424 gst_object_unref(sinkpad);
2425 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2426 g_object_set(sink, "sync", TRUE, NULL);
2427 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2429 /* keep the first sink reference only */
2430 if (!audiobin[MMPLAYER_A_SINK].gst) {
2431 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2432 audiobin[MMPLAYER_A_SINK].gst = sink;
2436 _mmplayer_add_signal_connection(player,
2438 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2440 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2443 __mmplayer_add_sink(player, sink);
2445 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2446 LOGE("failed to sync state");
2450 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2451 LOGE("failed to sync state");
2459 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2461 gst_object_unref(GST_OBJECT(queue));
2465 gst_object_unref(GST_OBJECT(sink));
2469 gst_object_unref(GST_OBJECT(sinkpad));
2477 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2479 mmplayer_t *player = (mmplayer_t *)data;
2482 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2484 player->no_more_pad = TRUE;
2485 _mmplayer_pipeline_complete(NULL, player);
2492 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2494 #define MAX_PROPS_LEN 128
2495 mmplayer_gst_element_t *audiobin = NULL;
2496 gint latency_mode = 0;
2497 gchar *stream_type = NULL;
2498 gchar *latency = NULL;
2500 gchar stream_props[MAX_PROPS_LEN] = {0,};
2501 GstStructure *props = NULL;
2504 * It should be set after player creation through attribute.
2505 * But, it can not be changed during playing.
2508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2510 audiobin = player->pipeline->audiobin;
2512 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2513 if (player->sound.mute) {
2514 LOGD("mute enabled");
2515 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2518 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2519 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2522 snprintf(stream_props, sizeof(stream_props) - 1,
2523 "props,application.process.id.origin=%d", player->client_pid);
2525 snprintf(stream_props, sizeof(stream_props) - 1,
2526 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2527 stream_type, stream_id, player->client_pid);
2529 props = gst_structure_from_string(stream_props, NULL);
2530 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2531 LOGI("props result[%s].", stream_props);
2532 gst_structure_free(props);
2534 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2536 switch (latency_mode) {
2537 case AUDIO_LATENCY_MODE_LOW:
2538 latency = g_strdup("low");
2540 case AUDIO_LATENCY_MODE_MID:
2541 latency = g_strdup("mid");
2543 case AUDIO_LATENCY_MODE_HIGH:
2544 latency = g_strdup("high");
2547 latency = g_strdup("mid");
2551 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2553 LOGD("audiosink property - latency=%s", latency);
2555 MMPLAYER_FREEIF(latency);
2561 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2563 mmplayer_gst_element_t *audiobin = NULL;
2566 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2568 audiobin = player->pipeline->audiobin;
2570 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2571 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2572 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2574 if (player->video360_yaw_radians <= M_PI &&
2575 player->video360_yaw_radians >= -M_PI &&
2576 player->video360_pitch_radians <= M_PI_2 &&
2577 player->video360_pitch_radians >= -M_PI_2) {
2578 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2579 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2580 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2581 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2582 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2583 "source-orientation-y", player->video360_metadata.init_view_heading,
2584 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2591 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2593 mmplayer_gst_element_t *audiobin = NULL;
2594 GstPad *sink_pad = NULL;
2595 GstCaps *acaps = NULL;
2597 int pitch_control = 0;
2598 double pitch_value = 1.0;
2601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2602 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2604 audiobin = player->pipeline->audiobin;
2606 LOGD("make element for normal audio playback");
2608 /* audio bin structure for playback. {} means optional.
2609 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2611 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2612 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2615 /* for pitch control */
2616 mm_attrs_multiple_get(player->attrs, NULL,
2617 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2618 MM_PLAYER_PITCH_VALUE, &pitch_value,
2621 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2622 if (pitch_control && (player->videodec_linked == 0)) {
2623 GstElementFactory *factory;
2625 factory = gst_element_factory_find("pitch");
2627 gst_object_unref(factory);
2630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2636 LOGW("there is no pitch element");
2641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2643 /* replaygain volume */
2644 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2645 if (player->sound.rg_enable)
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2648 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2653 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2654 /* currently, only openalsink uses volume element */
2655 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2658 if (player->sound.mute) {
2659 LOGD("mute enabled");
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2664 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2666 /* audio effect element. if audio effect is enabled */
2667 if ((strcmp(player->ini.audioeffect_element, ""))
2669 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2672 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2674 if ((!player->bypass_audio_effect)
2675 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2676 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2677 if (!_mmplayer_audio_effect_custom_apply(player))
2678 LOGI("apply audio effect(custom) setting success");
2682 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2683 && (player->set_mode.rich_audio)) {
2684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2688 /* create audio sink */
2689 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2690 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2691 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2693 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2694 if (player->is_360_feature_enabled &&
2695 player->is_content_spherical &&
2697 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2698 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2699 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2701 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2703 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2706 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2708 gst_caps_unref(acaps);
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2712 player->is_openal_plugin_used = TRUE;
2714 if (player->is_360_feature_enabled && player->is_content_spherical)
2715 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2719 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2720 (player->videodec_linked && player->ini.use_system_clock)) {
2721 LOGD("system clock will be used.");
2722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2725 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2726 __mmplayer_gst_set_pulsesink_property(player);
2727 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2728 __mmplayer_gst_set_openalsink_property(player);
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2734 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2735 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2736 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2737 gst_object_unref(GST_OBJECT(sink_pad));
2739 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2742 return MM_ERROR_NONE;
2744 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2746 return MM_ERROR_PLAYER_INTERNAL;
2750 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2752 mmplayer_gst_element_t *audiobin = NULL;
2753 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2755 gchar *dst_format = NULL;
2757 int dst_samplerate = 0;
2758 int dst_channels = 0;
2759 GstCaps *caps = NULL;
2760 char *caps_str = NULL;
2763 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2764 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2766 audiobin = player->pipeline->audiobin;
2768 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2770 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2772 [case 1] extract interleave audio pcm without playback
2773 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2774 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2776 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2778 [case 2] deinterleave for each channel without playback
2779 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2780 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2782 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2783 - fakesink (sync or not)
2786 [case 3] [case 1(sync only)] + playback
2787 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2789 * src - ... - tee - queue1 - playback path
2790 - queue2 - [case1 pipeline with sync]
2792 [case 4] [case 2(sync only)] + playback
2793 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2795 * src - ... - tee - queue1 - playback path
2796 - queue2 - [case2 pipeline with sync]
2800 /* 1. create tee and playback path
2801 'tee' should be added at first to copy the decoded stream
2803 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2804 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2805 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2807 /* tee - path 1 : for playback path */
2808 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2809 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2811 /* tee - path 2 : for extract path */
2812 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2813 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2816 /* if there is tee, 'tee - path 2' is linked here */
2818 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2823 /* 2. decide the extract pcm format */
2824 mm_attrs_multiple_get(player->attrs, NULL,
2825 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2826 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2827 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2830 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2831 dst_format, dst_len, dst_samplerate, dst_channels);
2833 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2834 mm_attrs_multiple_get(player->attrs, NULL,
2835 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2836 "content_audio_samplerate", &dst_samplerate,
2837 "content_audio_channels", &dst_channels,
2840 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2841 dst_format, dst_len, dst_samplerate, dst_channels);
2843 /* If there is no enough information, set it to platform default value. */
2844 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2845 LOGD("set platform default format");
2846 dst_format = DEFAULT_PCM_OUT_FORMAT;
2848 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2849 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2852 /* 3. create capsfilter */
2853 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2854 caps = gst_caps_new_simple("audio/x-raw",
2855 "format", G_TYPE_STRING, dst_format,
2856 "rate", G_TYPE_INT, dst_samplerate,
2857 "channels", G_TYPE_INT, dst_channels,
2860 caps_str = gst_caps_to_string(caps);
2861 LOGD("new caps : %s", caps_str);
2863 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2866 gst_caps_unref(caps);
2867 MMPLAYER_FREEIF(caps_str);
2869 /* 4-1. create deinterleave to extract pcm for each channel */
2870 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2871 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2872 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2874 /* audiosink will be added after getting signal for each channel */
2875 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2876 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2877 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2878 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2879 player->no_more_pad = FALSE;
2881 /* 4-2. create fakesink to extract interlevaed pcm */
2882 LOGD("add audio fakesink for interleaved audio");
2883 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2884 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2885 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2886 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2888 _mmplayer_add_signal_connection(player,
2889 G_OBJECT(audiobin[extract_sink_id].gst),
2890 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2892 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2895 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2899 return MM_ERROR_NONE;
2901 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2903 return MM_ERROR_PLAYER_INTERNAL;
2907 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2909 int ret = MM_ERROR_NONE;
2910 mmplayer_gst_element_t *audiobin = NULL;
2911 GList *element_bucket = NULL;
2914 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2915 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2917 audiobin = player->pipeline->audiobin;
2919 if (player->build_audio_offload) { /* skip all the audio filters */
2920 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2922 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2923 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2924 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2926 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2930 /* FIXME: need to mention the supportable condition at API reference */
2931 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2932 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2934 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2936 if (ret != MM_ERROR_NONE)
2939 LOGD("success to make audio bin element");
2940 *bucket = element_bucket;
2943 return MM_ERROR_NONE;
2946 LOGE("failed to make audio bin element");
2947 g_list_free(element_bucket);
2951 return MM_ERROR_PLAYER_INTERNAL;
2955 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2957 mmplayer_gst_element_t *first_element = NULL;
2958 mmplayer_gst_element_t *audiobin = NULL;
2960 GstPad *ghostpad = NULL;
2961 GList *element_bucket = NULL;
2965 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2968 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2970 LOGE("failed to allocate memory for audiobin");
2971 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2975 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2976 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2977 if (!audiobin[MMPLAYER_A_BIN].gst) {
2978 LOGE("failed to create audiobin");
2983 player->pipeline->audiobin = audiobin;
2985 /* create audio filters and audiosink */
2986 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2989 /* adding created elements to bin */
2990 LOGD("adding created elements to bin");
2991 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2994 /* linking elements in the bucket by added order. */
2995 LOGD("Linking elements in the bucket by added order.");
2996 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
2999 /* get first element's sinkpad for creating ghostpad */
3000 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3001 if (!first_element) {
3002 LOGE("failed to get first elem");
3006 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3008 LOGE("failed to get pad from first element of audiobin");
3012 ghostpad = gst_ghost_pad_new("sink", pad);
3014 LOGE("failed to create ghostpad");
3018 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3019 LOGE("failed to add ghostpad to audiobin");
3023 gst_object_unref(pad);
3025 g_list_free(element_bucket);
3028 return MM_ERROR_NONE;
3031 LOGD("ERROR : releasing audiobin");
3034 gst_object_unref(GST_OBJECT(pad));
3037 gst_object_unref(GST_OBJECT(ghostpad));
3040 g_list_free(element_bucket);
3042 /* release element which are not added to bin */
3043 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3044 /* NOTE : skip bin */
3045 if (audiobin[i].gst) {
3046 GstObject *parent = NULL;
3047 parent = gst_element_get_parent(audiobin[i].gst);
3050 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3051 audiobin[i].gst = NULL;
3053 gst_object_unref(GST_OBJECT(parent));
3057 /* release audiobin with it's childs */
3058 if (audiobin[MMPLAYER_A_BIN].gst)
3059 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3061 MMPLAYER_FREEIF(audiobin);
3063 player->pipeline->audiobin = NULL;
3065 return MM_ERROR_PLAYER_INTERNAL;
3069 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3071 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3075 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3077 int ret = MM_ERROR_NONE;
3079 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3080 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3082 MMPLAYER_VIDEO_BO_LOCK(player);
3084 if (player->video_bo_list) {
3085 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3086 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3087 if (tmp && tmp->bo == bo) {
3089 LOGD("release bo %p", bo);
3090 tbm_bo_unref(tmp->bo);
3091 MMPLAYER_VIDEO_BO_UNLOCK(player);
3092 MMPLAYER_VIDEO_BO_SIGNAL(player);
3097 /* hw codec is running or the list was reset for DRC. */
3098 LOGW("there is no bo list.");
3100 MMPLAYER_VIDEO_BO_UNLOCK(player);
3102 LOGW("failed to find bo %p", bo);
3107 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3112 MMPLAYER_RETURN_IF_FAIL(player);
3114 MMPLAYER_VIDEO_BO_LOCK(player);
3115 if (player->video_bo_list) {
3116 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3117 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3118 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3121 tbm_bo_unref(tmp->bo);
3125 g_list_free(player->video_bo_list);
3126 player->video_bo_list = NULL;
3128 player->video_bo_size = 0;
3129 MMPLAYER_VIDEO_BO_UNLOCK(player);
3136 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3139 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3140 gboolean ret = TRUE;
3142 /* check DRC, if it is, destroy the prev bo list to create again */
3143 if (player->video_bo_size != size) {
3144 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3145 __mmplayer_video_stream_destroy_bo_list(player);
3146 player->video_bo_size = size;
3149 MMPLAYER_VIDEO_BO_LOCK(player);
3151 if ((!player->video_bo_list) ||
3152 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3154 /* create bo list */
3156 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3158 if (player->video_bo_list) {
3159 /* if bo list did not created all, try it again. */
3160 idx = g_list_length(player->video_bo_list);
3161 LOGD("bo list exist(len: %d)", idx);
3164 for (; idx < player->ini.num_of_video_bo; idx++) {
3165 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3167 LOGE("Fail to alloc bo_info.");
3170 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3172 LOGE("Fail to tbm_bo_alloc.");
3173 MMPLAYER_FREEIF(bo_info);
3176 bo_info->used = FALSE;
3177 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3180 /* update video num buffers */
3181 LOGD("video_num_buffers : %d", idx);
3182 mm_player_set_attribute((MMHandleType)player, NULL,
3183 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3184 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3188 MMPLAYER_VIDEO_BO_UNLOCK(player);
3194 /* get bo from list*/
3195 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3196 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3197 if (tmp && (tmp->used == FALSE)) {
3198 LOGD("found bo %p to use", tmp->bo);
3200 MMPLAYER_VIDEO_BO_UNLOCK(player);
3201 return tbm_bo_ref(tmp->bo);
3205 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3206 MMPLAYER_VIDEO_BO_UNLOCK(player);
3210 if (player->ini.video_bo_timeout <= 0) {
3211 MMPLAYER_VIDEO_BO_WAIT(player);
3213 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3214 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3221 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3223 mmplayer_t *player = (mmplayer_t *)data;
3225 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3227 /* send prerolled pkt */
3228 player->video_stream_prerolled = false;
3230 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3232 /* not to send prerolled pkt again */
3233 player->video_stream_prerolled = true;
3237 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3239 mmplayer_t *player = (mmplayer_t *)data;
3240 mmplayer_video_decoded_data_info_t *stream = NULL;
3241 GstMemory *mem = NULL;
3244 MMPLAYER_RETURN_IF_FAIL(player);
3245 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3247 if (player->video_stream_prerolled) {
3248 player->video_stream_prerolled = false;
3249 LOGD("skip the prerolled pkt not to send it again");
3253 /* clear stream data structure */
3254 stream = __mmplayer_create_stream_from_pad(pad);
3256 LOGE("failed to alloc stream");
3260 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3262 /* set size and timestamp */
3263 mem = gst_buffer_peek_memory(buffer, 0);
3264 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3265 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3267 /* check zero-copy */
3268 if (player->set_mode.video_zc &&
3269 player->set_mode.video_export &&
3270 gst_is_tizen_memory(mem)) {
3271 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3272 stream->internal_buffer = gst_buffer_ref(buffer);
3273 } else { /* sw codec */
3274 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3277 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3281 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3282 LOGE("failed to send video decoded data.");
3289 LOGE("release video stream resource.");
3290 if (gst_is_tizen_memory(mem)) {
3292 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3294 tbm_bo_unref(stream->bo[i]);
3297 /* unref gst buffer */
3298 if (stream->internal_buffer)
3299 gst_buffer_unref(stream->internal_buffer);
3302 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3304 MMPLAYER_FREEIF(stream);
3309 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3311 mmplayer_gst_element_t *videobin = NULL;
3314 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3316 videobin = player->pipeline->videobin;
3318 /* Set spatial media metadata and/or user settings to the element.
3320 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3321 "projection-type", player->video360_metadata.projection_type, NULL);
3323 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3324 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3326 if (player->video360_metadata.full_pano_width_pixels &&
3327 player->video360_metadata.full_pano_height_pixels &&
3328 player->video360_metadata.cropped_area_image_width &&
3329 player->video360_metadata.cropped_area_image_height) {
3330 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3331 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3332 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3333 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3334 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3335 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3336 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3340 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3342 "horizontal-fov", player->video360_horizontal_fov,
3343 "vertical-fov", player->video360_vertical_fov, NULL);
3346 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3347 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3348 "zoom", 1.0f / player->video360_zoom, NULL);
3351 if (player->video360_yaw_radians <= M_PI &&
3352 player->video360_yaw_radians >= -M_PI &&
3353 player->video360_pitch_radians <= M_PI_2 &&
3354 player->video360_pitch_radians >= -M_PI_2) {
3355 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3356 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3357 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3358 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3359 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3360 "pose-yaw", player->video360_metadata.init_view_heading,
3361 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3364 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3365 "passthrough", !player->is_video360_enabled, NULL);
3372 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3374 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3375 GList *element_bucket = NULL;
3378 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3380 /* create video360 filter */
3381 if (player->is_360_feature_enabled && player->is_content_spherical) {
3382 LOGD("create video360 element");
3383 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3384 __mmplayer_gst_set_video360_property(player);
3388 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3389 LOGD("skip creating the videoconv and rotator");
3390 return MM_ERROR_NONE;
3393 /* in case of sw codec & overlay surface type, except 360 playback.
3394 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3395 LOGD("create video converter: %s", video_csc);
3396 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3399 *bucket = element_bucket;
3401 return MM_ERROR_NONE;
3403 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3404 g_list_free(element_bucket);
3408 return MM_ERROR_PLAYER_INTERNAL;
3412 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3414 gchar *factory_name = NULL;
3416 switch (surface_type) {
3417 case MM_DISPLAY_SURFACE_OVERLAY:
3418 if (strlen(player->ini.videosink_element_overlay) > 0)
3419 factory_name = player->ini.videosink_element_overlay;
3421 case MM_DISPLAY_SURFACE_REMOTE:
3422 case MM_DISPLAY_SURFACE_NULL:
3423 if (strlen(player->ini.videosink_element_fake) > 0)
3424 factory_name = player->ini.videosink_element_fake;
3427 LOGE("unidentified surface type");
3431 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3432 return factory_name;
3436 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3438 gchar *factory_name = NULL;
3439 mmplayer_gst_element_t *videobin = NULL;
3444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3446 videobin = player->pipeline->videobin;
3447 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3449 attrs = MMPLAYER_GET_ATTRS(player);
3451 LOGE("cannot get content attribute");
3452 return MM_ERROR_PLAYER_INTERNAL;
3455 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3456 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3457 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3458 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3459 "use-tbm", use_tbm, NULL);
3462 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3463 return MM_ERROR_PLAYER_INTERNAL;
3465 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3468 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3469 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3472 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3474 LOGD("disable last-sample");
3475 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3478 if (player->set_mode.video_export) {
3480 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3481 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3482 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3484 _mmplayer_add_signal_connection(player,
3485 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3486 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3488 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3491 _mmplayer_add_signal_connection(player,
3492 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3493 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3495 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3499 if (videobin[MMPLAYER_V_SINK].gst) {
3500 GstPad *sink_pad = NULL;
3501 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3503 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3504 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3505 gst_object_unref(GST_OBJECT(sink_pad));
3507 LOGE("failed to get sink pad from videosink");
3511 return MM_ERROR_NONE;
3516 * - video overlay surface(arm/x86) : tizenwlsink
3519 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3522 GList *element_bucket = NULL;
3523 mmplayer_gst_element_t *first_element = NULL;
3524 mmplayer_gst_element_t *videobin = NULL;
3525 gchar *videosink_factory_name = NULL;
3528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3531 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3533 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3535 player->pipeline->videobin = videobin;
3538 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3539 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3540 if (!videobin[MMPLAYER_V_BIN].gst) {
3541 LOGE("failed to create videobin");
3545 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3548 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3549 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3551 /* additional setting for sink plug-in */
3552 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3553 LOGE("failed to set video property");
3557 /* store it as it's sink element */
3558 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3560 /* adding created elements to bin */
3561 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3562 LOGE("failed to add elements");
3566 /* Linking elements in the bucket by added order */
3567 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3568 LOGE("failed to link elements");
3572 /* get first element's sinkpad for creating ghostpad */
3573 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3574 if (!first_element) {
3575 LOGE("failed to get first element from bucket");
3579 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3581 LOGE("failed to get pad from first element");
3585 /* create ghostpad */
3586 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3587 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3588 LOGE("failed to add ghostpad to videobin");
3591 gst_object_unref(pad);
3593 /* done. free allocated variables */
3594 g_list_free(element_bucket);
3598 return MM_ERROR_NONE;
3601 LOGE("ERROR : releasing videobin");
3602 g_list_free(element_bucket);
3605 gst_object_unref(GST_OBJECT(pad));
3607 /* release videobin with it's childs */
3608 if (videobin[MMPLAYER_V_BIN].gst)
3609 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3611 MMPLAYER_FREEIF(videobin);
3612 player->pipeline->videobin = NULL;
3614 return MM_ERROR_PLAYER_INTERNAL;
3618 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3620 GList *element_bucket = NULL;
3621 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3623 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3624 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3625 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3626 "signal-handoffs", FALSE,
3629 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3630 _mmplayer_add_signal_connection(player,
3631 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3632 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3634 G_CALLBACK(__mmplayer_update_subtitle),
3637 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3638 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3640 if (!player->play_subtitle) {
3641 LOGD("add textbin sink as sink element of whole pipeline.");
3642 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3645 /* adding created elements to bin */
3646 LOGD("adding created elements to bin");
3647 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3648 LOGE("failed to add elements");
3652 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3653 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3654 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3656 /* linking elements in the bucket by added order. */
3657 LOGD("Linking elements in the bucket by added order.");
3658 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3659 LOGE("failed to link elements");
3663 /* done. free allocated variables */
3664 g_list_free(element_bucket);
3666 if (textbin[MMPLAYER_T_QUEUE].gst) {
3668 GstPad *ghostpad = NULL;
3670 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3672 LOGE("failed to get sink pad of text queue");
3676 ghostpad = gst_ghost_pad_new("text_sink", pad);
3677 gst_object_unref(pad);
3680 LOGE("failed to create ghostpad of textbin");
3684 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3685 LOGE("failed to add ghostpad to textbin");
3686 gst_object_unref(ghostpad);
3691 return MM_ERROR_NONE;
3694 g_list_free(element_bucket);
3696 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3697 LOGE("remove textbin sink from sink list");
3698 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3701 /* release element at __mmplayer_gst_create_text_sink_bin */
3702 return MM_ERROR_PLAYER_INTERNAL;
3706 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3708 mmplayer_gst_element_t *textbin = NULL;
3709 GList *element_bucket = NULL;
3710 int surface_type = 0;
3715 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3718 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3720 LOGE("failed to allocate memory for textbin");
3721 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3725 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3726 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3727 if (!textbin[MMPLAYER_T_BIN].gst) {
3728 LOGE("failed to create textbin");
3733 player->pipeline->textbin = textbin;
3736 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3737 LOGD("surface type for subtitle : %d", surface_type);
3738 switch (surface_type) {
3739 case MM_DISPLAY_SURFACE_OVERLAY:
3740 case MM_DISPLAY_SURFACE_NULL:
3741 case MM_DISPLAY_SURFACE_REMOTE:
3742 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3743 LOGE("failed to make plain text elements");
3754 return MM_ERROR_NONE;
3758 LOGD("ERROR : releasing textbin");
3760 g_list_free(element_bucket);
3762 /* release signal */
3763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3765 /* release element which are not added to bin */
3766 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3767 /* NOTE : skip bin */
3768 if (textbin[i].gst) {
3769 GstObject *parent = NULL;
3770 parent = gst_element_get_parent(textbin[i].gst);
3773 gst_object_unref(GST_OBJECT(textbin[i].gst));
3774 textbin[i].gst = NULL;
3776 gst_object_unref(GST_OBJECT(parent));
3781 /* release textbin with it's childs */
3782 if (textbin[MMPLAYER_T_BIN].gst)
3783 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3785 MMPLAYER_FREEIF(textbin);
3786 player->pipeline->textbin = NULL;
3789 return MM_ERROR_PLAYER_INTERNAL;
3793 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3795 mmplayer_gst_element_t *mainbin = NULL;
3796 mmplayer_gst_element_t *textbin = NULL;
3797 MMHandleType attrs = 0;
3798 GstElement *subsrc = NULL;
3799 GstElement *subparse = NULL;
3800 gchar *subtitle_uri = NULL;
3801 const gchar *charset = NULL;
3807 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3809 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3811 mainbin = player->pipeline->mainbin;
3813 attrs = MMPLAYER_GET_ATTRS(player);
3815 LOGE("cannot get content attribute");
3816 return MM_ERROR_PLAYER_INTERNAL;
3819 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3820 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3821 LOGE("subtitle uri is not proper filepath.");
3822 return MM_ERROR_PLAYER_INVALID_URI;
3825 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3826 LOGE("failed to get storage info of subtitle path");
3827 return MM_ERROR_PLAYER_INVALID_URI;
3830 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3832 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3833 player->subtitle_language_list = NULL;
3834 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3836 /* create the subtitle source */
3837 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3839 LOGE("failed to create filesrc element");
3842 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3844 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3845 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3847 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3848 LOGW("failed to add queue");
3849 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3850 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3851 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3856 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3858 LOGE("failed to create subparse element");
3862 charset = _mmplayer_get_charset(subtitle_uri);
3864 LOGD("detected charset is %s", charset);
3865 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3868 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3869 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3871 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3872 LOGW("failed to add subparse");
3873 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3874 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3875 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3879 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3880 LOGW("failed to link subsrc and subparse");
3884 player->play_subtitle = TRUE;
3885 player->adjust_subtitle_pos = 0;
3887 LOGD("play subtitle using subtitle file");
3889 if (player->pipeline->textbin == NULL) {
3890 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3891 LOGE("failed to create text sink bin. continuing without text");
3895 textbin = player->pipeline->textbin;
3897 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3898 LOGW("failed to add textbin");
3900 /* release signal */
3901 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3903 /* release textbin with it's childs */
3904 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3905 MMPLAYER_FREEIF(player->pipeline->textbin);
3906 player->pipeline->textbin = textbin = NULL;
3910 LOGD("link text input selector and textbin ghost pad");
3912 player->textsink_linked = 1;
3913 player->external_text_idx = 0;
3914 LOGI("textsink is linked");
3916 textbin = player->pipeline->textbin;
3917 LOGD("text bin has been created. reuse it.");
3918 player->external_text_idx = 1;
3921 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3922 LOGW("failed to link subparse and textbin");
3926 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3928 LOGE("failed to get sink pad from textsink to probe data");
3932 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3933 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3935 gst_object_unref(pad);
3938 /* create dot. for debugging */
3939 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3942 return MM_ERROR_NONE;
3945 /* release text pipeline resource */
3946 player->textsink_linked = 0;
3948 /* release signal */
3949 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3951 if (player->pipeline->textbin) {
3952 LOGE("remove textbin");
3954 /* release textbin with it's childs */
3955 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3956 MMPLAYER_FREEIF(player->pipeline->textbin);
3957 player->pipeline->textbin = NULL;
3961 /* release subtitle elem */
3962 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3963 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3965 return MM_ERROR_PLAYER_INTERNAL;
3969 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3971 mmplayer_t *player = (mmplayer_t *)data;
3972 MMMessageParamType msg = {0, };
3973 GstClockTime duration = 0;
3974 gpointer text = NULL;
3975 guint text_size = 0;
3976 gboolean ret = TRUE;
3977 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3981 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3982 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3984 if (player->is_subtitle_force_drop) {
3985 LOGW("subtitle is dropped forcedly.");
3989 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3990 text = mapinfo.data;
3991 text_size = mapinfo.size;
3993 if (player->set_mode.subtitle_off) {
3994 LOGD("subtitle is OFF.");
3998 if (!text || (text_size == 0)) {
3999 LOGD("There is no subtitle to be displayed.");
4003 msg.data = (void *)text;
4005 duration = GST_BUFFER_DURATION(buffer);
4007 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4008 if (player->duration > GST_BUFFER_PTS(buffer))
4009 duration = player->duration - GST_BUFFER_PTS(buffer);
4012 LOGI("subtitle duration is invalid, subtitle duration change "
4013 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4015 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4017 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4019 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4020 gst_buffer_unmap(buffer, &mapinfo);
4027 static GstPadProbeReturn
4028 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4030 mmplayer_t *player = (mmplayer_t *)u_data;
4031 GstClockTime cur_timestamp = 0;
4032 gint64 adjusted_timestamp = 0;
4033 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4035 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4037 if (player->set_mode.subtitle_off) {
4038 LOGD("subtitle is OFF.");
4042 if (player->adjust_subtitle_pos == 0) {
4043 LOGD("nothing to do");
4047 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4048 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4050 if (adjusted_timestamp < 0) {
4051 LOGD("adjusted_timestamp under zero");
4056 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4057 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4058 GST_TIME_ARGS(cur_timestamp),
4059 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4061 return GST_PAD_PROBE_OK;
4065 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4069 /* check player and subtitlebin are created */
4070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4071 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4073 if (position == 0) {
4074 LOGD("nothing to do");
4076 return MM_ERROR_NONE;
4079 /* check current postion */
4080 player->adjust_subtitle_pos = position;
4082 LOGD("save adjust_subtitle_pos in player");
4086 return MM_ERROR_NONE;
4090 * This function is to create audio or video pipeline for playing.
4092 * @param player [in] handle of player
4094 * @return This function returns zero on success.
4099 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4101 int ret = MM_ERROR_NONE;
4102 mmplayer_gst_element_t *mainbin = NULL;
4103 MMHandleType attrs = 0;
4106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4108 /* get profile attribute */
4109 attrs = MMPLAYER_GET_ATTRS(player);
4111 LOGE("failed to get content attribute");
4115 /* create pipeline handles */
4116 if (player->pipeline) {
4117 LOGE("pipeline should be released before create new one");
4121 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4123 /* create mainbin */
4124 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4125 if (mainbin == NULL)
4128 /* create pipeline */
4129 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4130 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4131 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4132 LOGE("failed to create pipeline");
4137 player->pipeline->mainbin = mainbin;
4139 /* create the source and decoder elements */
4140 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4141 ret = _mmplayer_gst_build_es_pipeline(player);
4143 ret = _mmplayer_gst_build_pipeline(player);
4145 if (ret != MM_ERROR_NONE) {
4146 LOGE("failed to create some elements");
4150 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4151 if (__mmplayer_check_subtitle(player)
4152 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4153 LOGE("failed to create text pipeline");
4156 ret = _mmplayer_gst_add_bus_watch(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to add bus watch");
4163 return MM_ERROR_NONE;
4166 __mmplayer_gst_destroy_pipeline(player);
4167 return MM_ERROR_PLAYER_INTERNAL;
4171 __mmplayer_reset_gapless_state(mmplayer_t *player)
4174 MMPLAYER_RETURN_IF_FAIL(player
4176 && player->pipeline->audiobin
4177 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4179 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4186 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4189 int ret = MM_ERROR_NONE;
4193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4195 /* cleanup stuffs */
4196 MMPLAYER_FREEIF(player->type);
4197 player->no_more_pad = FALSE;
4198 player->num_dynamic_pad = 0;
4199 player->demux_pad_index = 0;
4201 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4202 player->subtitle_language_list = NULL;
4203 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4205 MMPLAYER_RECONFIGURE_LOCK(player);
4206 __mmplayer_reset_gapless_state(player);
4207 MMPLAYER_RECONFIGURE_UNLOCK(player);
4209 if (player->streamer) {
4210 _mm_player_streaming_initialize(player->streamer, FALSE);
4211 _mm_player_streaming_destroy(player->streamer);
4212 player->streamer = NULL;
4215 /* cleanup unlinked mime type */
4216 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4217 MMPLAYER_FREEIF(player->unlinked_video_mime);
4218 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4220 /* cleanup running stuffs */
4221 _mmplayer_cancel_eos_timer(player);
4223 /* cleanup gst stuffs */
4224 if (player->pipeline) {
4225 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4226 GstTagList *tag_list = player->pipeline->tag_list;
4228 /* first we need to disconnect all signal hander */
4229 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4232 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4233 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4234 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4235 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4236 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4237 gst_object_unref(bus);
4239 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4240 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4241 if (ret != MM_ERROR_NONE) {
4242 LOGE("fail to change state to NULL");
4243 return MM_ERROR_PLAYER_INTERNAL;
4246 LOGW("succeeded in changing state to NULL");
4248 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4251 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4252 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4254 /* free avsysaudiosink
4255 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4256 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4258 MMPLAYER_FREEIF(audiobin);
4259 MMPLAYER_FREEIF(videobin);
4260 MMPLAYER_FREEIF(textbin);
4261 MMPLAYER_FREEIF(mainbin);
4265 gst_tag_list_unref(tag_list);
4267 MMPLAYER_FREEIF(player->pipeline);
4269 MMPLAYER_FREEIF(player->album_art);
4271 if (player->v_stream_caps) {
4272 gst_caps_unref(player->v_stream_caps);
4273 player->v_stream_caps = NULL;
4276 if (player->a_stream_caps) {
4277 gst_caps_unref(player->a_stream_caps);
4278 player->a_stream_caps = NULL;
4281 if (player->s_stream_caps) {
4282 gst_caps_unref(player->s_stream_caps);
4283 player->s_stream_caps = NULL;
4285 _mmplayer_track_destroy(player);
4287 if (player->sink_elements)
4288 g_list_free(player->sink_elements);
4289 player->sink_elements = NULL;
4291 if (player->bufmgr) {
4292 tbm_bufmgr_deinit(player->bufmgr);
4293 player->bufmgr = NULL;
4296 LOGW("finished destroy pipeline");
4304 __mmplayer_gst_realize(mmplayer_t *player)
4307 int ret = MM_ERROR_NONE;
4311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4313 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4315 ret = __mmplayer_gst_create_pipeline(player);
4317 LOGE("failed to create pipeline");
4321 /* set pipeline state to READY */
4322 /* NOTE : state change to READY must be performed sync. */
4323 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4324 ret = _mmplayer_gst_set_state(player,
4325 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4327 if (ret != MM_ERROR_NONE) {
4328 /* return error if failed to set state */
4329 LOGE("failed to set READY state");
4333 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4335 /* create dot before error-return. for debugging */
4336 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4344 __mmplayer_gst_unrealize(mmplayer_t *player)
4346 int ret = MM_ERROR_NONE;
4350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4352 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4353 MMPLAYER_PRINT_STATE(player);
4355 /* release miscellaneous information */
4356 __mmplayer_release_misc(player);
4358 /* destroy pipeline */
4359 ret = __mmplayer_gst_destroy_pipeline(player);
4360 if (ret != MM_ERROR_NONE) {
4361 LOGE("failed to destory pipeline");
4365 /* release miscellaneous information.
4366 these info needs to be released after pipeline is destroyed. */
4367 __mmplayer_release_misc_post(player);
4369 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4377 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4382 LOGW("set_message_callback is called with invalid player handle");
4383 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4386 player->msg_cb = callback;
4387 player->msg_cb_param = user_param;
4389 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4393 return MM_ERROR_NONE;
4397 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4399 int ret = MM_ERROR_NONE;
4404 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4405 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4406 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4408 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4410 if (strstr(uri, "es_buff://")) {
4411 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4412 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4413 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4414 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4416 tmp = g_ascii_strdown(uri, strlen(uri));
4417 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4418 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4420 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4422 } else if (strstr(uri, "mms://")) {
4423 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4424 } else if ((path = strstr(uri, "mem://"))) {
4425 ret = __mmplayer_set_mem_uri(data, path, param);
4427 ret = __mmplayer_set_file_uri(data, uri);
4430 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4431 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4432 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4433 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4435 /* dump parse result */
4436 SECURE_LOGW("incoming uri : %s", uri);
4437 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4438 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4446 __mmplayer_can_do_interrupt(mmplayer_t *player)
4448 if (!player || !player->pipeline || !player->attrs) {
4449 LOGW("not initialized");
4453 if (player->audio_decoded_cb) {
4454 LOGW("not support in pcm extraction mode");
4458 /* check if seeking */
4459 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4460 MMMessageParamType msg_param;
4461 memset(&msg_param, 0, sizeof(MMMessageParamType));
4462 msg_param.code = MM_ERROR_PLAYER_SEEK;
4463 player->seek_state = MMPLAYER_SEEK_NONE;
4464 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4468 /* check other thread */
4469 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4470 LOGW("locked already, cmd state : %d", player->cmd);
4472 /* check application command */
4473 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4474 LOGW("playing.. should wait cmd lock then, will be interrupted");
4476 /* lock will be released at mrp_resource_release_cb() */
4477 MMPLAYER_CMD_LOCK(player);
4480 LOGW("nothing to do");
4483 LOGW("can interrupt immediately");
4487 FAILED: /* with CMD UNLOCKED */
4490 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4495 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4498 mmplayer_t *player = NULL;
4499 MMMessageParamType msg = {0, };
4501 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4506 LOGE("user_data is null");
4509 player = (mmplayer_t *)user_data;
4511 if (!__mmplayer_can_do_interrupt(player)) {
4512 LOGW("no need to interrupt, so leave");
4513 /* FIXME: there is no way to avoid releasing resource. */
4517 player->interrupted_by_resource = TRUE;
4519 /* get last play position */
4520 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4521 msg.union_type = MM_MSG_UNION_TIME;
4522 msg.time.elapsed = pos;
4523 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4525 LOGW("failed to get play position.");
4528 LOGD("video resource conflict so, resource will be freed by unrealizing");
4529 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4530 LOGE("failed to unrealize");
4532 /* lock is called in __mmplayer_can_do_interrupt() */
4533 MMPLAYER_CMD_UNLOCK(player);
4535 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4536 player->hw_resource[res_idx] = NULL;
4540 return TRUE; /* release all the resources */
4544 __mmplayer_initialize_video_roi(mmplayer_t *player)
4546 player->video_roi.scale_x = 0.0;
4547 player->video_roi.scale_y = 0.0;
4548 player->video_roi.scale_width = 1.0;
4549 player->video_roi.scale_height = 1.0;
4553 _mmplayer_create_player(MMHandleType handle)
4555 int ret = MM_ERROR_PLAYER_INTERNAL;
4556 bool enabled = false;
4558 mmplayer_t *player = MM_PLAYER_CAST(handle);
4562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4564 /* initialize player state */
4565 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4566 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4567 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4568 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4570 /* check current state */
4571 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4573 /* construct attributes */
4574 player->attrs = _mmplayer_construct_attribute(handle);
4576 if (!player->attrs) {
4577 LOGE("Failed to construct attributes");
4581 /* initialize gstreamer with configured parameter */
4582 if (!__mmplayer_init_gstreamer(player)) {
4583 LOGE("Initializing gstreamer failed");
4584 _mmplayer_deconstruct_attribute(handle);
4588 /* create lock. note that g_tread_init() has already called in gst_init() */
4589 g_mutex_init(&player->fsink_lock);
4591 /* create update tag lock */
4592 g_mutex_init(&player->update_tag_lock);
4594 /* create gapless play mutex */
4595 g_mutex_init(&player->gapless_play_thread_mutex);
4597 /* create gapless play cond */
4598 g_cond_init(&player->gapless_play_thread_cond);
4600 /* create gapless play thread */
4601 player->gapless_play_thread =
4602 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4603 if (!player->gapless_play_thread) {
4604 LOGE("failed to create gapless play thread");
4605 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4606 g_mutex_clear(&player->gapless_play_thread_mutex);
4607 g_cond_clear(&player->gapless_play_thread_cond);
4611 player->bus_msg_q = g_queue_new();
4612 if (!player->bus_msg_q) {
4613 LOGE("failed to create queue for bus_msg");
4614 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4618 ret = _mmplayer_initialize_video_capture(player);
4619 if (ret != MM_ERROR_NONE) {
4620 LOGE("failed to initialize video capture");
4624 /* initialize resource manager */
4625 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4626 __resource_release_cb, player, &player->resource_manager)
4627 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4628 LOGE("failed to initialize resource manager");
4629 ret = MM_ERROR_PLAYER_INTERNAL;
4633 /* create video bo lock and cond */
4634 g_mutex_init(&player->video_bo_mutex);
4635 g_cond_init(&player->video_bo_cond);
4637 /* create subtitle info lock and cond */
4638 g_mutex_init(&player->subtitle_info_mutex);
4639 g_cond_init(&player->subtitle_info_cond);
4641 player->streaming_type = STREAMING_SERVICE_NONE;
4643 /* give default value of audio effect setting */
4644 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4645 player->sound.rg_enable = false;
4646 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4648 player->play_subtitle = FALSE;
4649 player->has_closed_caption = FALSE;
4650 player->pending_resume = FALSE;
4651 if (player->ini.dump_element_keyword[0][0] == '\0')
4652 player->ini.set_dump_element_flag = FALSE;
4654 player->ini.set_dump_element_flag = TRUE;
4656 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4657 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4658 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4660 /* Set video360 settings to their defaults for just-created player.
4663 player->is_360_feature_enabled = FALSE;
4664 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4665 LOGI("spherical feature info: %d", enabled);
4667 player->is_360_feature_enabled = TRUE;
4669 LOGE("failed to get spherical feature info");
4672 player->is_content_spherical = FALSE;
4673 player->is_video360_enabled = TRUE;
4674 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4675 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4676 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4677 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4678 player->video360_zoom = 1.0f;
4679 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4680 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4682 __mmplayer_initialize_video_roi(player);
4684 /* set player state to null */
4685 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4686 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4690 return MM_ERROR_NONE;
4694 g_mutex_clear(&player->fsink_lock);
4695 /* free update tag lock */
4696 g_mutex_clear(&player->update_tag_lock);
4697 g_queue_free(player->bus_msg_q);
4698 player->bus_msg_q = NULL;
4699 /* free gapless play thread */
4700 if (player->gapless_play_thread) {
4701 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4702 player->gapless_play_thread_exit = TRUE;
4703 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4704 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4706 g_thread_join(player->gapless_play_thread);
4707 player->gapless_play_thread = NULL;
4709 g_mutex_clear(&player->gapless_play_thread_mutex);
4710 g_cond_clear(&player->gapless_play_thread_cond);
4713 /* release attributes */
4714 _mmplayer_deconstruct_attribute(handle);
4722 __mmplayer_init_gstreamer(mmplayer_t *player)
4724 static gboolean initialized = FALSE;
4725 static const int max_argc = 50;
4727 gchar **argv = NULL;
4728 gchar **argv2 = NULL;
4734 LOGD("gstreamer already initialized.");
4739 argc = malloc(sizeof(int));
4740 argv = malloc(sizeof(gchar *) * max_argc);
4741 argv2 = malloc(sizeof(gchar *) * max_argc);
4743 if (!argc || !argv || !argv2)
4746 memset(argv, 0, sizeof(gchar *) * max_argc);
4747 memset(argv2, 0, sizeof(gchar *) * max_argc);
4751 argv[0] = g_strdup("mmplayer");
4754 for (i = 0; i < 5; i++) {
4755 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4756 if (strlen(player->ini.gst_param[i]) > 0) {
4757 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4762 /* we would not do fork for scanning plugins */
4763 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4766 /* check disable registry scan */
4767 if (player->ini.skip_rescan) {
4768 argv[*argc] = g_strdup("--gst-disable-registry-update");
4772 /* check disable segtrap */
4773 if (player->ini.disable_segtrap) {
4774 argv[*argc] = g_strdup("--gst-disable-segtrap");
4778 LOGD("initializing gstreamer with following parameter");
4779 LOGD("argc : %d", *argc);
4782 for (i = 0; i < arg_count; i++) {
4784 LOGD("argv[%d] : %s", i, argv2[i]);
4787 /* initializing gstreamer */
4788 if (!gst_init_check(argc, &argv, &err)) {
4789 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4796 for (i = 0; i < arg_count; i++) {
4798 LOGD("release - argv[%d] : %s", i, argv2[i]);
4800 MMPLAYER_FREEIF(argv2[i]);
4803 MMPLAYER_FREEIF(argv);
4804 MMPLAYER_FREEIF(argv2);
4805 MMPLAYER_FREEIF(argc);
4815 for (i = 0; i < arg_count; i++) {
4816 LOGD("free[%d] : %s", i, argv2[i]);
4817 MMPLAYER_FREEIF(argv2[i]);
4820 MMPLAYER_FREEIF(argv);
4821 MMPLAYER_FREEIF(argv2);
4822 MMPLAYER_FREEIF(argc);
4828 __mmplayer_check_async_state_transition(mmplayer_t *player)
4830 GstState element_state = GST_STATE_VOID_PENDING;
4831 GstState element_pending_state = GST_STATE_VOID_PENDING;
4832 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4833 GstElement *element = NULL;
4834 gboolean async = FALSE;
4836 /* check player handle */
4837 MMPLAYER_RETURN_IF_FAIL(player &&
4839 player->pipeline->mainbin &&
4840 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4843 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4845 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4846 LOGD("don't need to check the pipeline state");
4850 MMPLAYER_PRINT_STATE(player);
4852 /* wait for state transition */
4853 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4854 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4856 if (ret == GST_STATE_CHANGE_FAILURE) {
4857 LOGE(" [%s] state : %s pending : %s",
4858 GST_ELEMENT_NAME(element),
4859 gst_element_state_get_name(element_state),
4860 gst_element_state_get_name(element_pending_state));
4862 /* dump state of all element */
4863 _mmplayer_dump_pipeline_state(player);
4868 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4873 _mmplayer_destroy(MMHandleType handle)
4875 mmplayer_t *player = MM_PLAYER_CAST(handle);
4879 /* check player handle */
4880 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4882 /* destroy can called at anytime */
4883 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4885 /* check async state transition */
4886 __mmplayer_check_async_state_transition(player);
4888 /* release gapless play thread */
4889 if (player->gapless_play_thread) {
4890 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4891 player->gapless_play_thread_exit = TRUE;
4892 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4893 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4895 LOGD("waitting for gapless play thread exit");
4896 g_thread_join(player->gapless_play_thread);
4897 g_mutex_clear(&player->gapless_play_thread_mutex);
4898 g_cond_clear(&player->gapless_play_thread_cond);
4899 LOGD("gapless play thread released");
4902 _mmplayer_release_video_capture(player);
4904 /* de-initialize resource manager */
4905 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4906 player->resource_manager))
4907 LOGE("failed to deinitialize resource manager");
4909 /* release miscellaneous information */
4910 __mmplayer_release_misc(player);
4912 /* release pipeline */
4913 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4914 LOGE("failed to destory pipeline");
4915 return MM_ERROR_PLAYER_INTERNAL;
4918 g_queue_free(player->bus_msg_q);
4920 /* release subtitle info lock and cond */
4921 g_mutex_clear(&player->subtitle_info_mutex);
4922 g_cond_clear(&player->subtitle_info_cond);
4924 __mmplayer_release_dump_list(player->dump_list);
4926 /* release miscellaneous information.
4927 these info needs to be released after pipeline is destroyed. */
4928 __mmplayer_release_misc_post(player);
4930 /* release attributes */
4931 _mmplayer_deconstruct_attribute(handle);
4933 if (player->uri_info.uri_list) {
4934 GList *uri_list = player->uri_info.uri_list;
4935 for (; uri_list; uri_list = g_list_next(uri_list)) {
4936 gchar *uri = uri_list->data;
4937 MMPLAYER_FREEIF(uri);
4939 g_list_free(player->uri_info.uri_list);
4940 player->uri_info.uri_list = NULL;
4944 g_mutex_clear(&player->fsink_lock);
4947 g_mutex_clear(&player->update_tag_lock);
4949 /* release video bo lock and cond */
4950 g_mutex_clear(&player->video_bo_mutex);
4951 g_cond_clear(&player->video_bo_cond);
4955 return MM_ERROR_NONE;
4959 _mmplayer_realize(MMHandleType hplayer)
4961 mmplayer_t *player = (mmplayer_t *)hplayer;
4962 int ret = MM_ERROR_NONE;
4965 MMHandleType attrs = 0;
4966 int video_codec_type = 0;
4967 int audio_codec_type = 0;
4968 int default_codec_type = 0;
4971 /* check player handle */
4972 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4974 /* check current state */
4975 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4977 attrs = MMPLAYER_GET_ATTRS(player);
4979 LOGE("fail to get attributes.");
4980 return MM_ERROR_PLAYER_INTERNAL;
4982 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4983 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4985 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4986 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4988 if (ret != MM_ERROR_NONE) {
4989 LOGE("failed to parse profile");
4994 if (uri && (strstr(uri, "es_buff://"))) {
4995 if (strstr(uri, "es_buff://push_mode"))
4996 player->es_player_push_mode = TRUE;
4998 player->es_player_push_mode = FALSE;
5001 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5002 LOGW("mms protocol is not supported format.");
5003 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5006 if (MMPLAYER_IS_STREAMING(player))
5007 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5009 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5011 player->smooth_streaming = FALSE;
5012 player->videodec_linked = 0;
5013 player->audiodec_linked = 0;
5014 player->textsink_linked = 0;
5015 player->is_external_subtitle_present = FALSE;
5016 player->is_external_subtitle_added_now = FALSE;
5017 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5018 player->video360_metadata.is_spherical = -1;
5019 player->is_openal_plugin_used = FALSE;
5020 player->demux_pad_index = 0;
5021 player->subtitle_language_list = NULL;
5022 player->is_subtitle_force_drop = FALSE;
5024 _mmplayer_track_initialize(player);
5025 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5027 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5028 gint prebuffer_ms = 0, rebuffer_ms = 0;
5030 player->streamer = _mm_player_streaming_create();
5031 _mm_player_streaming_initialize(player->streamer, TRUE);
5033 mm_attrs_multiple_get(player->attrs, NULL,
5034 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5035 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5037 if (prebuffer_ms > 0) {
5038 prebuffer_ms = MAX(prebuffer_ms, 1000);
5039 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5042 if (rebuffer_ms > 0) {
5043 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5044 rebuffer_ms = MAX(rebuffer_ms, 1000);
5045 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5048 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5049 player->streamer->buffering_req.rebuffer_time);
5052 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5053 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5054 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5056 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5058 if (audio_codec_type != default_codec_type) {
5059 LOGD("audio dec sorting is required");
5060 player->need_audio_dec_sorting = TRUE;
5063 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5064 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5065 LOGD("video dec sorting is required");
5066 player->need_video_dec_sorting = TRUE;
5069 /* realize pipeline */
5070 ret = __mmplayer_gst_realize(player);
5071 if (ret != MM_ERROR_NONE)
5072 LOGE("fail to realize the player.");
5074 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5082 _mmplayer_unrealize(MMHandleType hplayer)
5084 mmplayer_t *player = (mmplayer_t *)hplayer;
5085 int ret = MM_ERROR_NONE;
5089 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5091 MMPLAYER_CMD_UNLOCK(player);
5092 /* destroy the gst bus msg thread which is created during realize.
5093 this funct have to be called before getting cmd lock. */
5094 _mmplayer_bus_msg_thread_destroy(player);
5095 MMPLAYER_CMD_LOCK(player);
5097 /* check current state */
5098 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5100 /* check async state transition */
5101 __mmplayer_check_async_state_transition(player);
5103 /* unrealize pipeline */
5104 ret = __mmplayer_gst_unrealize(player);
5106 if (!player->interrupted_by_resource) {
5107 int rm_ret = MM_ERROR_NONE;
5108 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5110 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5111 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5112 if (rm_ret != MM_ERROR_NONE)
5113 LOGE("failed to release [%d] resources", res_idx);
5122 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5124 mmplayer_t *player = (mmplayer_t *)hplayer;
5126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5128 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5132 _mmplayer_get_state(MMHandleType hplayer, int *state)
5134 mmplayer_t *player = (mmplayer_t *)hplayer;
5136 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5138 *state = MMPLAYER_CURRENT_STATE(player);
5140 return MM_ERROR_NONE;
5144 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5146 GstElement *vol_element = NULL;
5147 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5150 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5151 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5153 /* check pipeline handle */
5154 if (!player->pipeline || !player->pipeline->audiobin) {
5155 LOGD("'%s' will be applied when audiobin is created", prop_name);
5157 /* NOTE : stored value will be used in create_audiobin
5158 * returning MM_ERROR_NONE here makes application to able to
5159 * set audio volume or mute at anytime.
5161 return MM_ERROR_NONE;
5164 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5165 volume_elem_id = MMPLAYER_A_SINK;
5167 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5169 LOGE("failed to get vol element %d", volume_elem_id);
5170 return MM_ERROR_PLAYER_INTERNAL;
5173 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5175 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5176 LOGE("there is no '%s' property", prop_name);
5177 return MM_ERROR_PLAYER_INTERNAL;
5180 if (!strcmp(prop_name, "volume")) {
5181 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5182 } else if (!strcmp(prop_name, "mute")) {
5183 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5185 LOGE("invalid property %s", prop_name);
5186 return MM_ERROR_PLAYER_INTERNAL;
5189 return MM_ERROR_NONE;
5193 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5195 int ret = MM_ERROR_NONE;
5196 mmplayer_t *player = (mmplayer_t *)hplayer;
5199 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5201 LOGD("volume = %f", volume);
5203 /* invalid factor range or not */
5204 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5205 LOGE("Invalid volume value");
5206 return MM_ERROR_INVALID_ARGUMENT;
5209 player->sound.volume = volume;
5211 ret = __mmplayer_gst_set_volume_property(player, "volume");
5218 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5220 mmplayer_t *player = (mmplayer_t *)hplayer;
5224 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5225 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5227 *volume = player->sound.volume;
5229 LOGD("current vol = %f", *volume);
5232 return MM_ERROR_NONE;
5236 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5238 int ret = MM_ERROR_NONE;
5239 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244 LOGD("mute = %d", mute);
5246 player->sound.mute = mute;
5248 ret = __mmplayer_gst_set_volume_property(player, "mute");
5255 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5257 mmplayer_t *player = (mmplayer_t *)hplayer;
5261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5262 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5264 *mute = player->sound.mute;
5266 LOGD("current mute = %d", *mute);
5270 return MM_ERROR_NONE;
5274 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5276 mmplayer_t *player = (mmplayer_t *)hplayer;
5280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5282 player->audio_stream_changed_cb = callback;
5283 player->audio_stream_changed_cb_user_param = user_param;
5284 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5288 return MM_ERROR_NONE;
5292 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5294 mmplayer_t *player = (mmplayer_t *)hplayer;
5298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5300 player->audio_decoded_cb = callback;
5301 player->audio_decoded_cb_user_param = user_param;
5302 player->audio_extract_opt = opt;
5303 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5307 return MM_ERROR_NONE;
5311 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5313 mmplayer_t *player = (mmplayer_t *)hplayer;
5317 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5319 if (callback && !player->bufmgr)
5320 player->bufmgr = tbm_bufmgr_init(-1);
5322 player->set_mode.video_export = (callback) ? true : false;
5323 player->video_decoded_cb = callback;
5324 player->video_decoded_cb_user_param = user_param;
5326 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5330 return MM_ERROR_NONE;
5334 _mmplayer_start(MMHandleType hplayer)
5336 mmplayer_t *player = (mmplayer_t *)hplayer;
5337 gint ret = MM_ERROR_NONE;
5341 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5343 /* check current state */
5344 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5346 /* start pipeline */
5347 ret = _mmplayer_gst_start(player);
5348 if (ret != MM_ERROR_NONE)
5349 LOGE("failed to start player.");
5351 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5352 LOGD("force playing start even during buffering");
5353 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5361 /* NOTE: post "not supported codec message" to application
5362 * when one codec is not found during AUTOPLUGGING in MSL.
5363 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5364 * And, if any codec is not found, don't send message here.
5365 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5368 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5370 MMMessageParamType msg_param;
5371 memset(&msg_param, 0, sizeof(MMMessageParamType));
5372 gboolean post_msg_direct = FALSE;
5376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5379 player->not_supported_codec, player->can_support_codec);
5381 if (player->not_found_demuxer) {
5382 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5383 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5385 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5386 MMPLAYER_FREEIF(msg_param.data);
5388 return MM_ERROR_NONE;
5391 if (player->not_supported_codec) {
5392 if (player->can_support_codec) {
5393 // There is one codec to play
5394 post_msg_direct = TRUE;
5396 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5397 post_msg_direct = TRUE;
5400 if (post_msg_direct) {
5401 MMMessageParamType msg_param;
5402 memset(&msg_param, 0, sizeof(MMMessageParamType));
5404 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5405 LOGW("not found AUDIO codec, posting error code to application.");
5407 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5408 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5409 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5410 LOGW("not found VIDEO codec, posting error code to application.");
5412 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5413 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5416 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5418 MMPLAYER_FREEIF(msg_param.data);
5420 return MM_ERROR_NONE;
5422 // no any supported codec case
5423 LOGW("not found any codec, posting error code to application.");
5425 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5426 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5427 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5429 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5430 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5433 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5435 MMPLAYER_FREEIF(msg_param.data);
5441 return MM_ERROR_NONE;
5444 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5446 GstState element_state = GST_STATE_VOID_PENDING;
5447 GstState element_pending_state = GST_STATE_VOID_PENDING;
5448 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5449 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5451 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5453 MMPLAYER_RECONFIGURE_LOCK(player);
5454 if (!player->gapless.reconfigure) {
5455 MMPLAYER_RECONFIGURE_UNLOCK(player);
5459 LOGI("reconfigure is under process");
5460 MMPLAYER_RECONFIGURE_WAIT(player);
5461 MMPLAYER_RECONFIGURE_UNLOCK(player);
5462 LOGI("reconfigure is completed.");
5464 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5465 &element_state, &element_pending_state, timeout * GST_SECOND);
5466 if (result == GST_STATE_CHANGE_FAILURE)
5467 LOGW("failed to get pipeline state in %d sec", timeout);
5472 /* NOTE : it should be able to call 'stop' anytime*/
5474 _mmplayer_stop(MMHandleType hplayer)
5476 mmplayer_t *player = (mmplayer_t *)hplayer;
5477 int ret = MM_ERROR_NONE;
5481 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5483 /* check current state */
5484 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5486 /* need to wait till the rebuilding pipeline is completed */
5487 __mmplayer_check_pipeline_reconfigure_state(player);
5488 MMPLAYER_RECONFIGURE_LOCK(player);
5489 __mmplayer_reset_gapless_state(player);
5490 MMPLAYER_RECONFIGURE_UNLOCK(player);
5492 /* NOTE : application should not wait for EOS after calling STOP */
5493 _mmplayer_cancel_eos_timer(player);
5496 player->seek_state = MMPLAYER_SEEK_NONE;
5499 ret = _mmplayer_gst_stop(player);
5501 if (ret != MM_ERROR_NONE)
5502 LOGE("failed to stop player.");
5510 _mmplayer_pause(MMHandleType hplayer)
5512 mmplayer_t *player = (mmplayer_t *)hplayer;
5513 gint64 pos_nsec = 0;
5514 gboolean async = FALSE;
5515 gint ret = MM_ERROR_NONE;
5519 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5521 /* check current state */
5522 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5524 /* check pipline reconfigure state */
5525 __mmplayer_check_pipeline_reconfigure_state(player);
5527 switch (MMPLAYER_CURRENT_STATE(player)) {
5528 case MM_PLAYER_STATE_READY:
5530 /* check prepare async or not.
5531 * In the case of streaming playback, it's recommned to avoid blocking wait.
5533 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5534 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5536 /* Changing back sync of rtspsrc to async */
5537 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5538 LOGD("async prepare working mode for rtsp");
5544 case MM_PLAYER_STATE_PLAYING:
5546 /* NOTE : store current point to overcome some bad operation
5547 *(returning zero when getting current position in paused state) of some
5550 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5551 LOGW("getting current position failed in paused");
5553 player->last_position = pos_nsec;
5555 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5556 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5557 This causes problem is position calculation during normal pause resume scenarios also.
5558 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5559 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5560 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5561 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5567 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5568 LOGD("doing async pause in case of ms buff src");
5572 /* pause pipeline */
5573 ret = _mmplayer_gst_pause(player, async);
5575 if (ret != MM_ERROR_NONE)
5576 LOGE("failed to pause player. ret : 0x%x", ret);
5578 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5579 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5580 LOGE("failed to update display_rotation");
5588 /* in case of streaming, pause could take long time.*/
5590 _mmplayer_abort_pause(MMHandleType hplayer)
5592 mmplayer_t *player = (mmplayer_t *)hplayer;
5593 int ret = MM_ERROR_NONE;
5597 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5599 player->pipeline->mainbin,
5600 MM_ERROR_PLAYER_NOT_INITIALIZED);
5602 LOGD("set the pipeline state to READY");
5604 /* set state to READY */
5605 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5606 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5607 if (ret != MM_ERROR_NONE) {
5608 LOGE("fail to change state to READY");
5609 return MM_ERROR_PLAYER_INTERNAL;
5612 LOGD("succeeded in changing state to READY");
5617 _mmplayer_resume(MMHandleType hplayer)
5619 mmplayer_t *player = (mmplayer_t *)hplayer;
5620 int ret = MM_ERROR_NONE;
5621 gboolean async = FALSE;
5625 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5627 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5628 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5629 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5633 /* Changing back sync mode rtspsrc to async */
5634 LOGD("async resume for rtsp case");
5638 /* check current state */
5639 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5641 ret = _mmplayer_gst_resume(player, async);
5642 if (ret != MM_ERROR_NONE)
5643 LOGE("failed to resume player.");
5645 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5646 LOGD("force resume even during buffering");
5647 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5656 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5658 mmplayer_t *player = (mmplayer_t *)hplayer;
5659 gint64 pos_nsec = 0;
5660 int ret = MM_ERROR_NONE;
5662 signed long long start = 0, stop = 0;
5663 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5666 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5667 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5669 /* The sound of video is not supported under 0.0 and over 2.0. */
5670 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5671 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5674 _mmplayer_set_mute(hplayer, mute);
5676 if (player->playback_rate == rate)
5677 return MM_ERROR_NONE;
5679 /* If the position is reached at start potion during fast backward, EOS is posted.
5680 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5682 player->playback_rate = rate;
5684 current_state = MMPLAYER_CURRENT_STATE(player);
5686 if (current_state != MM_PLAYER_STATE_PAUSED)
5687 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5689 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5691 if ((current_state == MM_PLAYER_STATE_PAUSED)
5692 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5693 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5694 pos_nsec = player->last_position;
5699 stop = GST_CLOCK_TIME_NONE;
5701 start = GST_CLOCK_TIME_NONE;
5705 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5706 player->playback_rate,
5708 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5709 GST_SEEK_TYPE_SET, start,
5710 GST_SEEK_TYPE_SET, stop)) {
5711 LOGE("failed to set speed playback");
5712 return MM_ERROR_PLAYER_SEEK;
5715 LOGD("succeeded to set speed playback as %0.1f", rate);
5719 return MM_ERROR_NONE;;
5723 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5725 mmplayer_t *player = (mmplayer_t *)hplayer;
5726 int ret = MM_ERROR_NONE;
5730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5732 /* check pipline reconfigure state */
5733 __mmplayer_check_pipeline_reconfigure_state(player);
5735 ret = _mmplayer_gst_set_position(player, position, FALSE);
5743 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5745 mmplayer_t *player = (mmplayer_t *)hplayer;
5746 int ret = MM_ERROR_NONE;
5748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5749 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5751 if (g_strrstr(player->type, "video/mpegts"))
5752 __mmplayer_update_duration_value(player);
5754 *duration = player->duration;
5759 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5761 mmplayer_t *player = (mmplayer_t *)hplayer;
5762 int ret = MM_ERROR_NONE;
5764 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5766 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5772 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5774 mmplayer_t *player = (mmplayer_t *)hplayer;
5775 int ret = MM_ERROR_NONE;
5779 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5781 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5789 __mmplayer_is_midi_type(gchar *str_caps)
5791 if ((g_strrstr(str_caps, "audio/midi")) ||
5792 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5793 (g_strrstr(str_caps, "application/x-smaf")) ||
5794 (g_strrstr(str_caps, "audio/x-imelody")) ||
5795 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5796 (g_strrstr(str_caps, "audio/xmf")) ||
5797 (g_strrstr(str_caps, "audio/mxmf"))) {
5806 __mmplayer_is_only_mp3_type(gchar *str_caps)
5808 if (g_strrstr(str_caps, "application/x-id3") ||
5809 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5815 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5817 GstStructure *caps_structure = NULL;
5818 gint samplerate = 0;
5822 MMPLAYER_RETURN_IF_FAIL(player && caps);
5824 caps_structure = gst_caps_get_structure(caps, 0);
5826 /* set stream information */
5827 gst_structure_get_int(caps_structure, "rate", &samplerate);
5828 gst_structure_get_int(caps_structure, "channels", &channels);
5830 mm_player_set_attribute((MMHandleType)player, NULL,
5831 "content_audio_samplerate", samplerate,
5832 "content_audio_channels", channels, NULL);
5834 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5838 __mmplayer_update_content_type_info(mmplayer_t *player)
5841 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5843 if (__mmplayer_is_midi_type(player->type)) {
5844 player->bypass_audio_effect = TRUE;
5848 if (!player->streamer) {
5849 LOGD("no need to check streaming type");
5853 if (g_strrstr(player->type, "application/x-hls")) {
5854 /* If it can't know exact type when it parses uri because of redirection case,
5855 * it will be fixed by typefinder or when doing autoplugging.
5857 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5858 player->streamer->is_adaptive_streaming = TRUE;
5859 } else if (g_strrstr(player->type, "application/dash+xml")) {
5860 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5861 player->streamer->is_adaptive_streaming = TRUE;
5864 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5865 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5866 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5868 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5869 if (player->streamer->is_adaptive_streaming)
5870 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5872 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5876 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5881 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5882 GstCaps *caps, gpointer data)
5884 mmplayer_t *player = (mmplayer_t *)data;
5889 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5891 /* store type string */
5892 MMPLAYER_FREEIF(player->type);
5893 player->type = gst_caps_to_string(caps);
5895 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5896 player, player->type, probability, gst_caps_get_size(caps));
5898 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5899 (g_strrstr(player->type, "audio/x-raw-int"))) {
5900 LOGE("not support media format");
5902 if (player->msg_posted == FALSE) {
5903 MMMessageParamType msg_param;
5904 memset(&msg_param, 0, sizeof(MMMessageParamType));
5906 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5907 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5909 /* don't post more if one was sent already */
5910 player->msg_posted = TRUE;
5915 __mmplayer_update_content_type_info(player);
5917 pad = gst_element_get_static_pad(tf, "src");
5919 LOGE("fail to get typefind src pad.");
5923 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5924 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5925 gboolean async = FALSE;
5926 LOGE("failed to autoplug %s", player->type);
5928 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5930 if (async && player->msg_posted == FALSE)
5931 __mmplayer_handle_missed_plugin(player);
5935 gst_object_unref(GST_OBJECT(pad));
5941 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5943 GstElement *decodebin = NULL;
5947 /* create decodebin */
5948 decodebin = gst_element_factory_make("decodebin", NULL);
5951 LOGE("fail to create decodebin");
5955 /* raw pad handling signal */
5956 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5957 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5959 /* no-more-pad pad handling signal */
5960 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5961 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5963 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5964 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
5966 /* This signal is emitted when a pad for which there is no further possible
5967 decoding is added to the decodebin.*/
5968 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5969 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
5971 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5972 before looking for any elements that can handle that stream.*/
5973 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5974 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5976 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5977 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5978 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5980 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5981 before looking for any elements that can handle that stream.*/
5982 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5983 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5985 /* This signal is emitted once decodebin has finished decoding all the data.*/
5986 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5987 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
5989 /* This signal is emitted when a element is added to the bin.*/
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5991 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5998 __mmplayer_gst_make_queue2(mmplayer_t *player)
6000 GstElement *queue2 = NULL;
6001 gint64 dur_bytes = 0L;
6002 mmplayer_gst_element_t *mainbin = NULL;
6003 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6006 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6008 mainbin = player->pipeline->mainbin;
6010 queue2 = gst_element_factory_make("queue2", "queue2");
6012 LOGE("failed to create buffering queue element");
6016 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6017 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6019 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6021 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6022 * skip the pull mode(file or ring buffering) setting. */
6023 if (dur_bytes > 0) {
6024 if (!g_strrstr(player->type, "video/mpegts")) {
6025 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6026 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6032 _mm_player_streaming_set_queue2(player->streamer,
6036 (guint64)dur_bytes); /* no meaning at the moment */
6042 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6044 mmplayer_gst_element_t *mainbin = NULL;
6045 GstElement *decodebin = NULL;
6046 GstElement *queue2 = NULL;
6047 GstPad *sinkpad = NULL;
6048 GstPad *qsrcpad = NULL;
6051 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6053 mainbin = player->pipeline->mainbin;
6055 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6057 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6058 LOGW("need to check: muxed buffer is not null");
6061 queue2 = __mmplayer_gst_make_queue2(player);
6063 LOGE("failed to make queue2");
6067 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6068 LOGE("failed to add buffering queue");
6072 sinkpad = gst_element_get_static_pad(queue2, "sink");
6073 qsrcpad = gst_element_get_static_pad(queue2, "src");
6075 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6076 LOGE("failed to link [%s:%s]-[%s:%s]",
6077 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6081 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6082 LOGE("failed to sync queue2 state with parent");
6086 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6087 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6091 gst_object_unref(GST_OBJECT(sinkpad));
6095 /* create decodebin */
6096 decodebin = _mmplayer_gst_make_decodebin(player);
6098 LOGE("failed to make decodebin");
6102 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6103 LOGE("failed to add decodebin");
6107 /* to force caps on the decodebin element and avoid reparsing stuff by
6108 * typefind. It also avoids a deadlock in the way typefind activates pads in
6109 * the state change */
6110 g_object_set(decodebin, "sink-caps", caps, NULL);
6112 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6114 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6115 LOGE("failed to link [%s:%s]-[%s:%s]",
6116 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6120 gst_object_unref(GST_OBJECT(sinkpad));
6122 gst_object_unref(GST_OBJECT(qsrcpad));
6125 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6126 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6128 /* set decodebin property about buffer in streaming playback. *
6129 * in case of HLS/DASH, it does not need to have big buffer *
6130 * because it is kind of adaptive streaming. */
6131 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6132 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6133 gint high_percent = 0;
6135 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6136 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6138 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6140 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6142 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6143 "high-percent", high_percent,
6144 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6145 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6146 "max-size-buffers", 0, NULL); // disable or automatic
6149 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6150 LOGE("failed to sync decodebin state with parent");
6161 gst_object_unref(GST_OBJECT(sinkpad));
6164 gst_object_unref(GST_OBJECT(qsrcpad));
6167 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6168 * You need to explicitly set elements to the NULL state before
6169 * dropping the final reference, to allow them to clean up.
6171 gst_element_set_state(queue2, GST_STATE_NULL);
6173 /* And, it still has a parent "player".
6174 * You need to let the parent manage the object instead of unreffing the object directly.
6176 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6177 gst_object_unref(queue2);
6182 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6183 * You need to explicitly set elements to the NULL state before
6184 * dropping the final reference, to allow them to clean up.
6186 gst_element_set_state(decodebin, GST_STATE_NULL);
6188 /* And, it still has a parent "player".
6189 * You need to let the parent manage the object instead of unreffing the object directly.
6192 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6193 gst_object_unref(decodebin);
6201 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6205 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6206 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6208 LOGD("class : %s, mime : %s", factory_class, mime);
6210 /* add missing plugin */
6211 /* NOTE : msl should check missing plugin for image mime type.
6212 * Some motion jpeg clips can have playable audio track.
6213 * So, msl have to play audio after displaying popup written video format not supported.
6215 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6216 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6217 LOGD("not found demuxer");
6218 player->not_found_demuxer = TRUE;
6219 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6225 if (!g_strrstr(factory_class, "Demuxer")) {
6226 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6227 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6228 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6230 /* check that clip have multi tracks or not */
6231 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6232 LOGD("video plugin is already linked");
6234 LOGW("add VIDEO to missing plugin");
6235 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6236 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6238 } else if (g_str_has_prefix(mime, "audio")) {
6239 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6240 LOGD("audio plugin is already linked");
6242 LOGW("add AUDIO to missing plugin");
6243 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6244 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6252 return MM_ERROR_NONE;
6256 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6258 mmplayer_t *player = (mmplayer_t *)data;
6262 MMPLAYER_RETURN_IF_FAIL(player);
6264 /* remove fakesink. */
6265 if (!_mmplayer_gst_remove_fakesink(player,
6266 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6267 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6268 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6269 * source element are not same. To overcome this situation, this function will called
6270 * several places and several times. Therefore, this is not an error case.
6275 LOGD("[handle: %p] pipeline has completely constructed", player);
6277 if ((player->msg_posted == FALSE) &&
6278 (player->cmd >= MMPLAYER_COMMAND_START))
6279 __mmplayer_handle_missed_plugin(player);
6281 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6285 __mmplayer_check_profile(void)
6288 static int profile_tv = -1;
6290 if (__builtin_expect(profile_tv != -1, 1))
6293 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6294 switch (*profileName) {
6309 __mmplayer_get_next_uri(mmplayer_t *player)
6311 mmplayer_parse_profile_t profile;
6313 guint num_of_list = 0;
6316 num_of_list = g_list_length(player->uri_info.uri_list);
6317 uri_idx = player->uri_info.uri_idx;
6319 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6320 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6321 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6323 LOGW("next uri does not exist");
6327 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6328 LOGE("failed to parse profile");
6332 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6333 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6334 LOGW("uri type is not supported(%d)", profile.uri_type);
6338 LOGD("success to find next uri %d", uri_idx);
6342 if (!uri || uri_idx == num_of_list) {
6343 LOGE("failed to find next uri");
6347 player->uri_info.uri_idx = uri_idx;
6348 if (mm_player_set_attribute((MMHandleType)player, NULL,
6349 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6350 LOGE("failed to set attribute");
6354 SECURE_LOGD("next playback uri: %s", uri);
6359 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6361 #define REPEAT_COUNT_INFINITE -1
6362 #define REPEAT_COUNT_MIN 2
6363 #define ORIGINAL_URI_ONLY 1
6365 MMHandleType attrs = 0;
6369 guint num_of_uri = 0;
6370 int profile_tv = -1;
6374 LOGD("checking for gapless play option");
6376 if (player->build_audio_offload) {
6377 LOGE("offload path is not supportable.");
6381 if (player->pipeline->textbin) {
6382 LOGE("subtitle path is enabled. gapless play is not supported.");
6386 attrs = MMPLAYER_GET_ATTRS(player);
6388 LOGE("fail to get attributes.");
6392 mm_attrs_multiple_get(player->attrs, NULL,
6393 "content_video_found", &video,
6394 "profile_play_count", &count,
6395 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6397 /* gapless playback is not supported in case of video at TV profile. */
6398 profile_tv = __mmplayer_check_profile();
6399 if (profile_tv && video) {
6400 LOGW("not support video gapless playback");
6404 /* check repeat count in case of audio */
6406 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6407 LOGW("gapless is disabled");
6411 num_of_uri = g_list_length(player->uri_info.uri_list);
6413 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6415 if (num_of_uri == ORIGINAL_URI_ONLY) {
6416 /* audio looping path */
6417 if (count >= REPEAT_COUNT_MIN) {
6418 /* decrease play count */
6419 /* we succeeded to rewind. update play count and then wait for next EOS */
6421 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6422 } else if (count != REPEAT_COUNT_INFINITE) {
6423 LOGD("there is no next uri and no repeat");
6426 LOGD("looping cnt %d", count);
6428 /* gapless playback path */
6429 if (!__mmplayer_get_next_uri(player)) {
6430 LOGE("failed to get next uri");
6437 LOGE("unable to play gapless path. EOS will be posted soon");
6442 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6444 mmplayer_selector_t *selector = &player->selector[type];
6445 mmplayer_gst_element_t *sinkbin = NULL;
6446 main_element_id_e selectorId = MMPLAYER_M_NUM;
6447 main_element_id_e sinkId = MMPLAYER_M_NUM;
6448 GstPad *srcpad = NULL;
6449 GstPad *sinkpad = NULL;
6450 gboolean send_notice = FALSE;
6453 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6455 LOGD("type %d", type);
6458 case MM_PLAYER_TRACK_TYPE_AUDIO:
6459 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6460 sinkId = MMPLAYER_A_BIN;
6461 sinkbin = player->pipeline->audiobin;
6463 case MM_PLAYER_TRACK_TYPE_VIDEO:
6464 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6465 sinkId = MMPLAYER_V_BIN;
6466 sinkbin = player->pipeline->videobin;
6469 case MM_PLAYER_TRACK_TYPE_TEXT:
6470 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6471 sinkId = MMPLAYER_T_BIN;
6472 sinkbin = player->pipeline->textbin;
6475 LOGE("requested type is not supportable");
6480 if (player->pipeline->mainbin[selectorId].gst) {
6483 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6485 if (selector->event_probe_id != 0)
6486 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6487 selector->event_probe_id = 0;
6489 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6490 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6492 if (srcpad && sinkpad) {
6493 /* after getting drained signal there is no data flows, so no need to do pad_block */
6494 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6495 gst_pad_unlink(srcpad, sinkpad);
6497 /* send custom event to sink pad to handle it at video sink */
6499 LOGD("send custom event to sinkpad");
6500 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6501 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6502 gst_pad_send_event(sinkpad, event);
6506 gst_object_unref(sinkpad);
6509 gst_object_unref(srcpad);
6512 LOGD("selector release");
6514 /* release and unref requests pad from the selector */
6515 for (n = 0; n < selector->channels->len; n++) {
6516 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6517 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6519 g_ptr_array_set_size(selector->channels, 0);
6521 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6522 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6524 player->pipeline->mainbin[selectorId].gst = NULL;
6532 __mmplayer_deactivate_old_path(mmplayer_t *player)
6535 MMPLAYER_RETURN_IF_FAIL(player);
6537 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6538 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6539 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6540 LOGE("deactivate selector error");
6544 _mmplayer_track_destroy(player);
6545 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6547 if (player->streamer) {
6548 _mm_player_streaming_initialize(player->streamer, FALSE);
6549 _mm_player_streaming_destroy(player->streamer);
6550 player->streamer = NULL;
6553 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6559 if (!player->msg_posted) {
6560 MMMessageParamType msg = {0,};
6563 msg.code = MM_ERROR_PLAYER_INTERNAL;
6564 LOGE("gapless_uri_play> deactivate error");
6566 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6567 player->msg_posted = TRUE;
6573 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6575 int result = MM_ERROR_NONE;
6576 mmplayer_t *player = (mmplayer_t *)hplayer;
6579 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6580 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6582 if (mm_player_set_attribute(hplayer, NULL,
6583 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6584 LOGE("failed to set attribute");
6585 result = MM_ERROR_PLAYER_INTERNAL;
6587 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6588 LOGE("failed to add the original uri in the uri list.");
6596 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6598 mmplayer_t *player = (mmplayer_t *)hplayer;
6599 guint num_of_list = 0;
6603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6604 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6606 if (player->pipeline && player->pipeline->textbin) {
6607 LOGE("subtitle path is enabled.");
6608 return MM_ERROR_PLAYER_INVALID_STATE;
6611 num_of_list = g_list_length(player->uri_info.uri_list);
6613 if (is_first_path) {
6614 if (num_of_list == 0) {
6615 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6616 SECURE_LOGD("add original path : %s", uri);
6618 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6619 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6621 SECURE_LOGD("change original path : %s", uri);
6624 MMHandleType attrs = 0;
6625 attrs = MMPLAYER_GET_ATTRS(player);
6627 if (num_of_list == 0) {
6628 char *original_uri = NULL;
6631 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6633 if (!original_uri) {
6634 LOGE("there is no original uri.");
6635 return MM_ERROR_PLAYER_INVALID_STATE;
6638 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6639 player->uri_info.uri_idx = 0;
6641 SECURE_LOGD("add original path at first : %s", original_uri);
6645 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6646 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6650 return MM_ERROR_NONE;
6654 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6656 mmplayer_t *player = (mmplayer_t *)hplayer;
6657 char *next_uri = NULL;
6658 guint num_of_list = 0;
6661 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6663 num_of_list = g_list_length(player->uri_info.uri_list);
6665 if (num_of_list > 0) {
6666 gint uri_idx = player->uri_info.uri_idx;
6668 if (uri_idx < num_of_list-1)
6673 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6674 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6676 *uri = g_strdup(next_uri);
6680 return MM_ERROR_NONE;
6684 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6685 GstCaps *caps, gpointer data)
6687 mmplayer_t *player = (mmplayer_t *)data;
6688 const gchar *klass = NULL;
6689 const gchar *mime = NULL;
6690 gchar *caps_str = NULL;
6692 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6693 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6694 caps_str = gst_caps_to_string(caps);
6696 LOGW("unknown type of caps : %s from %s",
6697 caps_str, GST_ELEMENT_NAME(elem));
6699 MMPLAYER_FREEIF(caps_str);
6701 /* There is no available codec. */
6702 __mmplayer_check_not_supported_codec(player, klass, mime);
6706 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6707 GstCaps *caps, gpointer data)
6709 mmplayer_t *player = (mmplayer_t *)data;
6710 const char *mime = NULL;
6711 gboolean ret = TRUE;
6713 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6714 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6716 if (g_str_has_prefix(mime, "audio")) {
6717 GstStructure *caps_structure = NULL;
6718 gint samplerate = 0;
6720 gchar *caps_str = NULL;
6722 caps_structure = gst_caps_get_structure(caps, 0);
6723 gst_structure_get_int(caps_structure, "rate", &samplerate);
6724 gst_structure_get_int(caps_structure, "channels", &channels);
6726 if ((channels > 0 && samplerate == 0)) {
6727 LOGD("exclude audio...");
6731 caps_str = gst_caps_to_string(caps);
6732 /* set it directly because not sent by TAG */
6733 if (g_strrstr(caps_str, "mobile-xmf"))
6734 mm_player_set_attribute((MMHandleType)player, NULL,
6735 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6737 MMPLAYER_FREEIF(caps_str);
6738 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6739 LOGD("already video linked");
6742 LOGD("found new stream");
6749 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6751 gboolean ret = FALSE;
6752 GDBusConnection *conn = NULL;
6754 GVariant *result = NULL;
6755 const gchar *dbus_device_type = NULL;
6756 const gchar *dbus_ret = NULL;
6759 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6761 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6766 result = g_dbus_connection_call_sync(conn,
6767 "org.pulseaudio.Server",
6768 "/org/pulseaudio/StreamManager",
6769 "org.pulseaudio.StreamManager",
6770 "GetCurrentMediaRoutingPath",
6771 g_variant_new("(s)", "out"),
6772 G_VARIANT_TYPE("(ss)"),
6773 G_DBUS_CALL_FLAGS_NONE,
6777 if (!result || err) {
6778 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6783 /* device type is listed in stream-map.json at mmfw-sysconf */
6784 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6786 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6787 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6790 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6791 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6792 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6793 LOGD("audio offload is supportable");
6799 LOGD("audio offload is not supportable");
6802 g_variant_unref(result);
6804 g_object_unref(conn);
6809 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6811 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6812 gint64 position = 0;
6814 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6815 player->pipeline && player->pipeline->mainbin);
6817 MMPLAYER_CMD_LOCK(player);
6818 current_state = MMPLAYER_CURRENT_STATE(player);
6820 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6821 LOGW("getting current position failed in paused");
6823 _mmplayer_unrealize((MMHandleType)player);
6824 _mmplayer_realize((MMHandleType)player);
6826 _mmplayer_set_position((MMHandleType)player, position);
6828 /* async not to be blocked in streaming case */
6829 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6831 _mmplayer_pause((MMHandleType)player);
6833 if (current_state == MM_PLAYER_STATE_PLAYING)
6834 _mmplayer_start((MMHandleType)player);
6835 MMPLAYER_CMD_UNLOCK(player);
6837 LOGD("rebuilding audio pipeline is completed.");
6840 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6842 mmplayer_t *player = (mmplayer_t *)user_data;
6843 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6844 gboolean is_supportable = FALSE;
6846 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6847 LOGW("failed to get device type");
6849 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6851 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6852 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6853 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6854 LOGD("ignore this dev connected info");
6858 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6859 if (player->build_audio_offload == is_supportable) {
6860 LOGD("keep current pipeline without re-building");
6864 /* rebuild pipeline */
6865 LOGD("re-build pipeline - offload: %d", is_supportable);
6866 player->build_audio_offload = FALSE;
6867 __mmplayer_rebuild_audio_pipeline(player);
6873 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6875 unsigned int id = 0;
6877 if (player->audio_device_cb_id != 0) {
6878 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6882 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6883 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6884 LOGD("added device connected cb (%u)", id);
6885 player->audio_device_cb_id = id;
6887 LOGW("failed to add device connected cb");
6894 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6896 mmplayer_t *player = (mmplayer_t *)hplayer;
6899 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6900 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6902 *activated = player->build_audio_offload;
6904 LOGD("offload activated : %d", (int)*activated);
6907 return MM_ERROR_NONE;
6911 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6914 this function need to be updated according to the supported media format
6915 @see player->ini.audio_offload_media_format */
6917 if (__mmplayer_is_only_mp3_type(player->type)) {
6918 LOGD("offload supportable media format type");
6926 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6928 gboolean ret = FALSE;
6929 GstElementFactory *factory = NULL;
6932 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6934 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6935 if (!__mmplayer_is_offload_supported_type(player))
6938 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6939 LOGD("there is no audio offload sink");
6943 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6944 LOGW("there is no audio device type to support offload");
6948 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6950 LOGW("there is no installed audio offload sink element");
6953 gst_object_unref(factory);
6955 if (__mmplayer_acquire_hw_resource(player,
6956 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6957 LOGE("failed to acquire audio offload decoder resource");
6961 if (!__mmplayer_add_audio_device_connected_cb(player))
6964 if (!__mmplayer_is_audio_offload_device_type(player))
6967 LOGD("audio offload can be built");
6972 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6978 static GstAutoplugSelectResult
6979 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6981 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6982 int audio_offload = 0;
6984 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6985 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6987 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6988 LOGD("expose audio path to build offload output path");
6989 player->build_audio_offload = TRUE;
6990 /* update codec info */
6991 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6992 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6993 player->audiodec_linked = 1;
6995 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6999 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7000 And need to consider the multi-track audio content.
7001 There is no HW audio decoder in public. */
7003 /* set stream information */
7004 if (!player->audiodec_linked)
7005 __mmplayer_set_audio_attrs(player, caps);
7007 /* update codec info */
7008 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7009 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7010 player->audiodec_linked = 1;
7012 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7014 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7015 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7017 /* mark video decoder for acquire */
7018 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7019 LOGW("video decoder resource is already acquired, skip it.");
7020 ret = GST_AUTOPLUG_SELECT_SKIP;
7024 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7025 LOGE("failed to acquire video decoder resource");
7026 ret = GST_AUTOPLUG_SELECT_SKIP;
7029 player->interrupted_by_resource = FALSE;
7032 /* update codec info */
7033 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7034 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7035 player->videodec_linked = 1;
7043 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7044 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7046 #define DEFAULT_IDX 0xFFFF
7047 #define MIN_FACTORY_NUM 2
7048 mmplayer_t *player = (mmplayer_t *)data;
7049 GValueArray *new_factories = NULL;
7050 GValue val = { 0, };
7051 GstElementFactory *factory = NULL;
7052 const gchar *klass = NULL;
7053 gchar *factory_name = NULL;
7054 guint hw_dec_idx = DEFAULT_IDX;
7055 guint first_sw_dec_idx = DEFAULT_IDX;
7056 guint last_sw_dec_idx = DEFAULT_IDX;
7057 guint new_pos = DEFAULT_IDX;
7058 guint rm_pos = DEFAULT_IDX;
7059 int audio_codec_type;
7060 int video_codec_type;
7061 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7063 if (factories->n_values < MIN_FACTORY_NUM)
7066 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7067 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7070 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7072 for (int i = 0 ; i < factories->n_values ; i++) {
7073 gchar *hw_dec_info = NULL;
7074 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7076 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7077 klass = gst_element_factory_get_klass(factory);
7078 factory_name = GST_OBJECT_NAME(factory);
7081 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7083 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7084 if (!player->need_audio_dec_sorting) {
7085 LOGD("sorting is not required");
7088 codec_type = audio_codec_type;
7089 hw_dec_info = player->ini.audiocodec_element_hw;
7090 sw_dec_info = player->ini.audiocodec_element_sw;
7091 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7092 if (!player->need_video_dec_sorting) {
7093 LOGD("sorting is not required");
7096 codec_type = video_codec_type;
7097 hw_dec_info = player->ini.videocodec_element_hw;
7098 sw_dec_info = player->ini.videocodec_element_sw;
7103 if (g_strrstr(factory_name, hw_dec_info)) {
7106 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7107 if (strstr(factory_name, sw_dec_info[j])) {
7108 last_sw_dec_idx = i;
7109 if (first_sw_dec_idx == DEFAULT_IDX) {
7110 first_sw_dec_idx = i;
7115 if (first_sw_dec_idx == DEFAULT_IDX)
7116 LOGW("unknown codec %s", factory_name);
7120 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7123 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7124 if (hw_dec_idx < first_sw_dec_idx)
7126 new_pos = first_sw_dec_idx - 1;
7127 rm_pos = hw_dec_idx + 1;
7128 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7129 if (last_sw_dec_idx < hw_dec_idx)
7131 new_pos = last_sw_dec_idx + 1;
7132 rm_pos = hw_dec_idx;
7137 /* change position - insert H/W decoder according to the new position */
7138 new_factories = g_value_array_copy(factories);
7139 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7140 g_value_init (&val, G_TYPE_OBJECT);
7141 g_value_set_object (&val, factory);
7142 g_value_array_insert(new_factories, new_pos, &val);
7143 g_value_unset (&val);
7144 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7146 for (int i = 0 ; i < new_factories->n_values ; i++) {
7147 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7149 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7150 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7153 return new_factories;
7157 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7158 GstCaps *caps, GstElementFactory *factory, gpointer data)
7160 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7161 mmplayer_t *player = (mmplayer_t *)data;
7163 gchar *factory_name = NULL;
7164 gchar *caps_str = NULL;
7165 const gchar *klass = NULL;
7168 factory_name = GST_OBJECT_NAME(factory);
7169 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7170 caps_str = gst_caps_to_string(caps);
7172 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7174 /* store type string */
7175 if (player->type == NULL) {
7176 player->type = gst_caps_to_string(caps);
7177 __mmplayer_update_content_type_info(player);
7180 /* filtering exclude keyword */
7181 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7182 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7183 LOGW("skipping [%s] by exculde keyword [%s]",
7184 factory_name, player->ini.exclude_element_keyword[idx]);
7186 result = GST_AUTOPLUG_SELECT_SKIP;
7191 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7192 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7193 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7194 factory_name, player->ini.unsupported_codec_keyword[idx]);
7195 result = GST_AUTOPLUG_SELECT_SKIP;
7200 /* exclude webm format */
7201 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7202 * because webm format is not supportable.
7203 * If webm is disabled in "autoplug-continue", there is no state change
7204 * failure or error because the decodebin will expose the pad directly.
7205 * It make MSL invoke _prepare_async_callback.
7206 * So, we need to disable webm format in "autoplug-select" */
7207 if (caps_str && strstr(caps_str, "webm")) {
7208 LOGW("webm is not supported");
7209 result = GST_AUTOPLUG_SELECT_SKIP;
7213 /* check factory class for filtering */
7214 /* NOTE : msl don't need to use image plugins.
7215 * So, those plugins should be skipped for error handling.
7217 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7218 LOGD("skipping [%s] by not required", factory_name);
7219 result = GST_AUTOPLUG_SELECT_SKIP;
7223 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7224 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7225 // TO CHECK : subtitle if needed, add subparse exception.
7226 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7227 result = GST_AUTOPLUG_SELECT_SKIP;
7231 if (g_strrstr(factory_name, "mpegpsdemux")) {
7232 LOGD("skipping PS container - not support");
7233 result = GST_AUTOPLUG_SELECT_SKIP;
7237 if (g_strrstr(factory_name, "mssdemux"))
7238 player->smooth_streaming = TRUE;
7240 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7241 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7244 GstStructure *str = NULL;
7245 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7247 /* don't make video because of not required */
7248 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7249 (!player->set_mode.video_export)) {
7250 LOGD("no need video decoding, expose pad");
7251 result = GST_AUTOPLUG_SELECT_EXPOSE;
7255 /* get w/h for omx state-tune */
7256 /* FIXME: deprecated? */
7257 str = gst_caps_get_structure(caps, 0);
7258 gst_structure_get_int(str, "width", &width);
7261 if (player->v_stream_caps) {
7262 gst_caps_unref(player->v_stream_caps);
7263 player->v_stream_caps = NULL;
7266 player->v_stream_caps = gst_caps_copy(caps);
7267 LOGD("take caps for video state tune");
7268 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7272 if (g_strrstr(klass, "Codec/Decoder")) {
7273 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7274 if (result != GST_AUTOPLUG_SELECT_TRY) {
7275 LOGW("skip add decoder");
7281 MMPLAYER_FREEIF(caps_str);
7287 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7290 //mmplayer_t *player = (mmplayer_t *)data;
7291 GstCaps *caps = NULL;
7293 LOGD("[Decodebin2] pad-removed signal");
7295 caps = gst_pad_query_caps(new_pad, NULL);
7297 LOGW("query caps is NULL");
7301 gchar *caps_str = NULL;
7302 caps_str = gst_caps_to_string(caps);
7304 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7306 MMPLAYER_FREEIF(caps_str);
7307 gst_caps_unref(caps);
7311 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7313 mmplayer_t *player = (mmplayer_t *)data;
7314 GstIterator *iter = NULL;
7315 GValue item = { 0, };
7317 gboolean done = FALSE;
7318 gboolean is_all_drained = TRUE;
7321 MMPLAYER_RETURN_IF_FAIL(player);
7323 LOGD("got drained signal");
7325 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7326 LOGW("Fail to get cmd lock");
7330 if (!__mmplayer_verify_gapless_play_path(player)) {
7331 LOGD("decoding is finished.");
7332 MMPLAYER_CMD_UNLOCK(player);
7336 _mmplayer_set_reconfigure_state(player, TRUE);
7337 MMPLAYER_CMD_UNLOCK(player);
7339 /* check decodebin src pads whether they received EOS or not */
7340 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7343 switch (gst_iterator_next(iter, &item)) {
7344 case GST_ITERATOR_OK:
7345 pad = g_value_get_object(&item);
7346 if (pad && !GST_PAD_IS_EOS(pad)) {
7347 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7348 is_all_drained = FALSE;
7351 g_value_reset(&item);
7353 case GST_ITERATOR_RESYNC:
7354 gst_iterator_resync(iter);
7356 case GST_ITERATOR_ERROR:
7357 case GST_ITERATOR_DONE:
7362 g_value_unset(&item);
7363 gst_iterator_free(iter);
7365 if (!is_all_drained) {
7366 LOGD("Wait util the all pads get EOS.");
7371 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7372 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7374 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7375 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7376 __mmplayer_deactivate_old_path(player);
7382 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7384 mmplayer_t *player = (mmplayer_t *)data;
7385 const gchar *klass = NULL;
7386 gchar *factory_name = NULL;
7388 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7389 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7391 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7393 if (__mmplayer_add_dump_buffer_probe(player, element))
7394 LOGD("add buffer probe");
7396 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7397 gchar *selected = NULL;
7398 selected = g_strdup(GST_ELEMENT_NAME(element));
7399 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7402 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7403 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7404 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7406 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7407 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7409 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7410 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7411 "max-video-width", player->adaptive_info.limit.width,
7412 "max-video-height", player->adaptive_info.limit.height, NULL);
7414 } else if (g_strrstr(klass, "Demuxer")) {
7416 LOGD("plugged element is demuxer. take it");
7418 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7419 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7422 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7423 int surface_type = 0;
7425 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7428 // to support trust-zone only
7429 if (g_strrstr(factory_name, "asfdemux")) {
7430 LOGD("set file-location %s", player->profile.uri);
7431 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7432 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7433 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7434 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7435 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7436 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7437 (__mmplayer_is_only_mp3_type(player->type))) {
7438 LOGD("[mpegaudioparse] set streaming pull mode.");
7439 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7441 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7442 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7445 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7446 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7447 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7449 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7450 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7452 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7453 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7454 (MMPLAYER_IS_DASH_STREAMING(player))) {
7455 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7456 _mm_player_streaming_set_multiqueue(player->streamer, element);
7457 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7466 __mmplayer_release_misc(mmplayer_t *player)
7469 bool cur_mode = player->set_mode.rich_audio;
7472 MMPLAYER_RETURN_IF_FAIL(player);
7474 player->sent_bos = FALSE;
7475 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7477 player->seek_state = MMPLAYER_SEEK_NONE;
7479 player->total_bitrate = 0;
7480 player->total_maximum_bitrate = 0;
7482 player->not_found_demuxer = 0;
7484 player->last_position = 0;
7485 player->duration = 0;
7486 player->http_content_size = 0;
7487 player->not_supported_codec = MISSING_PLUGIN_NONE;
7488 player->can_support_codec = FOUND_PLUGIN_NONE;
7489 player->pending_seek.is_pending = false;
7490 player->pending_seek.pos = 0;
7491 player->msg_posted = FALSE;
7492 player->has_many_types = FALSE;
7493 player->is_subtitle_force_drop = FALSE;
7494 player->play_subtitle = FALSE;
7495 player->adjust_subtitle_pos = 0;
7496 player->has_closed_caption = FALSE;
7497 player->set_mode.video_export = false;
7498 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7499 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7501 player->set_mode.rich_audio = cur_mode;
7503 if (player->audio_device_cb_id > 0 &&
7504 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7505 LOGW("failed to remove audio device_connected_callback");
7506 player->audio_device_cb_id = 0;
7508 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7509 player->bitrate[i] = 0;
7510 player->maximum_bitrate[i] = 0;
7513 /* free memory related to audio effect */
7514 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7516 if (player->adaptive_info.var_list) {
7517 g_list_free_full(player->adaptive_info.var_list, g_free);
7518 player->adaptive_info.var_list = NULL;
7521 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7522 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7523 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7525 /* Reset video360 settings to their defaults in case if the pipeline is to be
7528 player->video360_metadata.is_spherical = -1;
7529 player->is_openal_plugin_used = FALSE;
7531 player->is_content_spherical = FALSE;
7532 player->is_video360_enabled = TRUE;
7533 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7534 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7535 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7536 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7537 player->video360_zoom = 1.0f;
7538 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7539 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7541 player->sound.rg_enable = false;
7543 __mmplayer_initialize_video_roi(player);
7548 __mmplayer_release_misc_post(mmplayer_t *player)
7550 char *original_uri = NULL;
7553 /* player->pipeline is already released before. */
7554 MMPLAYER_RETURN_IF_FAIL(player);
7556 player->video_decoded_cb = NULL;
7557 player->video_decoded_cb_user_param = NULL;
7558 player->video_stream_prerolled = false;
7560 player->audio_decoded_cb = NULL;
7561 player->audio_decoded_cb_user_param = NULL;
7562 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7564 player->audio_stream_changed_cb = NULL;
7565 player->audio_stream_changed_cb_user_param = NULL;
7567 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7569 /* clean found audio decoders */
7570 if (player->audio_decoders) {
7571 GList *a_dec = player->audio_decoders;
7572 for (; a_dec; a_dec = g_list_next(a_dec)) {
7573 gchar *name = a_dec->data;
7574 MMPLAYER_FREEIF(name);
7576 g_list_free(player->audio_decoders);
7577 player->audio_decoders = NULL;
7580 /* clean the uri list except original uri */
7581 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7582 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7584 LOGW("failed to get original uri info");
7586 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7587 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7589 GList *uri_list = player->uri_info.uri_list;
7590 for (; uri_list; uri_list = g_list_next(uri_list)) {
7591 gchar *uri = uri_list->data;
7592 if (original_uri != uri)
7593 MMPLAYER_FREEIF(uri);
7597 /* clear the audio stream buffer list */
7598 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7600 /* clear the video stream bo list */
7601 __mmplayer_video_stream_destroy_bo_list(player);
7602 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7604 if (player->profile.input_mem.buf) {
7605 free(player->profile.input_mem.buf);
7606 player->profile.input_mem.buf = NULL;
7608 player->profile.input_mem.len = 0;
7609 player->profile.input_mem.offset = 0;
7611 player->uri_info.uri_idx = 0;
7616 __mmplayer_check_subtitle(mmplayer_t *player)
7618 MMHandleType attrs = 0;
7619 char *subtitle_uri = NULL;
7623 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7625 /* get subtitle attribute */
7626 attrs = MMPLAYER_GET_ATTRS(player);
7630 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7631 if (!subtitle_uri || !strlen(subtitle_uri))
7634 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7635 player->is_external_subtitle_present = TRUE;
7643 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7645 MMPLAYER_RETURN_IF_FAIL(player);
7647 if (player->eos_timer) {
7648 LOGD("cancel eos timer");
7649 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7650 player->eos_timer = 0;
7657 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7661 MMPLAYER_RETURN_IF_FAIL(player);
7662 MMPLAYER_RETURN_IF_FAIL(sink);
7664 player->sink_elements = g_list_append(player->sink_elements, sink);
7670 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7674 MMPLAYER_RETURN_IF_FAIL(player);
7675 MMPLAYER_RETURN_IF_FAIL(sink);
7677 player->sink_elements = g_list_remove(player->sink_elements, sink);
7683 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7684 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7686 mmplayer_signal_item_t *item = NULL;
7689 MMPLAYER_RETURN_IF_FAIL(player);
7691 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7692 LOGE("invalid signal type [%d]", type);
7696 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7698 LOGE("cannot connect signal [%s]", signal);
7703 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7704 player->signals[type] = g_list_append(player->signals[type], item);
7710 /* NOTE : be careful with calling this api. please refer to below glib comment
7711 * glib comment : Note that there is a bug in GObject that makes this function much
7712 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7713 * will no longer be called, but, the signal handler is not currently disconnected.
7714 * If the instance is itself being freed at the same time than this doesn't matter,
7715 * since the signal will automatically be removed, but if instance persists,
7716 * then the signal handler will leak. You should not remove the signal yourself
7717 * because in a future versions of GObject, the handler will automatically be
7720 * It's possible to work around this problem in a way that will continue to work
7721 * with future versions of GObject by checking that the signal handler is still
7722 * connected before disconnected it:
7724 * if (g_signal_handler_is_connected(instance, id))
7725 * g_signal_handler_disconnect(instance, id);
7728 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7730 GList *sig_list = NULL;
7731 mmplayer_signal_item_t *item = NULL;
7735 MMPLAYER_RETURN_IF_FAIL(player);
7737 LOGD("release signals type : %d", type);
7739 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7740 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7741 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7742 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7743 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7744 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7748 sig_list = player->signals[type];
7750 for (; sig_list; sig_list = sig_list->next) {
7751 item = sig_list->data;
7753 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7754 if (g_signal_handler_is_connected(item->obj, item->sig))
7755 g_signal_handler_disconnect(item->obj, item->sig);
7758 MMPLAYER_FREEIF(item);
7761 g_list_free(player->signals[type]);
7762 player->signals[type] = NULL;
7770 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7772 mmplayer_t *player = 0;
7773 int prev_display_surface_type = 0;
7777 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7779 player = MM_PLAYER_CAST(handle);
7781 /* check video sinkbin is created */
7782 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7783 LOGW("Videosink is already created");
7784 return MM_ERROR_NONE;
7787 LOGD("videosink element is not yet ready");
7789 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7790 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7792 return MM_ERROR_INVALID_ARGUMENT;
7795 /* load previous attributes */
7796 if (player->attrs) {
7797 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7798 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7799 if (prev_display_surface_type == surface_type) {
7800 LOGD("incoming display surface type is same as previous one, do nothing..");
7802 return MM_ERROR_NONE;
7805 LOGE("failed to load attributes");
7807 return MM_ERROR_PLAYER_INTERNAL;
7810 /* videobin is not created yet, so we just set attributes related to display surface */
7811 LOGD("store display attribute for given surface type(%d)", surface_type);
7812 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7813 "display_overlay", wl_surface_id, NULL);
7816 return MM_ERROR_NONE;
7819 /* Note : if silent is true, then subtitle would not be displayed. :*/
7821 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7823 mmplayer_t *player = (mmplayer_t *)hplayer;
7827 /* check player handle */
7828 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7830 player->set_mode.subtitle_off = silent;
7832 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7836 return MM_ERROR_NONE;
7840 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7842 mmplayer_gst_element_t *mainbin = NULL;
7843 mmplayer_gst_element_t *textbin = NULL;
7844 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7845 GstState current_state = GST_STATE_VOID_PENDING;
7846 GstState element_state = GST_STATE_VOID_PENDING;
7847 GstState element_pending_state = GST_STATE_VOID_PENDING;
7849 GstEvent *event = NULL;
7850 int result = MM_ERROR_NONE;
7852 GstClock *curr_clock = NULL;
7853 GstClockTime base_time, start_time, curr_time;
7858 /* check player handle */
7859 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7861 player->pipeline->mainbin &&
7862 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7864 mainbin = player->pipeline->mainbin;
7865 textbin = player->pipeline->textbin;
7867 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7869 // sync clock with current pipeline
7870 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7871 curr_time = gst_clock_get_time(curr_clock);
7873 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7874 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7876 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7877 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7879 if (current_state > GST_STATE_READY) {
7880 // sync state with current pipeline
7881 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7882 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7883 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7885 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7886 if (GST_STATE_CHANGE_FAILURE == ret) {
7887 LOGE("fail to state change.");
7888 result = MM_ERROR_PLAYER_INTERNAL;
7892 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7893 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7896 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7897 gst_object_unref(curr_clock);
7900 // seek to current position
7901 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7902 result = MM_ERROR_PLAYER_INVALID_STATE;
7903 LOGE("gst_element_query_position failed, invalid state");
7907 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7908 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);
7910 _mmplayer_gst_send_event_to_sink(player, event);
7912 result = MM_ERROR_PLAYER_INTERNAL;
7913 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7917 /* sync state with current pipeline */
7918 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7919 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7920 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7922 return MM_ERROR_NONE;
7925 /* release text pipeline resource */
7926 player->textsink_linked = 0;
7928 /* release signal */
7929 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7931 /* release textbin with it's childs */
7932 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7933 MMPLAYER_FREEIF(player->pipeline->textbin);
7934 player->pipeline->textbin = NULL;
7936 /* release subtitle elem */
7937 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7938 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7944 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7946 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7947 GstState current_state = GST_STATE_VOID_PENDING;
7949 MMHandleType attrs = 0;
7950 mmplayer_gst_element_t *mainbin = NULL;
7951 mmplayer_gst_element_t *textbin = NULL;
7953 gchar *subtitle_uri = NULL;
7954 int result = MM_ERROR_NONE;
7955 const gchar *charset = NULL;
7959 /* check player handle */
7960 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7962 player->pipeline->mainbin &&
7963 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7964 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7966 mainbin = player->pipeline->mainbin;
7967 textbin = player->pipeline->textbin;
7969 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7970 if (current_state < GST_STATE_READY) {
7971 result = MM_ERROR_PLAYER_INVALID_STATE;
7972 LOGE("Pipeline is not in proper state");
7976 attrs = MMPLAYER_GET_ATTRS(player);
7978 LOGE("cannot get content attribute");
7979 result = MM_ERROR_PLAYER_INTERNAL;
7983 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7984 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7985 LOGE("subtitle uri is not proper filepath");
7986 result = MM_ERROR_PLAYER_INVALID_URI;
7990 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7991 LOGE("failed to get storage info of subtitle path");
7992 result = MM_ERROR_PLAYER_INVALID_URI;
7996 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7997 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7999 if (!strcmp(filepath, subtitle_uri)) {
8000 LOGD("subtitle path is not changed");
8003 if (mm_player_set_attribute((MMHandleType)player, NULL,
8004 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8005 LOGE("failed to set attribute");
8010 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8011 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8012 player->subtitle_language_list = NULL;
8013 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8015 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8016 if (ret != GST_STATE_CHANGE_SUCCESS) {
8017 LOGE("failed to change state of textbin to READY");
8018 result = MM_ERROR_PLAYER_INTERNAL;
8022 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8023 if (ret != GST_STATE_CHANGE_SUCCESS) {
8024 LOGE("failed to change state of subparse to READY");
8025 result = MM_ERROR_PLAYER_INTERNAL;
8029 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8030 if (ret != GST_STATE_CHANGE_SUCCESS) {
8031 LOGE("failed to change state of filesrc to READY");
8032 result = MM_ERROR_PLAYER_INTERNAL;
8036 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8038 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8040 charset = _mmplayer_get_charset(filepath);
8042 LOGD("detected charset is %s", charset);
8043 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8046 result = _mmplayer_sync_subtitle_pipeline(player);
8053 /* API to switch between external subtitles */
8055 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8057 int result = MM_ERROR_NONE;
8058 mmplayer_t *player = (mmplayer_t *)hplayer;
8063 /* check player handle */
8064 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8066 /* filepath can be null in idle state */
8068 /* check file path */
8069 if ((path = strstr(filepath, "file://")))
8070 result = _mmplayer_exist_file_path(path + 7);
8072 result = _mmplayer_exist_file_path(filepath);
8074 if (result != MM_ERROR_NONE) {
8075 LOGE("invalid subtitle path 0x%X", result);
8076 return result; /* file not found or permission denied */
8080 if (!player->pipeline) {
8082 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8083 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8084 LOGE("failed to set attribute");
8085 return MM_ERROR_PLAYER_INTERNAL;
8088 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8089 /* check filepath */
8090 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8092 if (!__mmplayer_check_subtitle(player)) {
8093 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8094 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8095 LOGE("failed to set attribute");
8096 return MM_ERROR_PLAYER_INTERNAL;
8099 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8100 LOGE("fail to create text pipeline");
8101 return MM_ERROR_PLAYER_INTERNAL;
8104 result = _mmplayer_sync_subtitle_pipeline(player);
8106 result = __mmplayer_change_external_subtitle_language(player, filepath);
8109 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8110 player->is_external_subtitle_added_now = TRUE;
8112 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8113 if (!player->subtitle_language_list) {
8114 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8115 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8116 LOGW("subtitle language list is not updated yet");
8118 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8126 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8128 int result = MM_ERROR_NONE;
8129 gchar *change_pad_name = NULL;
8130 GstPad *sinkpad = NULL;
8131 mmplayer_gst_element_t *mainbin = NULL;
8132 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8133 GstCaps *caps = NULL;
8134 gint total_track_num = 0;
8138 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8139 MM_ERROR_PLAYER_NOT_INITIALIZED);
8141 LOGD("Change Track(%d) to %d", type, index);
8143 mainbin = player->pipeline->mainbin;
8145 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8146 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8147 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8148 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8150 /* Changing Video Track is not supported. */
8151 LOGE("Track Type Error");
8155 if (mainbin[elem_idx].gst == NULL) {
8156 result = MM_ERROR_PLAYER_NO_OP;
8157 LOGD("Req track doesn't exist");
8161 total_track_num = player->selector[type].total_track_num;
8162 if (total_track_num <= 0) {
8163 result = MM_ERROR_PLAYER_NO_OP;
8164 LOGD("Language list is not available");
8168 if ((index < 0) || (index >= total_track_num)) {
8169 result = MM_ERROR_INVALID_ARGUMENT;
8170 LOGD("Not a proper index : %d", index);
8174 /*To get the new pad from the selector*/
8175 change_pad_name = g_strdup_printf("sink_%u", index);
8176 if (change_pad_name == NULL) {
8177 result = MM_ERROR_PLAYER_INTERNAL;
8178 LOGD("Pad does not exists");
8182 LOGD("new active pad name: %s", change_pad_name);
8184 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8185 if (sinkpad == NULL) {
8186 LOGD("sinkpad is NULL");
8187 result = MM_ERROR_PLAYER_INTERNAL;
8191 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8192 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8194 caps = gst_pad_get_current_caps(sinkpad);
8195 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8198 gst_object_unref(sinkpad);
8200 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8201 __mmplayer_set_audio_attrs(player, caps);
8204 MMPLAYER_FREEIF(change_pad_name);
8209 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8211 int result = MM_ERROR_NONE;
8212 mmplayer_t *player = NULL;
8213 mmplayer_gst_element_t *mainbin = NULL;
8215 gint current_active_index = 0;
8217 GstState current_state = GST_STATE_VOID_PENDING;
8218 GstEvent *event = NULL;
8223 player = (mmplayer_t *)hplayer;
8224 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8226 if (!player->pipeline) {
8227 LOGE("Track %d pre setting -> %d", type, index);
8229 player->selector[type].active_pad_index = index;
8233 mainbin = player->pipeline->mainbin;
8235 current_active_index = player->selector[type].active_pad_index;
8237 /*If index is same as running index no need to change the pad*/
8238 if (current_active_index == index)
8241 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8242 result = MM_ERROR_PLAYER_INVALID_STATE;
8246 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8247 if (current_state < GST_STATE_PAUSED) {
8248 result = MM_ERROR_PLAYER_INVALID_STATE;
8249 LOGW("Pipeline not in porper state");
8253 result = __mmplayer_change_selector_pad(player, type, index);
8254 if (result != MM_ERROR_NONE) {
8255 LOGE("change selector pad error");
8259 player->selector[type].active_pad_index = index;
8261 if (current_state == GST_STATE_PLAYING) {
8262 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8263 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8264 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8266 _mmplayer_gst_send_event_to_sink(player, event);
8268 result = MM_ERROR_PLAYER_INTERNAL;
8278 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8280 mmplayer_t *player = (mmplayer_t *)hplayer;
8284 /* check player handle */
8285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8287 *silent = player->set_mode.subtitle_off;
8289 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8293 return MM_ERROR_NONE;
8297 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8299 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8300 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8302 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8303 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8307 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8308 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8309 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8310 mmplayer_dump_t *dump_s;
8311 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8312 if (dump_s == NULL) {
8313 LOGE("malloc fail");
8317 dump_s->dump_element_file = NULL;
8318 dump_s->dump_pad = NULL;
8319 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8321 if (dump_s->dump_pad) {
8322 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8323 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]);
8324 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8325 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);
8326 /* add list for removed buffer probe and close FILE */
8327 player->dump_list = g_list_append(player->dump_list, dump_s);
8328 LOGD("%s sink pad added buffer probe for dump", factory_name);
8331 MMPLAYER_FREEIF(dump_s);
8332 LOGE("failed to get %s sink pad added", factory_name);
8339 static GstPadProbeReturn
8340 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8342 FILE *dump_data = (FILE *)u_data;
8344 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8345 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8347 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8349 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8351 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8353 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8355 gst_buffer_unmap(buffer, &probe_info);
8357 return GST_PAD_PROBE_OK;
8361 __mmplayer_release_dump_list(GList *dump_list)
8363 GList *d_list = dump_list;
8368 for (; d_list; d_list = g_list_next(d_list)) {
8369 mmplayer_dump_t *dump_s = d_list->data;
8370 if (dump_s->dump_pad) {
8371 if (dump_s->probe_handle_id)
8372 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8373 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8375 if (dump_s->dump_element_file) {
8376 fclose(dump_s->dump_element_file);
8377 dump_s->dump_element_file = NULL;
8379 MMPLAYER_FREEIF(dump_s);
8381 g_list_free(dump_list);
8386 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8388 mmplayer_t *player = (mmplayer_t *)hplayer;
8392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8393 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8395 *exist = (bool)player->has_closed_caption;
8399 return MM_ERROR_NONE;
8403 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8408 LOGD("unref internal gst buffer %p", buffer);
8410 gst_buffer_unref((GstBuffer *)buffer);
8417 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8419 mmplayer_t *player = (mmplayer_t *)hplayer;
8423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8424 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8426 if (MMPLAYER_IS_STREAMING(player))
8427 *timeout = (int)player->ini.live_state_change_timeout;
8429 *timeout = (int)player->ini.localplayback_state_change_timeout;
8431 LOGD("timeout = %d", *timeout);
8434 return MM_ERROR_NONE;
8438 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8442 MMPLAYER_RETURN_IF_FAIL(player);
8444 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8446 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8447 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8448 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8449 player->storage_info[i].id = -1;
8450 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8452 if (path_type != MMPLAYER_PATH_MAX)
8461 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8463 int ret = MM_ERROR_NONE;
8464 mmplayer_t *player = (mmplayer_t *)hplayer;
8465 MMMessageParamType msg_param = {0, };
8468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8470 LOGW("state changed storage %d:%d", id, state);
8472 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8473 return MM_ERROR_NONE;
8475 /* FIXME: text path should be handled seperately. */
8476 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8477 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8478 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8479 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8480 LOGW("external storage is removed");
8482 if (player->msg_posted == FALSE) {
8483 memset(&msg_param, 0, sizeof(MMMessageParamType));
8484 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8485 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8486 player->msg_posted = TRUE;
8489 /* unrealize the player */
8490 ret = _mmplayer_unrealize(hplayer);
8491 if (ret != MM_ERROR_NONE)
8492 LOGE("failed to unrealize");
8500 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8502 int ret = MM_ERROR_NONE;
8503 mmplayer_t *player = (mmplayer_t *)hplayer;
8504 int idx = 0, total = 0;
8505 gchar *result = NULL, *tmp = NULL;
8508 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8509 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8511 total = *num = g_list_length(player->adaptive_info.var_list);
8513 LOGW("There is no stream variant info.");
8517 result = g_strdup("");
8518 for (idx = 0 ; idx < total ; idx++) {
8519 stream_variant_t *v_data = NULL;
8520 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8523 gchar data[64] = {0};
8524 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8526 tmp = g_strconcat(result, data, NULL);
8530 LOGW("There is no variant data in %d", idx);
8535 *var_info = (char *)result;
8537 LOGD("variant info %d:%s", *num, *var_info);
8543 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8545 int ret = MM_ERROR_NONE;
8546 mmplayer_t *player = (mmplayer_t *)hplayer;
8549 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8551 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8553 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8554 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8555 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8557 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8558 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8559 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8560 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8562 /* FIXME: seek to current position for applying new variant limitation */
8571 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8573 int ret = MM_ERROR_NONE;
8574 mmplayer_t *player = (mmplayer_t *)hplayer;
8577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8578 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8580 *bandwidth = player->adaptive_info.limit.bandwidth;
8581 *width = player->adaptive_info.limit.width;
8582 *height = player->adaptive_info.limit.height;
8584 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8591 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8593 int ret = MM_ERROR_NONE;
8594 mmplayer_t *player = (mmplayer_t *)hplayer;
8597 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8598 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8599 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8601 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8603 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8604 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8605 else /* live case */
8606 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8608 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8615 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8617 #define IDX_FIRST_SW_CODEC 0
8618 mmplayer_t *player = (mmplayer_t *)hplayer;
8619 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8624 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8625 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8626 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8628 switch (stream_type) {
8629 case MM_PLAYER_STREAM_TYPE_AUDIO:
8630 /* to support audio codec selection, codec info have to be added in ini file as below.
8631 audio codec element hw = xxxx
8632 audio codec element sw = avdec
8633 and in case of audio hw codec is supported and selected,
8634 audio filter elements should be applied depending on the hw capabilities.
8636 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8637 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8638 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8639 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8640 LOGE("There is no audio codec info for codec_type %d", codec_type);
8641 return MM_ERROR_PLAYER_NO_OP;
8644 case MM_PLAYER_STREAM_TYPE_VIDEO:
8645 /* to support video codec selection, codec info have to be added in ini file as below.
8646 video codec element hw = omx
8647 video codec element sw = avdec */
8648 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8649 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8650 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8651 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8652 LOGE("There is no video codec info for codec_type %d", codec_type);
8653 return MM_ERROR_PLAYER_NO_OP;
8657 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8658 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8662 LOGD("update %s codec_type to %d", attr_name, codec_type);
8663 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8666 return MM_ERROR_NONE;
8670 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8672 mmplayer_t *player = (mmplayer_t *)hplayer;
8673 GstElement *rg_vol_element = NULL;
8677 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8679 player->sound.rg_enable = enabled;
8681 /* just hold rgvolume enable value if pipeline is not ready */
8682 if (!player->pipeline || !player->pipeline->audiobin) {
8683 LOGD("pipeline is not ready. holding rgvolume enable value");
8684 return MM_ERROR_NONE;
8687 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8689 if (!rg_vol_element) {
8690 LOGD("rgvolume element is not created");
8691 return MM_ERROR_PLAYER_INTERNAL;
8695 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8697 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8701 return MM_ERROR_NONE;
8705 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8707 mmplayer_t *player = (mmplayer_t *)hplayer;
8708 GstElement *rg_vol_element = NULL;
8709 gboolean enable = FALSE;
8713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8714 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8716 /* just hold enable_rg value if pipeline is not ready */
8717 if (!player->pipeline || !player->pipeline->audiobin) {
8718 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8719 *enabled = player->sound.rg_enable;
8720 return MM_ERROR_NONE;
8723 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8725 if (!rg_vol_element) {
8726 LOGD("rgvolume element is not created");
8727 return MM_ERROR_PLAYER_INTERNAL;
8730 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8731 *enabled = (bool)enable;
8735 return MM_ERROR_NONE;
8739 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8741 mmplayer_t *player = (mmplayer_t *)hplayer;
8742 MMHandleType attrs = 0;
8744 int ret = MM_ERROR_NONE;
8748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8750 attrs = MMPLAYER_GET_ATTRS(player);
8751 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8753 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8755 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8756 return MM_ERROR_PLAYER_INTERNAL;
8759 player->video_roi.scale_x = scale_x;
8760 player->video_roi.scale_y = scale_y;
8761 player->video_roi.scale_width = scale_width;
8762 player->video_roi.scale_height = scale_height;
8764 /* check video sinkbin is created */
8765 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8766 return MM_ERROR_NONE;
8768 if (!gst_video_overlay_set_video_roi_area(
8769 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8770 scale_x, scale_y, scale_width, scale_height))
8771 ret = MM_ERROR_PLAYER_INTERNAL;
8773 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8774 scale_x, scale_y, scale_width, scale_height);
8782 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8784 mmplayer_t *player = (mmplayer_t *)hplayer;
8785 int ret = MM_ERROR_NONE;
8789 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8790 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8792 *scale_x = player->video_roi.scale_x;
8793 *scale_y = player->video_roi.scale_y;
8794 *scale_width = player->video_roi.scale_width;
8795 *scale_height = player->video_roi.scale_height;
8797 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8798 *scale_x, *scale_y, *scale_width, *scale_height);
8804 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8806 mmplayer_t *player = (mmplayer_t *)hplayer;
8810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812 player->client_pid = pid;
8814 LOGD("client pid[%d] %p", pid, player);
8818 return MM_ERROR_NONE;
8822 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8824 mmplayer_t *player = (mmplayer_t *)hplayer;
8825 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8826 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8831 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8834 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8836 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8838 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8839 return MM_ERROR_NONE;
8841 /* in case of audio codec default type is HW */
8843 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8844 if (player->ini.support_audio_effect)
8845 return MM_ERROR_NONE;
8846 elem_id = MMPLAYER_A_FILTER;
8848 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8849 if (player->ini.support_replaygain_control)
8850 return MM_ERROR_NONE;
8851 elem_id = MMPLAYER_A_RGVOL;
8853 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8854 if (player->ini.support_pitch_control)
8855 return MM_ERROR_NONE;
8856 elem_id = MMPLAYER_A_PITCH;
8858 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8859 if (player->ini.support_audio_effect)
8860 return MM_ERROR_NONE;
8862 /* default case handling is not required */
8865 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8866 LOGW("audio control option [%d] is not available", opt);
8869 /* setting pcm exporting option is allowed before READY state */
8870 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8871 return MM_ERROR_PLAYER_INVALID_STATE;
8873 /* check whether the audio filter exist or not after READY state,
8874 because the sw codec could be added during auto-plugging in some cases */
8875 if (!player->pipeline ||
8876 !player->pipeline->audiobin ||
8877 !player->pipeline->audiobin[elem_id].gst) {
8878 LOGW("there is no audio elem [%d]", elem_id);
8883 LOGD("audio control opt %d, available %d", opt, *available);
8887 return MM_ERROR_NONE;
8891 __mmplayer_update_duration_value(mmplayer_t *player)
8893 gboolean ret = FALSE;
8894 gint64 dur_nsec = 0;
8895 LOGD("try to update duration");
8897 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8898 player->duration = dur_nsec;
8899 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8903 if (player->duration < 0) {
8904 LOGW("duration is Non-Initialized !!!");
8905 player->duration = 0;
8908 /* update streaming service type */
8909 player->streaming_type = _mmplayer_get_stream_service_type(player);
8911 /* check duration is OK */
8912 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8913 /* FIXIT : find another way to get duration here. */
8914 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8920 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8922 /* update audio params
8923 NOTE : We need original audio params and it can be only obtained from src pad of audio
8924 decoder. Below code only valid when we are not using 'resampler' just before
8925 'audioconverter'. */
8926 GstCaps *caps_a = NULL;
8928 gint samplerate = 0, channels = 0;
8929 GstStructure *p = NULL;
8930 GstElement *aconv = NULL;
8932 LOGD("try to update audio attrs");
8934 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8936 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8937 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8938 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8939 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8941 LOGE("there is no audio converter");
8945 pad = gst_element_get_static_pad(aconv, "sink");
8948 LOGW("failed to get pad from audio converter");
8952 caps_a = gst_pad_get_current_caps(pad);
8954 LOGW("not ready to get audio caps");
8955 gst_object_unref(pad);
8959 p = gst_caps_get_structure(caps_a, 0);
8961 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8963 gst_structure_get_int(p, "rate", &samplerate);
8964 gst_structure_get_int(p, "channels", &channels);
8966 mm_player_set_attribute((MMHandleType)player, NULL,
8967 "content_audio_samplerate", samplerate,
8968 "content_audio_channels", channels, NULL);
8970 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8972 gst_caps_unref(caps_a);
8973 gst_object_unref(pad);
8979 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8981 LOGD("try to update video attrs");
8983 GstCaps *caps_v = NULL;
8987 GstStructure *p = NULL;
8989 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8990 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8992 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8994 LOGD("no videosink sink pad");
8998 caps_v = gst_pad_get_current_caps(pad);
8999 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9000 if (!caps_v && player->v_stream_caps) {
9001 caps_v = player->v_stream_caps;
9002 gst_caps_ref(caps_v);
9006 LOGD("no negitiated caps from videosink");
9007 gst_object_unref(pad);
9011 p = gst_caps_get_structure(caps_v, 0);
9012 gst_structure_get_int(p, "width", &width);
9013 gst_structure_get_int(p, "height", &height);
9015 mm_player_set_attribute((MMHandleType)player, NULL,
9016 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9018 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9020 SECURE_LOGD("width : %d height : %d", width, height);
9022 gst_caps_unref(caps_v);
9023 gst_object_unref(pad);
9026 mm_player_set_attribute((MMHandleType)player, NULL,
9027 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9028 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9035 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9037 gboolean ret = FALSE;
9038 guint64 data_size = 0;
9042 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9043 if (!player->duration)
9046 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9047 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9048 if (stat(path, &sb) == 0)
9049 data_size = (guint64)sb.st_size;
9051 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9052 data_size = player->http_content_size;
9055 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9058 guint64 bitrate = 0;
9059 guint64 msec_dur = 0;
9061 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9063 bitrate = data_size * 8 * 1000 / msec_dur;
9064 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9065 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9066 mm_player_set_attribute((MMHandleType)player, NULL,
9067 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9070 LOGD("player duration is less than 0");
9074 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9075 if (player->total_bitrate) {
9076 mm_player_set_attribute((MMHandleType)player, NULL,
9077 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9086 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9088 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9089 data->uri_type = uri_type;
9093 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9095 int ret = MM_ERROR_PLAYER_INVALID_URI;
9097 char *buffer = NULL;
9098 char *seperator = strchr(path, ',');
9099 char ext[100] = {0,}, size[100] = {0,};
9102 if ((buffer = strstr(path, "ext="))) {
9103 buffer += strlen("ext=");
9105 if (strlen(buffer)) {
9106 strncpy(ext, buffer, 99);
9108 if ((seperator = strchr(ext, ','))
9109 || (seperator = strchr(ext, ' '))
9110 || (seperator = strchr(ext, '\0'))) {
9111 seperator[0] = '\0';
9116 if ((buffer = strstr(path, "size="))) {
9117 buffer += strlen("size=");
9119 if (strlen(buffer) > 0) {
9120 strncpy(size, buffer, 99);
9122 if ((seperator = strchr(size, ','))
9123 || (seperator = strchr(size, ' '))
9124 || (seperator = strchr(size, '\0'))) {
9125 seperator[0] = '\0';
9128 mem_size = atoi(size);
9133 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9135 if (mem_size && param) {
9136 if (data->input_mem.buf)
9137 free(data->input_mem.buf);
9138 data->input_mem.buf = malloc(mem_size);
9140 if (data->input_mem.buf) {
9141 memcpy(data->input_mem.buf, param, mem_size);
9142 data->input_mem.len = mem_size;
9143 ret = MM_ERROR_NONE;
9145 LOGE("failed to alloc mem %d", mem_size);
9146 ret = MM_ERROR_PLAYER_INTERNAL;
9149 data->input_mem.offset = 0;
9150 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9157 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9159 gchar *location = NULL;
9162 int ret = MM_ERROR_NONE;
9164 if ((path = strstr(uri, "file://"))) {
9165 location = g_filename_from_uri(uri, NULL, &err);
9166 if (!location || (err != NULL)) {
9167 LOGE("Invalid URI '%s' for filesrc: %s", path,
9168 (err != NULL) ? err->message : "unknown error");
9172 MMPLAYER_FREEIF(location);
9174 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9175 return MM_ERROR_PLAYER_INVALID_URI;
9177 LOGD("path from uri: %s", location);
9180 path = (location != NULL) ? (location) : ((char *)uri);
9183 ret = _mmplayer_exist_file_path(path);
9185 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9186 if (ret == MM_ERROR_NONE) {
9187 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9188 if (_mmplayer_is_sdp_file(path)) {
9189 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9190 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9192 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9194 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9195 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9197 LOGE("invalid uri, could not play..");
9198 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9201 MMPLAYER_FREEIF(location);
9206 static mmplayer_video_decoded_data_info_t *
9207 __mmplayer_create_stream_from_pad(GstPad *pad)
9209 GstCaps *caps = NULL;
9210 GstStructure *structure = NULL;
9211 unsigned int fourcc = 0;
9212 const gchar *string_format = NULL;
9213 mmplayer_video_decoded_data_info_t *stream = NULL;
9215 MMPixelFormatType format;
9218 caps = gst_pad_get_current_caps(pad);
9220 LOGE("Caps is NULL.");
9225 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9227 structure = gst_caps_get_structure(caps, 0);
9228 gst_structure_get_int(structure, "width", &width);
9229 gst_structure_get_int(structure, "height", &height);
9230 string_format = gst_structure_get_string(structure, "format");
9233 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9234 format = _mmplayer_get_pixtype(fourcc);
9235 gst_video_info_from_caps(&info, caps);
9236 gst_caps_unref(caps);
9239 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9240 LOGE("Wrong condition!!");
9244 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9246 LOGE("failed to alloc mem for video data");
9250 stream->width = width;
9251 stream->height = height;
9252 stream->format = format;
9253 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9259 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9261 unsigned int pitch = 0;
9262 unsigned int size = 0;
9264 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9267 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9268 bo = gst_tizen_memory_get_bos(mem, index);
9270 stream->bo[index] = tbm_bo_ref(bo);
9272 LOGE("failed to get bo for index %d", index);
9275 for (index = 0; index < stream->plane_num; index++) {
9276 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9277 stream->stride[index] = pitch;
9279 stream->elevation[index] = size / pitch;
9281 stream->elevation[index] = stream->height;
9286 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9288 if (stream->format == MM_PIXEL_FORMAT_I420) {
9289 int ret = TBM_SURFACE_ERROR_NONE;
9290 tbm_surface_h surface;
9291 tbm_surface_info_s info;
9293 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9295 ret = tbm_surface_get_info(surface, &info);
9296 if (ret != TBM_SURFACE_ERROR_NONE) {
9297 tbm_surface_destroy(surface);
9301 tbm_surface_destroy(surface);
9302 stream->stride[0] = info.planes[0].stride;
9303 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9304 stream->stride[1] = info.planes[1].stride;
9305 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9306 stream->stride[2] = info.planes[2].stride;
9307 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9308 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9309 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9310 stream->stride[0] = stream->width * 4;
9311 stream->elevation[0] = stream->height;
9312 stream->bo_size = stream->stride[0] * stream->height;
9314 LOGE("Not support format %d", stream->format);
9322 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9324 tbm_bo_handle thandle;
9326 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9327 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9328 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9332 unsigned char *src = NULL;
9333 unsigned char *dest = NULL;
9334 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9336 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9338 LOGE("fail to gst_memory_map");
9342 if (!mapinfo.data) {
9343 LOGE("data pointer is wrong");
9347 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9348 if (!stream->bo[0]) {
9349 LOGE("Fail to tbm_bo_alloc!!");
9353 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9355 LOGE("thandle pointer is wrong");
9359 if (stream->format == MM_PIXEL_FORMAT_I420) {
9360 src_stride[0] = GST_ROUND_UP_4(stream->width);
9361 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9362 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9363 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9366 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9367 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9369 for (i = 0; i < 3; i++) {
9370 src = mapinfo.data + src_offset[i];
9371 dest = thandle.ptr + dest_offset[i];
9376 for (j = 0; j < stream->height >> k; j++) {
9377 memcpy(dest, src, stream->width>>k);
9378 src += src_stride[i];
9379 dest += stream->stride[i];
9382 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9383 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9385 LOGE("Not support format %d", stream->format);
9389 tbm_bo_unmap(stream->bo[0]);
9390 gst_memory_unmap(mem, &mapinfo);
9396 tbm_bo_unmap(stream->bo[0]);
9399 gst_memory_unmap(mem, &mapinfo);
9405 __mmplayer_set_pause_state(mmplayer_t *player)
9407 if (player->sent_bos)
9410 /* rtsp case, get content attrs by GstMessage */
9411 if (MMPLAYER_IS_RTSP_STREAMING(player))
9414 /* it's first time to update all content attrs. */
9415 _mmplayer_update_content_attrs(player, ATTR_ALL);
9419 __mmplayer_set_playing_state(mmplayer_t *player)
9421 gchar *audio_codec = NULL;
9423 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9424 /* initialize because auto resume is done well. */
9425 player->resumed_by_rewind = FALSE;
9426 player->playback_rate = 1.0;
9429 if (player->sent_bos)
9432 /* try to get content metadata */
9434 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9435 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9436 * legacy mmfw-player api
9438 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9440 if ((player->cmd == MMPLAYER_COMMAND_START)
9441 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9442 __mmplayer_handle_missed_plugin(player);
9445 /* check audio codec field is set or not
9446 * we can get it from typefinder or codec's caps.
9448 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9450 /* The codec format can't be sent for audio only case like amr, mid etc.
9451 * Because, parser don't make related TAG.
9452 * So, if it's not set yet, fill it with found data.
9455 if (g_strrstr(player->type, "audio/midi"))
9456 audio_codec = "MIDI";
9457 else if (g_strrstr(player->type, "audio/x-amr"))
9458 audio_codec = "AMR";
9459 else if (g_strrstr(player->type, "audio/mpeg")
9460 && !g_strrstr(player->type, "mpegversion=(int)1"))
9461 audio_codec = "AAC";
9463 audio_codec = "unknown";
9465 if (mm_player_set_attribute((MMHandleType)player, NULL,
9466 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9467 LOGE("failed to set attribute");
9469 LOGD("set audio codec type with caps");