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_VAL_IF_FAIL(player && player->pipeline &&
2567 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2569 audiobin = player->pipeline->audiobin;
2571 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2572 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2573 LOGE("failed to create media stream info");
2574 return MM_ERROR_PLAYER_INTERNAL;
2577 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2579 if (player->video360_yaw_radians <= M_PI &&
2580 player->video360_yaw_radians >= -M_PI &&
2581 player->video360_pitch_radians <= M_PI_2 &&
2582 player->video360_pitch_radians >= -M_PI_2) {
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2584 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2585 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2586 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2587 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2588 "source-orientation-y", player->video360_metadata.init_view_heading,
2589 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2593 return MM_ERROR_NONE;
2597 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2599 mmplayer_gst_element_t *audiobin = NULL;
2600 GstPad *sink_pad = NULL;
2601 GstCaps *acaps = NULL;
2603 int pitch_control = 0;
2604 double pitch_value = 1.0;
2607 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2608 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2610 audiobin = player->pipeline->audiobin;
2612 LOGD("make element for normal audio playback");
2614 /* audio bin structure for playback. {} means optional.
2615 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2617 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2618 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2621 /* for pitch control */
2622 mm_attrs_multiple_get(player->attrs, NULL,
2623 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2624 MM_PLAYER_PITCH_VALUE, &pitch_value,
2627 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2628 if (pitch_control && (player->videodec_linked == 0)) {
2629 GstElementFactory *factory;
2631 factory = gst_element_factory_find("pitch");
2633 gst_object_unref(factory);
2636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2639 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2640 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2642 LOGW("there is no pitch element");
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2649 /* replaygain volume */
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2651 if (player->sound.rg_enable)
2652 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2654 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2657 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2659 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2660 /* currently, only openalsink uses volume element */
2661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2664 if (player->sound.mute) {
2665 LOGD("mute enabled");
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2670 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2672 /* audio effect element. if audio effect is enabled */
2673 if ((strcmp(player->ini.audioeffect_element, ""))
2675 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2676 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2678 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2680 if ((!player->bypass_audio_effect)
2681 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2682 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2683 if (!_mmplayer_audio_effect_custom_apply(player))
2684 LOGI("apply audio effect(custom) setting success");
2688 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2689 && (player->set_mode.rich_audio)) {
2690 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2694 /* create audio sink */
2695 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2696 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2697 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2699 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2700 if (player->is_360_feature_enabled &&
2701 player->is_content_spherical &&
2703 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2704 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2705 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2707 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2712 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2713 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2714 gst_caps_unref(acaps);
2716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2718 player->is_openal_plugin_used = TRUE;
2720 if (player->is_360_feature_enabled && player->is_content_spherical)
2721 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2725 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2726 (player->videodec_linked && player->ini.use_system_clock)) {
2727 LOGD("system clock will be used.");
2728 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2731 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2732 __mmplayer_gst_set_pulsesink_property(player);
2733 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2734 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2739 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2740 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2742 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2743 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2744 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2745 gst_object_unref(GST_OBJECT(sink_pad));
2747 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2750 return MM_ERROR_NONE;
2752 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2754 return MM_ERROR_PLAYER_INTERNAL;
2758 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2760 mmplayer_gst_element_t *audiobin = NULL;
2761 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2763 gchar *dst_format = NULL;
2765 int dst_samplerate = 0;
2766 int dst_channels = 0;
2767 GstCaps *caps = NULL;
2768 char *caps_str = NULL;
2771 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2772 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2774 audiobin = player->pipeline->audiobin;
2776 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2778 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2780 [case 1] extract interleave audio pcm without playback
2781 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2782 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2784 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2786 [case 2] deinterleave for each channel without playback
2787 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2788 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2790 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2791 - fakesink (sync or not)
2794 [case 3] [case 1(sync only)] + playback
2795 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2797 * src - ... - tee - queue1 - playback path
2798 - queue2 - [case1 pipeline with sync]
2800 [case 4] [case 2(sync only)] + playback
2801 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2803 * src - ... - tee - queue1 - playback path
2804 - queue2 - [case2 pipeline with sync]
2808 /* 1. create tee and playback path
2809 'tee' should be added at first to copy the decoded stream
2811 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2812 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2813 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2815 /* tee - path 1 : for playback path */
2816 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2817 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2819 /* tee - path 2 : for extract path */
2820 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2821 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2824 /* if there is tee, 'tee - path 2' is linked here */
2826 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2829 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2831 /* 2. decide the extract pcm format */
2832 mm_attrs_multiple_get(player->attrs, NULL,
2833 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2834 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2835 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2838 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2839 dst_format, dst_len, dst_samplerate, dst_channels);
2841 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2842 mm_attrs_multiple_get(player->attrs, NULL,
2843 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2844 "content_audio_samplerate", &dst_samplerate,
2845 "content_audio_channels", &dst_channels,
2848 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2849 dst_format, dst_len, dst_samplerate, dst_channels);
2851 /* If there is no enough information, set it to platform default value. */
2852 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2853 LOGD("set platform default format");
2854 dst_format = DEFAULT_PCM_OUT_FORMAT;
2856 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2857 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2860 /* 3. create capsfilter */
2861 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2862 caps = gst_caps_new_simple("audio/x-raw",
2863 "format", G_TYPE_STRING, dst_format,
2864 "rate", G_TYPE_INT, dst_samplerate,
2865 "channels", G_TYPE_INT, dst_channels,
2868 caps_str = gst_caps_to_string(caps);
2869 LOGD("new caps : %s", caps_str);
2871 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2874 gst_caps_unref(caps);
2875 MMPLAYER_FREEIF(caps_str);
2877 /* 4-1. create deinterleave to extract pcm for each channel */
2878 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2879 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2880 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2882 /* audiosink will be added after getting signal for each channel */
2883 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2884 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2885 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2886 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2887 player->no_more_pad = FALSE;
2889 /* 4-2. create fakesink to extract interlevaed pcm */
2890 LOGD("add audio fakesink for interleaved audio");
2891 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2892 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2893 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2894 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2896 _mmplayer_add_signal_connection(player,
2897 G_OBJECT(audiobin[extract_sink_id].gst),
2898 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2900 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2903 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2907 return MM_ERROR_NONE;
2909 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2911 return MM_ERROR_PLAYER_INTERNAL;
2915 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2917 int ret = MM_ERROR_NONE;
2918 mmplayer_gst_element_t *audiobin = NULL;
2919 GList *element_bucket = NULL;
2922 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2923 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2925 audiobin = player->pipeline->audiobin;
2927 if (player->build_audio_offload) { /* skip all the audio filters */
2928 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2930 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2931 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2932 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2934 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2938 /* FIXME: need to mention the supportable condition at API reference */
2939 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2940 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2942 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2944 if (ret != MM_ERROR_NONE)
2947 LOGD("success to make audio bin element");
2948 *bucket = element_bucket;
2951 return MM_ERROR_NONE;
2954 LOGE("failed to make audio bin element");
2955 g_list_free(element_bucket);
2959 return MM_ERROR_PLAYER_INTERNAL;
2963 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2965 mmplayer_gst_element_t *first_element = NULL;
2966 mmplayer_gst_element_t *audiobin = NULL;
2968 GstPad *ghostpad = NULL;
2969 GList *element_bucket = NULL;
2973 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2976 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2978 LOGE("failed to allocate memory for audiobin");
2979 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2983 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2984 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2985 if (!audiobin[MMPLAYER_A_BIN].gst) {
2986 LOGE("failed to create audiobin");
2991 player->pipeline->audiobin = audiobin;
2993 /* create audio filters and audiosink */
2994 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2997 /* adding created elements to bin */
2998 LOGD("adding created elements to bin");
2999 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3002 /* linking elements in the bucket by added order. */
3003 LOGD("Linking elements in the bucket by added order.");
3004 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3007 /* get first element's sinkpad for creating ghostpad */
3008 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3009 if (!first_element) {
3010 LOGE("failed to get first elem");
3014 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3016 LOGE("failed to get pad from first element of audiobin");
3020 ghostpad = gst_ghost_pad_new("sink", pad);
3022 LOGE("failed to create ghostpad");
3026 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3027 LOGE("failed to add ghostpad to audiobin");
3031 gst_object_unref(pad);
3033 g_list_free(element_bucket);
3036 return MM_ERROR_NONE;
3039 LOGD("ERROR : releasing audiobin");
3042 gst_object_unref(GST_OBJECT(pad));
3045 gst_object_unref(GST_OBJECT(ghostpad));
3048 g_list_free(element_bucket);
3050 /* release element which are not added to bin */
3051 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3052 /* NOTE : skip bin */
3053 if (audiobin[i].gst) {
3054 GstObject *parent = NULL;
3055 parent = gst_element_get_parent(audiobin[i].gst);
3058 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3059 audiobin[i].gst = NULL;
3061 gst_object_unref(GST_OBJECT(parent));
3065 /* release audiobin with it's childs */
3066 if (audiobin[MMPLAYER_A_BIN].gst)
3067 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3069 MMPLAYER_FREEIF(audiobin);
3071 player->pipeline->audiobin = NULL;
3073 return MM_ERROR_PLAYER_INTERNAL;
3077 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3079 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3083 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3085 int ret = MM_ERROR_NONE;
3087 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3088 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3090 MMPLAYER_VIDEO_BO_LOCK(player);
3092 if (player->video_bo_list) {
3093 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3094 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3095 if (tmp && tmp->bo == bo) {
3097 LOGD("release bo %p", bo);
3098 tbm_bo_unref(tmp->bo);
3099 MMPLAYER_VIDEO_BO_UNLOCK(player);
3100 MMPLAYER_VIDEO_BO_SIGNAL(player);
3105 /* hw codec is running or the list was reset for DRC. */
3106 LOGW("there is no bo list.");
3108 MMPLAYER_VIDEO_BO_UNLOCK(player);
3110 LOGW("failed to find bo %p", bo);
3115 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3120 MMPLAYER_RETURN_IF_FAIL(player);
3122 MMPLAYER_VIDEO_BO_LOCK(player);
3123 if (player->video_bo_list) {
3124 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3125 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3126 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3129 tbm_bo_unref(tmp->bo);
3133 g_list_free(player->video_bo_list);
3134 player->video_bo_list = NULL;
3136 player->video_bo_size = 0;
3137 MMPLAYER_VIDEO_BO_UNLOCK(player);
3144 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3147 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3148 gboolean ret = TRUE;
3150 /* check DRC, if it is, destroy the prev bo list to create again */
3151 if (player->video_bo_size != size) {
3152 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3153 __mmplayer_video_stream_destroy_bo_list(player);
3154 player->video_bo_size = size;
3157 MMPLAYER_VIDEO_BO_LOCK(player);
3159 if ((!player->video_bo_list) ||
3160 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3162 /* create bo list */
3164 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3166 if (player->video_bo_list) {
3167 /* if bo list did not created all, try it again. */
3168 idx = g_list_length(player->video_bo_list);
3169 LOGD("bo list exist(len: %d)", idx);
3172 for (; idx < player->ini.num_of_video_bo; idx++) {
3173 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3175 LOGE("Fail to alloc bo_info.");
3178 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3180 LOGE("Fail to tbm_bo_alloc.");
3181 MMPLAYER_FREEIF(bo_info);
3184 bo_info->used = FALSE;
3185 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3188 /* update video num buffers */
3189 LOGD("video_num_buffers : %d", idx);
3190 mm_player_set_attribute((MMHandleType)player, NULL,
3191 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3192 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3196 MMPLAYER_VIDEO_BO_UNLOCK(player);
3202 /* get bo from list*/
3203 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3204 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3205 if (tmp && (tmp->used == FALSE)) {
3206 LOGD("found bo %p to use", tmp->bo);
3208 MMPLAYER_VIDEO_BO_UNLOCK(player);
3209 return tbm_bo_ref(tmp->bo);
3213 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3214 MMPLAYER_VIDEO_BO_UNLOCK(player);
3218 if (player->ini.video_bo_timeout <= 0) {
3219 MMPLAYER_VIDEO_BO_WAIT(player);
3221 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3222 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3229 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3231 mmplayer_t *player = (mmplayer_t *)data;
3233 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3235 /* send prerolled pkt */
3236 player->video_stream_prerolled = false;
3238 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3240 /* not to send prerolled pkt again */
3241 player->video_stream_prerolled = true;
3245 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3247 mmplayer_t *player = (mmplayer_t *)data;
3248 mmplayer_video_decoded_data_info_t *stream = NULL;
3249 GstMemory *mem = NULL;
3252 MMPLAYER_RETURN_IF_FAIL(player);
3253 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3255 if (player->video_stream_prerolled) {
3256 player->video_stream_prerolled = false;
3257 LOGD("skip the prerolled pkt not to send it again");
3261 /* clear stream data structure */
3262 stream = __mmplayer_create_stream_from_pad(pad);
3264 LOGE("failed to alloc stream");
3268 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3270 /* set size and timestamp */
3271 mem = gst_buffer_peek_memory(buffer, 0);
3272 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3273 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3275 /* check zero-copy */
3276 if (player->set_mode.video_zc &&
3277 player->set_mode.video_export &&
3278 gst_is_tizen_memory(mem)) {
3279 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3280 stream->internal_buffer = gst_buffer_ref(buffer);
3281 } else { /* sw codec */
3282 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3285 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3289 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3290 LOGE("failed to send video decoded data.");
3297 LOGE("release video stream resource.");
3298 if (gst_is_tizen_memory(mem)) {
3300 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3302 tbm_bo_unref(stream->bo[i]);
3305 /* unref gst buffer */
3306 if (stream->internal_buffer)
3307 gst_buffer_unref(stream->internal_buffer);
3310 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3312 MMPLAYER_FREEIF(stream);
3317 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3319 mmplayer_gst_element_t *videobin = NULL;
3322 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3324 videobin = player->pipeline->videobin;
3326 /* Set spatial media metadata and/or user settings to the element.
3328 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3329 "projection-type", player->video360_metadata.projection_type, NULL);
3331 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3332 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3334 if (player->video360_metadata.full_pano_width_pixels &&
3335 player->video360_metadata.full_pano_height_pixels &&
3336 player->video360_metadata.cropped_area_image_width &&
3337 player->video360_metadata.cropped_area_image_height) {
3338 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3339 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3340 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3341 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3342 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3343 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3344 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3348 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3349 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3350 "horizontal-fov", player->video360_horizontal_fov,
3351 "vertical-fov", player->video360_vertical_fov, NULL);
3354 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3355 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3356 "zoom", 1.0f / player->video360_zoom, NULL);
3359 if (player->video360_yaw_radians <= M_PI &&
3360 player->video360_yaw_radians >= -M_PI &&
3361 player->video360_pitch_radians <= M_PI_2 &&
3362 player->video360_pitch_radians >= -M_PI_2) {
3363 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3364 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3365 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3366 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3367 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3368 "pose-yaw", player->video360_metadata.init_view_heading,
3369 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3372 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3373 "passthrough", !player->is_video360_enabled, NULL);
3380 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3382 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3383 GList *element_bucket = NULL;
3386 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3388 /* create video360 filter */
3389 if (player->is_360_feature_enabled && player->is_content_spherical) {
3390 LOGD("create video360 element");
3391 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3392 __mmplayer_gst_set_video360_property(player);
3396 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3397 LOGD("skip creating the videoconv and rotator");
3398 return MM_ERROR_NONE;
3401 /* in case of sw codec & overlay surface type, except 360 playback.
3402 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3403 LOGD("create video converter: %s", video_csc);
3404 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3407 *bucket = element_bucket;
3409 return MM_ERROR_NONE;
3411 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3412 g_list_free(element_bucket);
3416 return MM_ERROR_PLAYER_INTERNAL;
3420 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3422 gchar *factory_name = NULL;
3424 switch (surface_type) {
3425 case MM_DISPLAY_SURFACE_OVERLAY:
3426 if (strlen(player->ini.videosink_element_overlay) > 0)
3427 factory_name = player->ini.videosink_element_overlay;
3429 case MM_DISPLAY_SURFACE_REMOTE:
3430 case MM_DISPLAY_SURFACE_NULL:
3431 if (strlen(player->ini.videosink_element_fake) > 0)
3432 factory_name = player->ini.videosink_element_fake;
3435 LOGE("unidentified surface type");
3439 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3440 return factory_name;
3444 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3446 gchar *factory_name = NULL;
3447 mmplayer_gst_element_t *videobin = NULL;
3452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3454 videobin = player->pipeline->videobin;
3455 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3457 attrs = MMPLAYER_GET_ATTRS(player);
3459 LOGE("cannot get content attribute");
3460 return MM_ERROR_PLAYER_INTERNAL;
3463 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3464 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3465 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3466 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3467 "use-tbm", use_tbm, NULL);
3470 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3471 return MM_ERROR_PLAYER_INTERNAL;
3473 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3476 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3477 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3480 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3482 LOGD("disable last-sample");
3483 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3486 if (player->set_mode.video_export) {
3488 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3489 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3490 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3492 _mmplayer_add_signal_connection(player,
3493 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3494 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3496 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3499 _mmplayer_add_signal_connection(player,
3500 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3501 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3503 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3507 if (videobin[MMPLAYER_V_SINK].gst) {
3508 GstPad *sink_pad = NULL;
3509 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3511 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3512 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3513 gst_object_unref(GST_OBJECT(sink_pad));
3515 LOGE("failed to get sink pad from videosink");
3519 return MM_ERROR_NONE;
3524 * - video overlay surface(arm/x86) : tizenwlsink
3527 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3530 GList *element_bucket = NULL;
3531 mmplayer_gst_element_t *first_element = NULL;
3532 mmplayer_gst_element_t *videobin = NULL;
3533 gchar *videosink_factory_name = NULL;
3536 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3539 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3541 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3543 player->pipeline->videobin = videobin;
3546 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3547 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3548 if (!videobin[MMPLAYER_V_BIN].gst) {
3549 LOGE("failed to create videobin");
3553 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3556 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3557 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3559 /* additional setting for sink plug-in */
3560 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3561 LOGE("failed to set video property");
3565 /* store it as it's sink element */
3566 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3568 /* adding created elements to bin */
3569 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3570 LOGE("failed to add elements");
3574 /* Linking elements in the bucket by added order */
3575 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3576 LOGE("failed to link elements");
3580 /* get first element's sinkpad for creating ghostpad */
3581 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3582 if (!first_element) {
3583 LOGE("failed to get first element from bucket");
3587 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3589 LOGE("failed to get pad from first element");
3593 /* create ghostpad */
3594 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3595 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3596 LOGE("failed to add ghostpad to videobin");
3599 gst_object_unref(pad);
3601 /* done. free allocated variables */
3602 g_list_free(element_bucket);
3606 return MM_ERROR_NONE;
3609 LOGE("ERROR : releasing videobin");
3610 g_list_free(element_bucket);
3613 gst_object_unref(GST_OBJECT(pad));
3615 /* release videobin with it's childs */
3616 if (videobin[MMPLAYER_V_BIN].gst)
3617 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3619 MMPLAYER_FREEIF(videobin);
3620 player->pipeline->videobin = NULL;
3622 return MM_ERROR_PLAYER_INTERNAL;
3626 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3628 GList *element_bucket = NULL;
3629 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3631 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3632 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3633 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3634 "signal-handoffs", FALSE,
3637 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3638 _mmplayer_add_signal_connection(player,
3639 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3640 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3642 G_CALLBACK(__mmplayer_update_subtitle),
3645 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3646 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3648 if (!player->play_subtitle) {
3649 LOGD("add textbin sink as sink element of whole pipeline.");
3650 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3653 /* adding created elements to bin */
3654 LOGD("adding created elements to bin");
3655 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3656 LOGE("failed to add elements");
3660 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3661 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3662 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3664 /* linking elements in the bucket by added order. */
3665 LOGD("Linking elements in the bucket by added order.");
3666 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3667 LOGE("failed to link elements");
3671 /* done. free allocated variables */
3672 g_list_free(element_bucket);
3674 if (textbin[MMPLAYER_T_QUEUE].gst) {
3676 GstPad *ghostpad = NULL;
3678 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3680 LOGE("failed to get sink pad of text queue");
3684 ghostpad = gst_ghost_pad_new("text_sink", pad);
3685 gst_object_unref(pad);
3688 LOGE("failed to create ghostpad of textbin");
3692 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3693 LOGE("failed to add ghostpad to textbin");
3694 gst_object_unref(ghostpad);
3699 return MM_ERROR_NONE;
3702 g_list_free(element_bucket);
3704 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3705 LOGE("remove textbin sink from sink list");
3706 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3709 /* release element at __mmplayer_gst_create_text_sink_bin */
3710 return MM_ERROR_PLAYER_INTERNAL;
3714 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3716 mmplayer_gst_element_t *textbin = NULL;
3717 GList *element_bucket = NULL;
3718 int surface_type = 0;
3723 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3726 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3728 LOGE("failed to allocate memory for textbin");
3729 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3733 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3734 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3735 if (!textbin[MMPLAYER_T_BIN].gst) {
3736 LOGE("failed to create textbin");
3741 player->pipeline->textbin = textbin;
3744 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3745 LOGD("surface type for subtitle : %d", surface_type);
3746 switch (surface_type) {
3747 case MM_DISPLAY_SURFACE_OVERLAY:
3748 case MM_DISPLAY_SURFACE_NULL:
3749 case MM_DISPLAY_SURFACE_REMOTE:
3750 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3751 LOGE("failed to make plain text elements");
3762 return MM_ERROR_NONE;
3766 LOGD("ERROR : releasing textbin");
3768 g_list_free(element_bucket);
3770 /* release signal */
3771 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3773 /* release element which are not added to bin */
3774 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3775 /* NOTE : skip bin */
3776 if (textbin[i].gst) {
3777 GstObject *parent = NULL;
3778 parent = gst_element_get_parent(textbin[i].gst);
3781 gst_object_unref(GST_OBJECT(textbin[i].gst));
3782 textbin[i].gst = NULL;
3784 gst_object_unref(GST_OBJECT(parent));
3789 /* release textbin with it's childs */
3790 if (textbin[MMPLAYER_T_BIN].gst)
3791 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3793 MMPLAYER_FREEIF(textbin);
3794 player->pipeline->textbin = NULL;
3797 return MM_ERROR_PLAYER_INTERNAL;
3801 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3803 mmplayer_gst_element_t *mainbin = NULL;
3804 mmplayer_gst_element_t *textbin = NULL;
3805 MMHandleType attrs = 0;
3806 GstElement *subsrc = NULL;
3807 GstElement *subparse = NULL;
3808 gchar *subtitle_uri = NULL;
3809 const gchar *charset = NULL;
3815 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3817 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3819 mainbin = player->pipeline->mainbin;
3821 attrs = MMPLAYER_GET_ATTRS(player);
3823 LOGE("cannot get content attribute");
3824 return MM_ERROR_PLAYER_INTERNAL;
3827 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3828 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3829 LOGE("subtitle uri is not proper filepath.");
3830 return MM_ERROR_PLAYER_INVALID_URI;
3833 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3834 LOGE("failed to get storage info of subtitle path");
3835 return MM_ERROR_PLAYER_INVALID_URI;
3838 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3840 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3841 player->subtitle_language_list = NULL;
3842 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3844 /* create the subtitle source */
3845 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3847 LOGE("failed to create filesrc element");
3850 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3852 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3853 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3855 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3856 LOGW("failed to add queue");
3857 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3858 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3859 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3864 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3866 LOGE("failed to create subparse element");
3870 charset = _mmplayer_get_charset(subtitle_uri);
3872 LOGD("detected charset is %s", charset);
3873 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3876 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3877 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3879 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3880 LOGW("failed to add subparse");
3881 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3882 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3883 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3887 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3888 LOGW("failed to link subsrc and subparse");
3892 player->play_subtitle = TRUE;
3893 player->adjust_subtitle_pos = 0;
3895 LOGD("play subtitle using subtitle file");
3897 if (player->pipeline->textbin == NULL) {
3898 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3899 LOGE("failed to create text sink bin. continuing without text");
3903 textbin = player->pipeline->textbin;
3905 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3906 LOGW("failed to add textbin");
3908 /* release signal */
3909 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3911 /* release textbin with it's childs */
3912 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3913 MMPLAYER_FREEIF(player->pipeline->textbin);
3914 player->pipeline->textbin = textbin = NULL;
3918 LOGD("link text input selector and textbin ghost pad");
3920 player->textsink_linked = 1;
3921 player->external_text_idx = 0;
3922 LOGI("textsink is linked");
3924 textbin = player->pipeline->textbin;
3925 LOGD("text bin has been created. reuse it.");
3926 player->external_text_idx = 1;
3929 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3930 LOGW("failed to link subparse and textbin");
3934 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3936 LOGE("failed to get sink pad from textsink to probe data");
3940 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3941 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3943 gst_object_unref(pad);
3946 /* create dot. for debugging */
3947 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3950 return MM_ERROR_NONE;
3953 /* release text pipeline resource */
3954 player->textsink_linked = 0;
3956 /* release signal */
3957 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3959 if (player->pipeline->textbin) {
3960 LOGE("remove textbin");
3962 /* release textbin with it's childs */
3963 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3964 MMPLAYER_FREEIF(player->pipeline->textbin);
3965 player->pipeline->textbin = NULL;
3969 /* release subtitle elem */
3970 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3971 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3973 return MM_ERROR_PLAYER_INTERNAL;
3977 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3979 mmplayer_t *player = (mmplayer_t *)data;
3980 MMMessageParamType msg = {0, };
3981 GstClockTime duration = 0;
3982 gpointer text = NULL;
3983 guint text_size = 0;
3984 gboolean ret = TRUE;
3985 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3989 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3990 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3992 if (player->is_subtitle_force_drop) {
3993 LOGW("subtitle is dropped forcedly.");
3997 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3998 text = mapinfo.data;
3999 text_size = mapinfo.size;
4001 if (player->set_mode.subtitle_off) {
4002 LOGD("subtitle is OFF.");
4006 if (!text || (text_size == 0)) {
4007 LOGD("There is no subtitle to be displayed.");
4011 msg.data = (void *)text;
4013 duration = GST_BUFFER_DURATION(buffer);
4015 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4016 if (player->duration > GST_BUFFER_PTS(buffer))
4017 duration = player->duration - GST_BUFFER_PTS(buffer);
4020 LOGI("subtitle duration is invalid, subtitle duration change "
4021 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4023 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4025 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4027 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4028 gst_buffer_unmap(buffer, &mapinfo);
4035 static GstPadProbeReturn
4036 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4038 mmplayer_t *player = (mmplayer_t *)u_data;
4039 GstClockTime cur_timestamp = 0;
4040 gint64 adjusted_timestamp = 0;
4041 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4043 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4045 if (player->set_mode.subtitle_off) {
4046 LOGD("subtitle is OFF.");
4050 if (player->adjust_subtitle_pos == 0) {
4051 LOGD("nothing to do");
4055 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4056 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4058 if (adjusted_timestamp < 0) {
4059 LOGD("adjusted_timestamp under zero");
4064 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4065 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4066 GST_TIME_ARGS(cur_timestamp),
4067 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4069 return GST_PAD_PROBE_OK;
4073 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4077 /* check player and subtitlebin are created */
4078 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4079 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4081 if (position == 0) {
4082 LOGD("nothing to do");
4084 return MM_ERROR_NONE;
4087 /* check current postion */
4088 player->adjust_subtitle_pos = position;
4090 LOGD("save adjust_subtitle_pos in player");
4094 return MM_ERROR_NONE;
4098 * This function is to create audio or video pipeline for playing.
4100 * @param player [in] handle of player
4102 * @return This function returns zero on success.
4107 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4109 int ret = MM_ERROR_NONE;
4110 mmplayer_gst_element_t *mainbin = NULL;
4111 MMHandleType attrs = 0;
4114 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4116 /* get profile attribute */
4117 attrs = MMPLAYER_GET_ATTRS(player);
4119 LOGE("failed to get content attribute");
4123 /* create pipeline handles */
4124 if (player->pipeline) {
4125 LOGE("pipeline should be released before create new one");
4129 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4131 /* create mainbin */
4132 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4133 if (mainbin == NULL)
4136 /* create pipeline */
4137 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4138 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4139 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4140 LOGE("failed to create pipeline");
4145 player->pipeline->mainbin = mainbin;
4147 /* create the source and decoder elements */
4148 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4149 ret = _mmplayer_gst_build_es_pipeline(player);
4151 ret = _mmplayer_gst_build_pipeline(player);
4153 if (ret != MM_ERROR_NONE) {
4154 LOGE("failed to create some elements");
4158 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4159 if (__mmplayer_check_subtitle(player)
4160 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4161 LOGE("failed to create text pipeline");
4164 ret = _mmplayer_gst_add_bus_watch(player);
4165 if (ret != MM_ERROR_NONE) {
4166 LOGE("failed to add bus watch");
4171 return MM_ERROR_NONE;
4174 __mmplayer_gst_destroy_pipeline(player);
4175 return MM_ERROR_PLAYER_INTERNAL;
4179 __mmplayer_reset_gapless_state(mmplayer_t *player)
4182 MMPLAYER_RETURN_IF_FAIL(player
4184 && player->pipeline->audiobin
4185 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4187 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4194 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4197 int ret = MM_ERROR_NONE;
4201 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4203 /* cleanup stuffs */
4204 MMPLAYER_FREEIF(player->type);
4205 player->no_more_pad = FALSE;
4206 player->num_dynamic_pad = 0;
4208 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4209 player->subtitle_language_list = NULL;
4210 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4212 MMPLAYER_RECONFIGURE_LOCK(player);
4213 __mmplayer_reset_gapless_state(player);
4214 MMPLAYER_RECONFIGURE_UNLOCK(player);
4216 if (player->streamer) {
4217 _mm_player_streaming_initialize(player->streamer, FALSE);
4218 _mm_player_streaming_destroy(player->streamer);
4219 player->streamer = NULL;
4222 /* cleanup unlinked mime type */
4223 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4224 MMPLAYER_FREEIF(player->unlinked_video_mime);
4225 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4227 /* cleanup running stuffs */
4228 _mmplayer_cancel_eos_timer(player);
4230 /* cleanup gst stuffs */
4231 if (player->pipeline) {
4232 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4233 GstTagList *tag_list = player->pipeline->tag_list;
4235 /* first we need to disconnect all signal hander */
4236 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4239 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4240 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4241 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4242 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4243 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4244 gst_object_unref(bus);
4246 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4247 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4248 if (ret != MM_ERROR_NONE) {
4249 LOGE("fail to change state to NULL");
4250 return MM_ERROR_PLAYER_INTERNAL;
4253 LOGW("succeeded in changing state to NULL");
4255 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4258 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4259 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4261 /* free avsysaudiosink
4262 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4263 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4265 MMPLAYER_FREEIF(audiobin);
4266 MMPLAYER_FREEIF(videobin);
4267 MMPLAYER_FREEIF(textbin);
4268 MMPLAYER_FREEIF(mainbin);
4272 gst_tag_list_unref(tag_list);
4274 MMPLAYER_FREEIF(player->pipeline);
4276 MMPLAYER_FREEIF(player->album_art);
4278 if (player->v_stream_caps) {
4279 gst_caps_unref(player->v_stream_caps);
4280 player->v_stream_caps = NULL;
4283 if (player->a_stream_caps) {
4284 gst_caps_unref(player->a_stream_caps);
4285 player->a_stream_caps = NULL;
4288 if (player->s_stream_caps) {
4289 gst_caps_unref(player->s_stream_caps);
4290 player->s_stream_caps = NULL;
4292 _mmplayer_track_destroy(player);
4294 if (player->sink_elements)
4295 g_list_free(player->sink_elements);
4296 player->sink_elements = NULL;
4298 if (player->bufmgr) {
4299 tbm_bufmgr_deinit(player->bufmgr);
4300 player->bufmgr = NULL;
4303 LOGW("finished destroy pipeline");
4311 __mmplayer_gst_realize(mmplayer_t *player)
4314 int ret = MM_ERROR_NONE;
4318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4320 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4322 ret = __mmplayer_gst_create_pipeline(player);
4324 LOGE("failed to create pipeline");
4328 /* set pipeline state to READY */
4329 /* NOTE : state change to READY must be performed sync. */
4330 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4331 ret = _mmplayer_gst_set_state(player,
4332 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4334 if (ret != MM_ERROR_NONE) {
4335 /* return error if failed to set state */
4336 LOGE("failed to set READY state");
4340 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4342 /* create dot before error-return. for debugging */
4343 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4351 __mmplayer_gst_unrealize(mmplayer_t *player)
4353 int ret = MM_ERROR_NONE;
4357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4359 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4360 MMPLAYER_PRINT_STATE(player);
4362 /* release miscellaneous information */
4363 __mmplayer_release_misc(player);
4365 /* destroy pipeline */
4366 ret = __mmplayer_gst_destroy_pipeline(player);
4367 if (ret != MM_ERROR_NONE) {
4368 LOGE("failed to destory pipeline");
4372 /* release miscellaneous information.
4373 these info needs to be released after pipeline is destroyed. */
4374 __mmplayer_release_misc_post(player);
4376 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4384 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4389 LOGW("set_message_callback is called with invalid player handle");
4390 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4393 player->msg_cb = callback;
4394 player->msg_cb_param = user_param;
4396 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4400 return MM_ERROR_NONE;
4404 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4406 int ret = MM_ERROR_NONE;
4411 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4412 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4413 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4415 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4417 if (strstr(uri, "es_buff://")) {
4418 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4419 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4420 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4421 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4423 tmp = g_ascii_strdown(uri, strlen(uri));
4424 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4425 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4427 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4429 } else if (strstr(uri, "mms://")) {
4430 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4431 } else if ((path = strstr(uri, "mem://"))) {
4432 ret = __mmplayer_set_mem_uri(data, path, param);
4434 ret = __mmplayer_set_file_uri(data, uri);
4437 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4438 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4439 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4440 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4442 /* dump parse result */
4443 SECURE_LOGW("incoming uri : %s", uri);
4444 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4445 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4453 __mmplayer_can_do_interrupt(mmplayer_t *player)
4455 if (!player || !player->pipeline || !player->attrs) {
4456 LOGW("not initialized");
4460 if (player->audio_decoded_cb) {
4461 LOGW("not support in pcm extraction mode");
4465 /* check if seeking */
4466 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4467 MMMessageParamType msg_param;
4468 memset(&msg_param, 0, sizeof(MMMessageParamType));
4469 msg_param.code = MM_ERROR_PLAYER_SEEK;
4470 player->seek_state = MMPLAYER_SEEK_NONE;
4471 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4475 /* check other thread */
4476 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4477 LOGW("locked already, cmd state : %d", player->cmd);
4479 /* check application command */
4480 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4481 LOGW("playing.. should wait cmd lock then, will be interrupted");
4483 /* lock will be released at mrp_resource_release_cb() */
4484 MMPLAYER_CMD_LOCK(player);
4487 LOGW("nothing to do");
4490 LOGW("can interrupt immediately");
4494 FAILED: /* with CMD UNLOCKED */
4497 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4502 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4505 mmplayer_t *player = NULL;
4506 MMMessageParamType msg = {0, };
4508 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4513 LOGE("user_data is null");
4516 player = (mmplayer_t *)user_data;
4518 if (!__mmplayer_can_do_interrupt(player)) {
4519 LOGW("no need to interrupt, so leave");
4520 /* FIXME: there is no way to avoid releasing resource. */
4524 player->interrupted_by_resource = TRUE;
4526 /* get last play position */
4527 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4528 msg.union_type = MM_MSG_UNION_TIME;
4529 msg.time.elapsed = pos;
4530 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4532 LOGW("failed to get play position.");
4535 LOGD("video resource conflict so, resource will be freed by unrealizing");
4536 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4537 LOGE("failed to unrealize");
4539 /* lock is called in __mmplayer_can_do_interrupt() */
4540 MMPLAYER_CMD_UNLOCK(player);
4542 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4543 player->hw_resource[res_idx] = NULL;
4547 return TRUE; /* release all the resources */
4551 __mmplayer_initialize_video_roi(mmplayer_t *player)
4553 player->video_roi.scale_x = 0.0;
4554 player->video_roi.scale_y = 0.0;
4555 player->video_roi.scale_width = 1.0;
4556 player->video_roi.scale_height = 1.0;
4560 _mmplayer_create_player(MMHandleType handle)
4562 int ret = MM_ERROR_PLAYER_INTERNAL;
4563 bool enabled = false;
4565 mmplayer_t *player = MM_PLAYER_CAST(handle);
4569 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4571 /* initialize player state */
4572 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4573 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4574 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4575 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4577 /* check current state */
4578 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4580 /* construct attributes */
4581 player->attrs = _mmplayer_construct_attribute(handle);
4583 if (!player->attrs) {
4584 LOGE("Failed to construct attributes");
4588 /* initialize gstreamer with configured parameter */
4589 if (!__mmplayer_init_gstreamer(player)) {
4590 LOGE("Initializing gstreamer failed");
4591 _mmplayer_deconstruct_attribute(handle);
4595 /* create lock. note that g_tread_init() has already called in gst_init() */
4596 g_mutex_init(&player->fsink_lock);
4598 /* create update tag lock */
4599 g_mutex_init(&player->update_tag_lock);
4601 /* create gapless play mutex */
4602 g_mutex_init(&player->gapless_play_thread_mutex);
4604 /* create gapless play cond */
4605 g_cond_init(&player->gapless_play_thread_cond);
4607 /* create gapless play thread */
4608 player->gapless_play_thread =
4609 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4610 if (!player->gapless_play_thread) {
4611 LOGE("failed to create gapless play thread");
4612 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4613 g_mutex_clear(&player->gapless_play_thread_mutex);
4614 g_cond_clear(&player->gapless_play_thread_cond);
4618 player->bus_msg_q = g_queue_new();
4619 if (!player->bus_msg_q) {
4620 LOGE("failed to create queue for bus_msg");
4621 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4625 ret = _mmplayer_initialize_video_capture(player);
4626 if (ret != MM_ERROR_NONE) {
4627 LOGE("failed to initialize video capture");
4631 /* initialize resource manager */
4632 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4633 __resource_release_cb, player, &player->resource_manager)
4634 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4635 LOGE("failed to initialize resource manager");
4636 ret = MM_ERROR_PLAYER_INTERNAL;
4640 /* create video bo lock and cond */
4641 g_mutex_init(&player->video_bo_mutex);
4642 g_cond_init(&player->video_bo_cond);
4644 /* create subtitle info lock and cond */
4645 g_mutex_init(&player->subtitle_info_mutex);
4646 g_cond_init(&player->subtitle_info_cond);
4648 player->streaming_type = STREAMING_SERVICE_NONE;
4650 /* give default value of audio effect setting */
4651 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4652 player->sound.rg_enable = false;
4653 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4655 player->play_subtitle = FALSE;
4656 player->has_closed_caption = FALSE;
4657 player->pending_resume = FALSE;
4658 if (player->ini.dump_element_keyword[0][0] == '\0')
4659 player->ini.set_dump_element_flag = FALSE;
4661 player->ini.set_dump_element_flag = TRUE;
4663 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4664 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4665 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4667 /* Set video360 settings to their defaults for just-created player.
4670 player->is_360_feature_enabled = FALSE;
4671 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4672 LOGI("spherical feature info: %d", enabled);
4674 player->is_360_feature_enabled = TRUE;
4676 LOGE("failed to get spherical feature info");
4679 player->is_content_spherical = FALSE;
4680 player->is_video360_enabled = TRUE;
4681 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4682 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4683 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4684 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4685 player->video360_zoom = 1.0f;
4686 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4687 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4689 __mmplayer_initialize_video_roi(player);
4691 /* set player state to null */
4692 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4693 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4697 return MM_ERROR_NONE;
4701 g_mutex_clear(&player->fsink_lock);
4702 /* free update tag lock */
4703 g_mutex_clear(&player->update_tag_lock);
4704 g_queue_free(player->bus_msg_q);
4705 player->bus_msg_q = NULL;
4706 /* free gapless play thread */
4707 if (player->gapless_play_thread) {
4708 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4709 player->gapless_play_thread_exit = TRUE;
4710 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4711 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4713 g_thread_join(player->gapless_play_thread);
4714 player->gapless_play_thread = NULL;
4716 g_mutex_clear(&player->gapless_play_thread_mutex);
4717 g_cond_clear(&player->gapless_play_thread_cond);
4720 /* release attributes */
4721 _mmplayer_deconstruct_attribute(handle);
4729 __mmplayer_init_gstreamer(mmplayer_t *player)
4731 static gboolean initialized = FALSE;
4732 static const int max_argc = 50;
4734 gchar **argv = NULL;
4735 gchar **argv2 = NULL;
4741 LOGD("gstreamer already initialized.");
4746 argc = malloc(sizeof(int));
4747 argv = malloc(sizeof(gchar *) * max_argc);
4748 argv2 = malloc(sizeof(gchar *) * max_argc);
4750 if (!argc || !argv || !argv2)
4753 memset(argv, 0, sizeof(gchar *) * max_argc);
4754 memset(argv2, 0, sizeof(gchar *) * max_argc);
4758 argv[0] = g_strdup("mmplayer");
4761 for (i = 0; i < 5; i++) {
4762 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4763 if (strlen(player->ini.gst_param[i]) > 0) {
4764 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4769 /* we would not do fork for scanning plugins */
4770 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4773 /* check disable registry scan */
4774 if (player->ini.skip_rescan) {
4775 argv[*argc] = g_strdup("--gst-disable-registry-update");
4779 /* check disable segtrap */
4780 if (player->ini.disable_segtrap) {
4781 argv[*argc] = g_strdup("--gst-disable-segtrap");
4785 LOGD("initializing gstreamer with following parameter");
4786 LOGD("argc : %d", *argc);
4789 for (i = 0; i < arg_count; i++) {
4791 LOGD("argv[%d] : %s", i, argv2[i]);
4794 /* initializing gstreamer */
4795 if (!gst_init_check(argc, &argv, &err)) {
4796 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4803 for (i = 0; i < arg_count; i++) {
4805 LOGD("release - argv[%d] : %s", i, argv2[i]);
4807 MMPLAYER_FREEIF(argv2[i]);
4810 MMPLAYER_FREEIF(argv);
4811 MMPLAYER_FREEIF(argv2);
4812 MMPLAYER_FREEIF(argc);
4822 for (i = 0; i < arg_count; i++) {
4823 LOGD("free[%d] : %s", i, argv2[i]);
4824 MMPLAYER_FREEIF(argv2[i]);
4827 MMPLAYER_FREEIF(argv);
4828 MMPLAYER_FREEIF(argv2);
4829 MMPLAYER_FREEIF(argc);
4835 __mmplayer_check_async_state_transition(mmplayer_t *player)
4837 GstState element_state = GST_STATE_VOID_PENDING;
4838 GstState element_pending_state = GST_STATE_VOID_PENDING;
4839 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4840 GstElement *element = NULL;
4841 gboolean async = FALSE;
4843 /* check player handle */
4844 MMPLAYER_RETURN_IF_FAIL(player &&
4846 player->pipeline->mainbin &&
4847 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4850 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4852 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4853 LOGD("don't need to check the pipeline state");
4857 MMPLAYER_PRINT_STATE(player);
4859 /* wait for state transition */
4860 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4861 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4863 if (ret == GST_STATE_CHANGE_FAILURE) {
4864 LOGE(" [%s] state : %s pending : %s",
4865 GST_ELEMENT_NAME(element),
4866 gst_element_state_get_name(element_state),
4867 gst_element_state_get_name(element_pending_state));
4869 /* dump state of all element */
4870 _mmplayer_dump_pipeline_state(player);
4875 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4880 _mmplayer_destroy(MMHandleType handle)
4882 mmplayer_t *player = MM_PLAYER_CAST(handle);
4886 /* check player handle */
4887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4889 /* destroy can called at anytime */
4890 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4892 /* check async state transition */
4893 __mmplayer_check_async_state_transition(player);
4895 /* release gapless play thread */
4896 if (player->gapless_play_thread) {
4897 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4898 player->gapless_play_thread_exit = TRUE;
4899 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4900 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4902 LOGD("waitting for gapless play thread exit");
4903 g_thread_join(player->gapless_play_thread);
4904 g_mutex_clear(&player->gapless_play_thread_mutex);
4905 g_cond_clear(&player->gapless_play_thread_cond);
4906 LOGD("gapless play thread released");
4909 _mmplayer_release_video_capture(player);
4911 /* de-initialize resource manager */
4912 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4913 player->resource_manager))
4914 LOGE("failed to deinitialize resource manager");
4916 /* release miscellaneous information */
4917 __mmplayer_release_misc(player);
4919 /* release pipeline */
4920 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4921 LOGE("failed to destory pipeline");
4922 return MM_ERROR_PLAYER_INTERNAL;
4925 g_queue_free(player->bus_msg_q);
4927 /* release subtitle info lock and cond */
4928 g_mutex_clear(&player->subtitle_info_mutex);
4929 g_cond_clear(&player->subtitle_info_cond);
4931 __mmplayer_release_dump_list(player->dump_list);
4933 /* release miscellaneous information.
4934 these info needs to be released after pipeline is destroyed. */
4935 __mmplayer_release_misc_post(player);
4937 /* release attributes */
4938 _mmplayer_deconstruct_attribute(handle);
4940 if (player->uri_info.uri_list) {
4941 GList *uri_list = player->uri_info.uri_list;
4942 for (; uri_list; uri_list = g_list_next(uri_list)) {
4943 gchar *uri = uri_list->data;
4944 MMPLAYER_FREEIF(uri);
4946 g_list_free(player->uri_info.uri_list);
4947 player->uri_info.uri_list = NULL;
4951 g_mutex_clear(&player->fsink_lock);
4954 g_mutex_clear(&player->update_tag_lock);
4956 /* release video bo lock and cond */
4957 g_mutex_clear(&player->video_bo_mutex);
4958 g_cond_clear(&player->video_bo_cond);
4962 return MM_ERROR_NONE;
4966 _mmplayer_realize(MMHandleType hplayer)
4968 mmplayer_t *player = (mmplayer_t *)hplayer;
4969 int ret = MM_ERROR_NONE;
4972 MMHandleType attrs = 0;
4973 int video_codec_type = 0;
4974 int audio_codec_type = 0;
4975 int default_codec_type = 0;
4978 /* check player handle */
4979 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4981 /* check current state */
4982 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4984 attrs = MMPLAYER_GET_ATTRS(player);
4986 LOGE("fail to get attributes.");
4987 return MM_ERROR_PLAYER_INTERNAL;
4989 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4990 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4992 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4993 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4995 if (ret != MM_ERROR_NONE) {
4996 LOGE("failed to parse profile");
5001 if (uri && (strstr(uri, "es_buff://"))) {
5002 if (strstr(uri, "es_buff://push_mode"))
5003 player->es_player_push_mode = TRUE;
5005 player->es_player_push_mode = FALSE;
5008 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5009 LOGW("mms protocol is not supported format.");
5010 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5013 if (MMPLAYER_IS_STREAMING(player))
5014 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5016 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5018 player->smooth_streaming = FALSE;
5019 player->videodec_linked = 0;
5020 player->audiodec_linked = 0;
5021 player->textsink_linked = 0;
5022 player->is_external_subtitle_present = FALSE;
5023 player->is_external_subtitle_added_now = FALSE;
5024 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5025 player->video360_metadata.is_spherical = -1;
5026 player->is_openal_plugin_used = FALSE;
5027 player->subtitle_language_list = NULL;
5028 player->is_subtitle_force_drop = FALSE;
5030 _mmplayer_track_initialize(player);
5031 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5033 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5034 gint prebuffer_ms = 0, rebuffer_ms = 0;
5036 player->streamer = _mm_player_streaming_create();
5037 _mm_player_streaming_initialize(player->streamer, TRUE);
5039 mm_attrs_multiple_get(player->attrs, NULL,
5040 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5041 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5043 if (prebuffer_ms > 0) {
5044 prebuffer_ms = MAX(prebuffer_ms, 1000);
5045 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5048 if (rebuffer_ms > 0) {
5049 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5050 rebuffer_ms = MAX(rebuffer_ms, 1000);
5051 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5054 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5055 player->streamer->buffering_req.rebuffer_time);
5058 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5059 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5060 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5062 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5064 if (audio_codec_type != default_codec_type) {
5065 LOGD("audio dec sorting is required");
5066 player->need_audio_dec_sorting = TRUE;
5069 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5070 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5071 LOGD("video dec sorting is required");
5072 player->need_video_dec_sorting = TRUE;
5075 /* realize pipeline */
5076 ret = __mmplayer_gst_realize(player);
5077 if (ret != MM_ERROR_NONE)
5078 LOGE("fail to realize the player.");
5080 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5088 _mmplayer_unrealize(MMHandleType hplayer)
5090 mmplayer_t *player = (mmplayer_t *)hplayer;
5091 int ret = MM_ERROR_NONE;
5095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5097 MMPLAYER_CMD_UNLOCK(player);
5098 /* destroy the gst bus msg thread which is created during realize.
5099 this funct have to be called before getting cmd lock. */
5100 _mmplayer_bus_msg_thread_destroy(player);
5101 MMPLAYER_CMD_LOCK(player);
5103 /* check current state */
5104 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5106 /* check async state transition */
5107 __mmplayer_check_async_state_transition(player);
5109 /* unrealize pipeline */
5110 ret = __mmplayer_gst_unrealize(player);
5112 if (!player->interrupted_by_resource) {
5113 int rm_ret = MM_ERROR_NONE;
5114 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5116 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5117 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5118 if (rm_ret != MM_ERROR_NONE)
5119 LOGE("failed to release [%d] resources", res_idx);
5128 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5130 mmplayer_t *player = (mmplayer_t *)hplayer;
5132 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5134 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5138 _mmplayer_get_state(MMHandleType hplayer, int *state)
5140 mmplayer_t *player = (mmplayer_t *)hplayer;
5142 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5144 *state = MMPLAYER_CURRENT_STATE(player);
5146 return MM_ERROR_NONE;
5150 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5152 GstElement *vol_element = NULL;
5153 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5157 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5159 /* check pipeline handle */
5160 if (!player->pipeline || !player->pipeline->audiobin) {
5161 LOGD("'%s' will be applied when audiobin is created", prop_name);
5163 /* NOTE : stored value will be used in create_audiobin
5164 * returning MM_ERROR_NONE here makes application to able to
5165 * set audio volume or mute at anytime.
5167 return MM_ERROR_NONE;
5170 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5171 volume_elem_id = MMPLAYER_A_SINK;
5173 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5175 LOGE("failed to get vol element %d", volume_elem_id);
5176 return MM_ERROR_PLAYER_INTERNAL;
5179 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5181 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5182 LOGE("there is no '%s' property", prop_name);
5183 return MM_ERROR_PLAYER_INTERNAL;
5186 if (!strcmp(prop_name, "volume")) {
5187 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5188 } else if (!strcmp(prop_name, "mute")) {
5189 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5191 LOGE("invalid property %s", prop_name);
5192 return MM_ERROR_PLAYER_INTERNAL;
5195 return MM_ERROR_NONE;
5199 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5201 int ret = MM_ERROR_NONE;
5202 mmplayer_t *player = (mmplayer_t *)hplayer;
5205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5207 LOGD("volume = %f", volume);
5209 /* invalid factor range or not */
5210 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5211 LOGE("Invalid volume value");
5212 return MM_ERROR_INVALID_ARGUMENT;
5215 player->sound.volume = volume;
5217 ret = __mmplayer_gst_set_volume_property(player, "volume");
5224 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5226 mmplayer_t *player = (mmplayer_t *)hplayer;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5233 *volume = player->sound.volume;
5235 LOGD("current vol = %f", *volume);
5238 return MM_ERROR_NONE;
5242 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5244 int ret = MM_ERROR_NONE;
5245 mmplayer_t *player = (mmplayer_t *)hplayer;
5248 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5250 LOGD("mute = %d", mute);
5252 player->sound.mute = mute;
5254 ret = __mmplayer_gst_set_volume_property(player, "mute");
5261 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5268 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5270 *mute = player->sound.mute;
5272 LOGD("current mute = %d", *mute);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 player->audio_stream_changed_cb = callback;
5289 player->audio_stream_changed_cb_user_param = user_param;
5290 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5294 return MM_ERROR_NONE;
5298 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5300 mmplayer_t *player = (mmplayer_t *)hplayer;
5304 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5306 player->audio_decoded_cb = callback;
5307 player->audio_decoded_cb_user_param = user_param;
5308 player->audio_extract_opt = opt;
5309 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5313 return MM_ERROR_NONE;
5317 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5319 mmplayer_t *player = (mmplayer_t *)hplayer;
5323 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5325 if (callback && !player->bufmgr)
5326 player->bufmgr = tbm_bufmgr_init(-1);
5328 player->set_mode.video_export = (callback) ? true : false;
5329 player->video_decoded_cb = callback;
5330 player->video_decoded_cb_user_param = user_param;
5332 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5336 return MM_ERROR_NONE;
5340 _mmplayer_start(MMHandleType hplayer)
5342 mmplayer_t *player = (mmplayer_t *)hplayer;
5343 gint ret = MM_ERROR_NONE;
5347 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5349 /* check current state */
5350 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5352 /* start pipeline */
5353 ret = _mmplayer_gst_start(player);
5354 if (ret != MM_ERROR_NONE)
5355 LOGE("failed to start player.");
5357 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5358 LOGD("force playing start even during buffering");
5359 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5367 /* NOTE: post "not supported codec message" to application
5368 * when one codec is not found during AUTOPLUGGING in MSL.
5369 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5370 * And, if any codec is not found, don't send message here.
5371 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5374 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5376 MMMessageParamType msg_param;
5377 memset(&msg_param, 0, sizeof(MMMessageParamType));
5378 gboolean post_msg_direct = FALSE;
5382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5384 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5385 player->not_supported_codec, player->can_support_codec);
5387 if (player->not_found_demuxer) {
5388 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5389 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5391 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5392 MMPLAYER_FREEIF(msg_param.data);
5394 return MM_ERROR_NONE;
5397 if (player->not_supported_codec) {
5398 if (player->can_support_codec) {
5399 // There is one codec to play
5400 post_msg_direct = TRUE;
5402 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5403 post_msg_direct = TRUE;
5406 if (post_msg_direct) {
5407 MMMessageParamType msg_param;
5408 memset(&msg_param, 0, sizeof(MMMessageParamType));
5410 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5411 LOGW("not found AUDIO codec, posting error code to application.");
5413 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5414 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5415 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5416 LOGW("not found VIDEO codec, posting error code to application.");
5418 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5419 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5422 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5424 MMPLAYER_FREEIF(msg_param.data);
5426 return MM_ERROR_NONE;
5428 // no any supported codec case
5429 LOGW("not found any codec, posting error code to application.");
5431 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5432 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5433 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5435 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5436 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5439 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5441 MMPLAYER_FREEIF(msg_param.data);
5447 return MM_ERROR_NONE;
5450 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5452 GstState element_state = GST_STATE_VOID_PENDING;
5453 GstState element_pending_state = GST_STATE_VOID_PENDING;
5454 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5455 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5457 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5459 MMPLAYER_RECONFIGURE_LOCK(player);
5460 if (!player->gapless.reconfigure) {
5461 MMPLAYER_RECONFIGURE_UNLOCK(player);
5465 LOGI("reconfigure is under process");
5466 MMPLAYER_RECONFIGURE_WAIT(player);
5467 MMPLAYER_RECONFIGURE_UNLOCK(player);
5468 LOGI("reconfigure is completed.");
5470 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5471 &element_state, &element_pending_state, timeout * GST_SECOND);
5472 if (result == GST_STATE_CHANGE_FAILURE)
5473 LOGW("failed to get pipeline state in %d sec", timeout);
5478 /* NOTE : it should be able to call 'stop' anytime*/
5480 _mmplayer_stop(MMHandleType hplayer)
5482 mmplayer_t *player = (mmplayer_t *)hplayer;
5483 int ret = MM_ERROR_NONE;
5487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5489 /* check current state */
5490 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5492 /* need to wait till the rebuilding pipeline is completed */
5493 __mmplayer_check_pipeline_reconfigure_state(player);
5494 MMPLAYER_RECONFIGURE_LOCK(player);
5495 __mmplayer_reset_gapless_state(player);
5496 MMPLAYER_RECONFIGURE_UNLOCK(player);
5498 /* NOTE : application should not wait for EOS after calling STOP */
5499 _mmplayer_cancel_eos_timer(player);
5502 player->seek_state = MMPLAYER_SEEK_NONE;
5505 ret = _mmplayer_gst_stop(player);
5507 if (ret != MM_ERROR_NONE)
5508 LOGE("failed to stop player.");
5516 _mmplayer_pause(MMHandleType hplayer)
5518 mmplayer_t *player = (mmplayer_t *)hplayer;
5519 gint64 pos_nsec = 0;
5520 gboolean async = FALSE;
5521 gint ret = MM_ERROR_NONE;
5525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5527 /* check current state */
5528 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5530 /* check pipline reconfigure state */
5531 __mmplayer_check_pipeline_reconfigure_state(player);
5533 switch (MMPLAYER_CURRENT_STATE(player)) {
5534 case MM_PLAYER_STATE_READY:
5536 /* check prepare async or not.
5537 * In the case of streaming playback, it's recommned to avoid blocking wait.
5539 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5540 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5542 /* Changing back sync of rtspsrc to async */
5543 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5544 LOGD("async prepare working mode for rtsp");
5550 case MM_PLAYER_STATE_PLAYING:
5552 /* NOTE : store current point to overcome some bad operation
5553 *(returning zero when getting current position in paused state) of some
5556 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5557 LOGW("getting current position failed in paused");
5559 player->last_position = pos_nsec;
5561 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5562 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5563 This causes problem is position calculation during normal pause resume scenarios also.
5564 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5565 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5566 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5567 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5573 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5574 LOGD("doing async pause in case of ms buff src");
5578 /* pause pipeline */
5579 ret = _mmplayer_gst_pause(player, async);
5581 if (ret != MM_ERROR_NONE)
5582 LOGE("failed to pause player. ret : 0x%x", ret);
5584 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5585 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5586 LOGE("failed to update display_rotation");
5594 /* in case of streaming, pause could take long time.*/
5596 _mmplayer_abort_pause(MMHandleType hplayer)
5598 mmplayer_t *player = (mmplayer_t *)hplayer;
5599 int ret = MM_ERROR_NONE;
5603 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5605 player->pipeline->mainbin,
5606 MM_ERROR_PLAYER_NOT_INITIALIZED);
5608 LOGD("set the pipeline state to READY");
5610 /* set state to READY */
5611 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5612 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5613 if (ret != MM_ERROR_NONE) {
5614 LOGE("fail to change state to READY");
5615 return MM_ERROR_PLAYER_INTERNAL;
5618 LOGD("succeeded in changing state to READY");
5623 _mmplayer_resume(MMHandleType hplayer)
5625 mmplayer_t *player = (mmplayer_t *)hplayer;
5626 int ret = MM_ERROR_NONE;
5627 gboolean async = FALSE;
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5633 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5634 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5635 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5639 /* Changing back sync mode rtspsrc to async */
5640 LOGD("async resume for rtsp case");
5644 /* check current state */
5645 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5647 ret = _mmplayer_gst_resume(player, async);
5648 if (ret != MM_ERROR_NONE)
5649 LOGE("failed to resume player.");
5651 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5652 LOGD("force resume even during buffering");
5653 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5662 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5664 mmplayer_t *player = (mmplayer_t *)hplayer;
5665 gint64 pos_nsec = 0;
5666 int ret = MM_ERROR_NONE;
5668 signed long long start = 0, stop = 0;
5669 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5672 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5673 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5675 /* The sound of video is not supported under 0.0 and over 2.0. */
5676 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5677 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5680 _mmplayer_set_mute(hplayer, mute);
5682 if (player->playback_rate == rate)
5683 return MM_ERROR_NONE;
5685 /* If the position is reached at start potion during fast backward, EOS is posted.
5686 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5688 player->playback_rate = rate;
5690 current_state = MMPLAYER_CURRENT_STATE(player);
5692 if (current_state != MM_PLAYER_STATE_PAUSED)
5693 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5695 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5697 if ((current_state == MM_PLAYER_STATE_PAUSED)
5698 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5699 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5700 pos_nsec = player->last_position;
5705 stop = GST_CLOCK_TIME_NONE;
5707 start = GST_CLOCK_TIME_NONE;
5711 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5712 player->playback_rate,
5714 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5715 GST_SEEK_TYPE_SET, start,
5716 GST_SEEK_TYPE_SET, stop)) {
5717 LOGE("failed to set speed playback");
5718 return MM_ERROR_PLAYER_SEEK;
5721 LOGD("succeeded to set speed playback as %0.1f", rate);
5725 return MM_ERROR_NONE;;
5729 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5731 mmplayer_t *player = (mmplayer_t *)hplayer;
5732 int ret = MM_ERROR_NONE;
5736 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5738 /* check pipline reconfigure state */
5739 __mmplayer_check_pipeline_reconfigure_state(player);
5741 ret = _mmplayer_gst_set_position(player, position, FALSE);
5749 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5751 mmplayer_t *player = (mmplayer_t *)hplayer;
5752 int ret = MM_ERROR_NONE;
5754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5755 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5757 if (g_strrstr(player->type, "video/mpegts"))
5758 __mmplayer_update_duration_value(player);
5760 *duration = player->duration;
5765 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5767 mmplayer_t *player = (mmplayer_t *)hplayer;
5768 int ret = MM_ERROR_NONE;
5770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5772 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5778 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5780 mmplayer_t *player = (mmplayer_t *)hplayer;
5781 int ret = MM_ERROR_NONE;
5785 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5787 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5795 __mmplayer_is_midi_type(gchar *str_caps)
5797 if ((g_strrstr(str_caps, "audio/midi")) ||
5798 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5799 (g_strrstr(str_caps, "application/x-smaf")) ||
5800 (g_strrstr(str_caps, "audio/x-imelody")) ||
5801 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5802 (g_strrstr(str_caps, "audio/xmf")) ||
5803 (g_strrstr(str_caps, "audio/mxmf"))) {
5812 __mmplayer_is_only_mp3_type(gchar *str_caps)
5814 if (g_strrstr(str_caps, "application/x-id3") ||
5815 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5821 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5823 GstStructure *caps_structure = NULL;
5824 gint samplerate = 0;
5828 MMPLAYER_RETURN_IF_FAIL(player && caps);
5830 caps_structure = gst_caps_get_structure(caps, 0);
5832 /* set stream information */
5833 gst_structure_get_int(caps_structure, "rate", &samplerate);
5834 gst_structure_get_int(caps_structure, "channels", &channels);
5836 mm_player_set_attribute((MMHandleType)player, NULL,
5837 "content_audio_samplerate", samplerate,
5838 "content_audio_channels", channels, NULL);
5840 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5844 __mmplayer_update_content_type_info(mmplayer_t *player)
5847 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5849 if (__mmplayer_is_midi_type(player->type)) {
5850 player->bypass_audio_effect = TRUE;
5854 if (!player->streamer) {
5855 LOGD("no need to check streaming type");
5859 if (g_strrstr(player->type, "application/x-hls")) {
5860 /* If it can't know exact type when it parses uri because of redirection case,
5861 * it will be fixed by typefinder or when doing autoplugging.
5863 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5864 player->streamer->is_adaptive_streaming = TRUE;
5865 } else if (g_strrstr(player->type, "application/dash+xml")) {
5866 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5867 player->streamer->is_adaptive_streaming = TRUE;
5870 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5871 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5872 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5874 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5875 if (player->streamer->is_adaptive_streaming)
5876 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5878 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5882 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5887 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5888 GstCaps *caps, gpointer data)
5890 mmplayer_t *player = (mmplayer_t *)data;
5894 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5896 /* store type string */
5897 MMPLAYER_FREEIF(player->type);
5898 player->type = gst_caps_to_string(caps);
5900 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5901 player, player->type, probability, gst_caps_get_size(caps));
5903 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5904 (g_strrstr(player->type, "audio/x-raw-int"))) {
5905 LOGE("not support media format");
5907 if (player->msg_posted == FALSE) {
5908 MMMessageParamType msg_param;
5909 memset(&msg_param, 0, sizeof(MMMessageParamType));
5911 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5912 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5914 /* don't post more if one was sent already */
5915 player->msg_posted = TRUE;
5920 __mmplayer_update_content_type_info(player);
5922 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5925 pad = gst_element_get_static_pad(tf, "src");
5927 LOGE("fail to get typefind src pad.");
5931 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5932 gboolean async = FALSE;
5933 LOGE("failed to autoplug %s", player->type);
5935 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5937 if (async && player->msg_posted == FALSE)
5938 __mmplayer_handle_missed_plugin(player);
5940 gst_object_unref(GST_OBJECT(pad));
5947 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5949 GstElement *decodebin = NULL;
5953 /* create decodebin */
5954 decodebin = gst_element_factory_make("decodebin", NULL);
5957 LOGE("fail to create decodebin");
5961 /* raw pad handling signal */
5962 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5963 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5965 /* no-more-pad pad handling signal */
5966 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5967 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5969 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5970 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
5972 /* This signal is emitted when a pad for which there is no further possible
5973 decoding is added to the decodebin.*/
5974 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5975 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
5977 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5978 before looking for any elements that can handle that stream.*/
5979 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5980 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5982 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5983 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5984 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5986 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5987 before looking for any elements that can handle that stream.*/
5988 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5989 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5991 /* This signal is emitted once decodebin has finished decoding all the data.*/
5992 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5993 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
5995 /* This signal is emitted when a element is added to the bin.*/
5996 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5997 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6004 __mmplayer_gst_make_queue2(mmplayer_t *player)
6006 GstElement *queue2 = NULL;
6007 gint64 dur_bytes = 0L;
6008 mmplayer_gst_element_t *mainbin = NULL;
6009 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6012 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6014 mainbin = player->pipeline->mainbin;
6016 queue2 = gst_element_factory_make("queue2", "queue2");
6018 LOGE("failed to create buffering queue element");
6022 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6023 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6025 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6027 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6028 * skip the pull mode(file or ring buffering) setting. */
6029 if (dur_bytes > 0) {
6030 if (!g_strrstr(player->type, "video/mpegts")) {
6031 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6032 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6038 _mm_player_streaming_set_queue2(player->streamer,
6042 (guint64)dur_bytes); /* no meaning at the moment */
6048 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6050 mmplayer_gst_element_t *mainbin = NULL;
6051 GstElement *decodebin = NULL;
6052 GstElement *queue2 = NULL;
6053 GstPad *sinkpad = NULL;
6054 GstPad *qsrcpad = NULL;
6057 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6059 mainbin = player->pipeline->mainbin;
6061 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6063 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6064 LOGW("need to check: muxed buffer is not null");
6067 queue2 = __mmplayer_gst_make_queue2(player);
6069 LOGE("failed to make queue2");
6073 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6074 LOGE("failed to add buffering queue");
6078 sinkpad = gst_element_get_static_pad(queue2, "sink");
6079 qsrcpad = gst_element_get_static_pad(queue2, "src");
6081 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6082 LOGE("failed to link [%s:%s]-[%s:%s]",
6083 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6087 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6088 LOGE("failed to sync queue2 state with parent");
6092 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6093 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6097 gst_object_unref(GST_OBJECT(sinkpad));
6101 /* create decodebin */
6102 decodebin = _mmplayer_gst_make_decodebin(player);
6104 LOGE("failed to make decodebin");
6108 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6109 LOGE("failed to add decodebin");
6113 /* to force caps on the decodebin element and avoid reparsing stuff by
6114 * typefind. It also avoids a deadlock in the way typefind activates pads in
6115 * the state change */
6116 g_object_set(decodebin, "sink-caps", caps, NULL);
6118 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6120 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6121 LOGE("failed to link [%s:%s]-[%s:%s]",
6122 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6126 gst_object_unref(GST_OBJECT(sinkpad));
6128 gst_object_unref(GST_OBJECT(qsrcpad));
6131 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6132 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6134 /* set decodebin property about buffer in streaming playback. *
6135 * in case of HLS/DASH, it does not need to have big buffer *
6136 * because it is kind of adaptive streaming. */
6137 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6138 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6139 gint high_percent = 0;
6141 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6142 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6144 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6146 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6148 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6149 "high-percent", high_percent,
6150 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6151 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6152 "max-size-buffers", 0, NULL); // disable or automatic
6155 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6156 LOGE("failed to sync decodebin state with parent");
6167 gst_object_unref(GST_OBJECT(sinkpad));
6170 gst_object_unref(GST_OBJECT(qsrcpad));
6173 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6174 * You need to explicitly set elements to the NULL state before
6175 * dropping the final reference, to allow them to clean up.
6177 gst_element_set_state(queue2, GST_STATE_NULL);
6179 /* And, it still has a parent "player".
6180 * You need to let the parent manage the object instead of unreffing the object directly.
6182 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6183 gst_object_unref(queue2);
6188 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6189 * You need to explicitly set elements to the NULL state before
6190 * dropping the final reference, to allow them to clean up.
6192 gst_element_set_state(decodebin, GST_STATE_NULL);
6194 /* And, it still has a parent "player".
6195 * You need to let the parent manage the object instead of unreffing the object directly.
6198 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6199 gst_object_unref(decodebin);
6207 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6211 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6212 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6214 LOGD("class : %s, mime : %s", factory_class, mime);
6216 /* add missing plugin */
6217 /* NOTE : msl should check missing plugin for image mime type.
6218 * Some motion jpeg clips can have playable audio track.
6219 * So, msl have to play audio after displaying popup written video format not supported.
6221 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6222 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6223 LOGD("not found demuxer");
6224 player->not_found_demuxer = TRUE;
6225 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6231 if (!g_strrstr(factory_class, "Demuxer")) {
6232 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6233 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6234 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6236 /* check that clip have multi tracks or not */
6237 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6238 LOGD("video plugin is already linked");
6240 LOGW("add VIDEO to missing plugin");
6241 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6242 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6244 } else if (g_str_has_prefix(mime, "audio")) {
6245 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6246 LOGD("audio plugin is already linked");
6248 LOGW("add AUDIO to missing plugin");
6249 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6250 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6258 return MM_ERROR_NONE;
6262 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6264 mmplayer_t *player = (mmplayer_t *)data;
6268 MMPLAYER_RETURN_IF_FAIL(player);
6270 /* remove fakesink. */
6271 if (!_mmplayer_gst_remove_fakesink(player,
6272 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6273 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6274 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6275 * source element are not same. To overcome this situation, this function will called
6276 * several places and several times. Therefore, this is not an error case.
6281 LOGD("[handle: %p] pipeline has completely constructed", player);
6283 if ((player->msg_posted == FALSE) &&
6284 (player->cmd >= MMPLAYER_COMMAND_START))
6285 __mmplayer_handle_missed_plugin(player);
6287 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6291 __mmplayer_check_profile(void)
6294 static int profile_tv = -1;
6296 if (__builtin_expect(profile_tv != -1, 1))
6299 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6300 switch (*profileName) {
6315 __mmplayer_get_next_uri(mmplayer_t *player)
6317 mmplayer_parse_profile_t profile;
6319 guint num_of_list = 0;
6322 num_of_list = g_list_length(player->uri_info.uri_list);
6323 uri_idx = player->uri_info.uri_idx;
6325 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6326 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6327 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6329 LOGW("next uri does not exist");
6333 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6334 LOGE("failed to parse profile");
6338 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6339 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6340 LOGW("uri type is not supported(%d)", profile.uri_type);
6344 LOGD("success to find next uri %d", uri_idx);
6348 if (!uri || uri_idx == num_of_list) {
6349 LOGE("failed to find next uri");
6353 player->uri_info.uri_idx = uri_idx;
6354 if (mm_player_set_attribute((MMHandleType)player, NULL,
6355 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6356 LOGE("failed to set attribute");
6360 SECURE_LOGD("next playback uri: %s", uri);
6365 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6367 #define REPEAT_COUNT_INFINITE -1
6368 #define REPEAT_COUNT_MIN 2
6369 #define ORIGINAL_URI_ONLY 1
6371 MMHandleType attrs = 0;
6375 guint num_of_uri = 0;
6376 int profile_tv = -1;
6380 LOGD("checking for gapless play option");
6382 if (player->build_audio_offload) {
6383 LOGE("offload path is not supportable.");
6387 if (player->pipeline->textbin) {
6388 LOGE("subtitle path is enabled. gapless play is not supported.");
6392 attrs = MMPLAYER_GET_ATTRS(player);
6394 LOGE("fail to get attributes.");
6398 mm_attrs_multiple_get(player->attrs, NULL,
6399 "content_video_found", &video,
6400 "profile_play_count", &count,
6401 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6403 /* gapless playback is not supported in case of video at TV profile. */
6404 profile_tv = __mmplayer_check_profile();
6405 if (profile_tv && video) {
6406 LOGW("not support video gapless playback");
6410 /* check repeat count in case of audio */
6412 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6413 LOGW("gapless is disabled");
6417 num_of_uri = g_list_length(player->uri_info.uri_list);
6419 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6421 if (num_of_uri == ORIGINAL_URI_ONLY) {
6422 /* audio looping path */
6423 if (count >= REPEAT_COUNT_MIN) {
6424 /* decrease play count */
6425 /* we succeeded to rewind. update play count and then wait for next EOS */
6427 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6428 } else if (count != REPEAT_COUNT_INFINITE) {
6429 LOGD("there is no next uri and no repeat");
6432 LOGD("looping cnt %d", count);
6434 /* gapless playback path */
6435 if (!__mmplayer_get_next_uri(player)) {
6436 LOGE("failed to get next uri");
6443 LOGE("unable to play gapless path. EOS will be posted soon");
6448 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6450 mmplayer_selector_t *selector = &player->selector[type];
6451 mmplayer_gst_element_t *sinkbin = NULL;
6452 main_element_id_e selectorId = MMPLAYER_M_NUM;
6453 main_element_id_e sinkId = MMPLAYER_M_NUM;
6454 GstPad *srcpad = NULL;
6455 GstPad *sinkpad = NULL;
6456 gboolean send_notice = FALSE;
6459 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6461 LOGD("type %d", type);
6464 case MM_PLAYER_TRACK_TYPE_AUDIO:
6465 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6466 sinkId = MMPLAYER_A_BIN;
6467 sinkbin = player->pipeline->audiobin;
6469 case MM_PLAYER_TRACK_TYPE_VIDEO:
6470 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6471 sinkId = MMPLAYER_V_BIN;
6472 sinkbin = player->pipeline->videobin;
6475 case MM_PLAYER_TRACK_TYPE_TEXT:
6476 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6477 sinkId = MMPLAYER_T_BIN;
6478 sinkbin = player->pipeline->textbin;
6481 LOGE("requested type is not supportable");
6486 if (player->pipeline->mainbin[selectorId].gst) {
6489 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6491 if (selector->event_probe_id != 0)
6492 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6493 selector->event_probe_id = 0;
6495 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6496 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6498 if (srcpad && sinkpad) {
6499 /* after getting drained signal there is no data flows, so no need to do pad_block */
6500 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6501 gst_pad_unlink(srcpad, sinkpad);
6503 /* send custom event to sink pad to handle it at video sink */
6505 LOGD("send custom event to sinkpad");
6506 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6507 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6508 gst_pad_send_event(sinkpad, event);
6512 gst_object_unref(sinkpad);
6515 gst_object_unref(srcpad);
6518 LOGD("selector release");
6520 /* release and unref requests pad from the selector */
6521 for (n = 0; n < selector->channels->len; n++) {
6522 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6523 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6525 g_ptr_array_set_size(selector->channels, 0);
6527 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6528 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6530 player->pipeline->mainbin[selectorId].gst = NULL;
6538 __mmplayer_deactivate_old_path(mmplayer_t *player)
6541 MMPLAYER_RETURN_IF_FAIL(player);
6543 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6544 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6545 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6546 LOGE("deactivate selector error");
6550 _mmplayer_track_destroy(player);
6551 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6553 if (player->streamer) {
6554 _mm_player_streaming_initialize(player->streamer, FALSE);
6555 _mm_player_streaming_destroy(player->streamer);
6556 player->streamer = NULL;
6559 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6565 if (!player->msg_posted) {
6566 MMMessageParamType msg = {0,};
6569 msg.code = MM_ERROR_PLAYER_INTERNAL;
6570 LOGE("gapless_uri_play> deactivate error");
6572 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6573 player->msg_posted = TRUE;
6579 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6581 int result = MM_ERROR_NONE;
6582 mmplayer_t *player = (mmplayer_t *)hplayer;
6585 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6586 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6588 if (mm_player_set_attribute(hplayer, NULL,
6589 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6590 LOGE("failed to set attribute");
6591 result = MM_ERROR_PLAYER_INTERNAL;
6593 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6594 LOGE("failed to add the original uri in the uri list.");
6602 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6604 mmplayer_t *player = (mmplayer_t *)hplayer;
6605 guint num_of_list = 0;
6609 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6610 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6612 if (player->pipeline && player->pipeline->textbin) {
6613 LOGE("subtitle path is enabled.");
6614 return MM_ERROR_PLAYER_INVALID_STATE;
6617 num_of_list = g_list_length(player->uri_info.uri_list);
6619 if (is_first_path) {
6620 if (num_of_list == 0) {
6621 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6622 SECURE_LOGD("add original path : %s", uri);
6624 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6625 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6627 SECURE_LOGD("change original path : %s", uri);
6630 MMHandleType attrs = 0;
6631 attrs = MMPLAYER_GET_ATTRS(player);
6633 if (num_of_list == 0) {
6634 char *original_uri = NULL;
6637 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6639 if (!original_uri) {
6640 LOGE("there is no original uri.");
6641 return MM_ERROR_PLAYER_INVALID_STATE;
6644 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6645 player->uri_info.uri_idx = 0;
6647 SECURE_LOGD("add original path at first : %s", original_uri);
6651 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6652 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6656 return MM_ERROR_NONE;
6660 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6662 mmplayer_t *player = (mmplayer_t *)hplayer;
6663 char *next_uri = NULL;
6664 guint num_of_list = 0;
6667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6669 num_of_list = g_list_length(player->uri_info.uri_list);
6671 if (num_of_list > 0) {
6672 gint uri_idx = player->uri_info.uri_idx;
6674 if (uri_idx < num_of_list-1)
6679 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6680 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6682 *uri = g_strdup(next_uri);
6686 return MM_ERROR_NONE;
6690 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6691 GstCaps *caps, gpointer data)
6693 mmplayer_t *player = (mmplayer_t *)data;
6694 const gchar *klass = NULL;
6695 const gchar *mime = NULL;
6696 gchar *caps_str = NULL;
6698 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6699 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6700 caps_str = gst_caps_to_string(caps);
6702 LOGW("unknown type of caps : %s from %s",
6703 caps_str, GST_ELEMENT_NAME(elem));
6705 MMPLAYER_FREEIF(caps_str);
6707 /* There is no available codec. */
6708 __mmplayer_check_not_supported_codec(player, klass, mime);
6712 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6713 GstCaps *caps, gpointer data)
6715 mmplayer_t *player = (mmplayer_t *)data;
6716 const char *mime = NULL;
6717 gboolean ret = TRUE;
6719 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6720 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6722 if (g_str_has_prefix(mime, "audio")) {
6723 GstStructure *caps_structure = NULL;
6724 gint samplerate = 0;
6726 gchar *caps_str = NULL;
6728 caps_structure = gst_caps_get_structure(caps, 0);
6729 gst_structure_get_int(caps_structure, "rate", &samplerate);
6730 gst_structure_get_int(caps_structure, "channels", &channels);
6732 if ((channels > 0 && samplerate == 0)) {
6733 LOGD("exclude audio...");
6737 caps_str = gst_caps_to_string(caps);
6738 /* set it directly because not sent by TAG */
6739 if (g_strrstr(caps_str, "mobile-xmf"))
6740 mm_player_set_attribute((MMHandleType)player, NULL,
6741 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6743 MMPLAYER_FREEIF(caps_str);
6744 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6745 LOGD("already video linked");
6748 LOGD("found new stream");
6755 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6757 gboolean ret = FALSE;
6758 GDBusConnection *conn = NULL;
6760 GVariant *result = NULL;
6761 const gchar *dbus_device_type = NULL;
6762 const gchar *dbus_ret = NULL;
6765 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6767 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6772 result = g_dbus_connection_call_sync(conn,
6773 "org.pulseaudio.Server",
6774 "/org/pulseaudio/StreamManager",
6775 "org.pulseaudio.StreamManager",
6776 "GetCurrentMediaRoutingPath",
6777 g_variant_new("(s)", "out"),
6778 G_VARIANT_TYPE("(ss)"),
6779 G_DBUS_CALL_FLAGS_NONE,
6783 if (!result || err) {
6784 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6789 /* device type is listed in stream-map.json at mmfw-sysconf */
6790 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6792 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6793 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6796 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6797 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6798 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6799 LOGD("audio offload is supportable");
6805 LOGD("audio offload is not supportable");
6808 g_variant_unref(result);
6810 g_object_unref(conn);
6815 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6817 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6818 gint64 position = 0;
6820 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6821 player->pipeline && player->pipeline->mainbin);
6823 MMPLAYER_CMD_LOCK(player);
6824 current_state = MMPLAYER_CURRENT_STATE(player);
6826 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6827 LOGW("getting current position failed in paused");
6829 _mmplayer_unrealize((MMHandleType)player);
6830 _mmplayer_realize((MMHandleType)player);
6832 _mmplayer_set_position((MMHandleType)player, position);
6834 /* async not to be blocked in streaming case */
6835 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6837 _mmplayer_pause((MMHandleType)player);
6839 if (current_state == MM_PLAYER_STATE_PLAYING)
6840 _mmplayer_start((MMHandleType)player);
6841 MMPLAYER_CMD_UNLOCK(player);
6843 LOGD("rebuilding audio pipeline is completed.");
6846 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6848 mmplayer_t *player = (mmplayer_t *)user_data;
6849 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6850 gboolean is_supportable = FALSE;
6852 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6853 LOGW("failed to get device type");
6855 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6857 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6858 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6859 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6860 LOGD("ignore this dev connected info");
6864 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6865 if (player->build_audio_offload == is_supportable) {
6866 LOGD("keep current pipeline without re-building");
6870 /* rebuild pipeline */
6871 LOGD("re-build pipeline - offload: %d", is_supportable);
6872 player->build_audio_offload = FALSE;
6873 __mmplayer_rebuild_audio_pipeline(player);
6879 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6881 unsigned int id = 0;
6883 if (player->audio_device_cb_id != 0) {
6884 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6888 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6889 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6890 LOGD("added device connected cb (%u)", id);
6891 player->audio_device_cb_id = id;
6893 LOGW("failed to add device connected cb");
6900 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6902 mmplayer_t *player = (mmplayer_t *)hplayer;
6905 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6906 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6908 *activated = player->build_audio_offload;
6910 LOGD("offload activated : %d", (int)*activated);
6913 return MM_ERROR_NONE;
6917 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6920 this function need to be updated according to the supported media format
6921 @see player->ini.audio_offload_media_format */
6923 if (__mmplayer_is_only_mp3_type(player->type)) {
6924 LOGD("offload supportable media format type");
6932 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6934 gboolean ret = FALSE;
6935 GstElementFactory *factory = NULL;
6938 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6940 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6941 if (!__mmplayer_is_offload_supported_type(player))
6944 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6945 LOGD("there is no audio offload sink");
6949 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6950 LOGW("there is no audio device type to support offload");
6954 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6956 LOGW("there is no installed audio offload sink element");
6959 gst_object_unref(factory);
6961 if (__mmplayer_acquire_hw_resource(player,
6962 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6963 LOGE("failed to acquire audio offload decoder resource");
6967 if (!__mmplayer_add_audio_device_connected_cb(player))
6970 if (!__mmplayer_is_audio_offload_device_type(player))
6973 LOGD("audio offload can be built");
6978 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6984 static GstAutoplugSelectResult
6985 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6987 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6988 int audio_offload = 0;
6990 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6991 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6993 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6994 LOGD("expose audio path to build offload output path");
6995 player->build_audio_offload = TRUE;
6996 /* update codec info */
6997 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6998 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6999 player->audiodec_linked = 1;
7001 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7005 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7006 And need to consider the multi-track audio content.
7007 There is no HW audio decoder in public. */
7009 /* set stream information */
7010 if (!player->audiodec_linked)
7011 __mmplayer_set_audio_attrs(player, caps);
7013 /* update codec info */
7014 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7015 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7016 player->audiodec_linked = 1;
7018 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7020 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7021 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7023 /* mark video decoder for acquire */
7024 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7025 LOGW("video decoder resource is already acquired, skip it.");
7026 ret = GST_AUTOPLUG_SELECT_SKIP;
7030 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7031 LOGE("failed to acquire video decoder resource");
7032 ret = GST_AUTOPLUG_SELECT_SKIP;
7035 player->interrupted_by_resource = FALSE;
7038 /* update codec info */
7039 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7040 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7041 player->videodec_linked = 1;
7049 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7050 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7052 #define DEFAULT_IDX 0xFFFF
7053 #define MIN_FACTORY_NUM 2
7054 mmplayer_t *player = (mmplayer_t *)data;
7055 GValueArray *new_factories = NULL;
7056 GValue val = { 0, };
7057 GstElementFactory *factory = NULL;
7058 const gchar *klass = NULL;
7059 gchar *factory_name = NULL;
7060 guint hw_dec_idx = DEFAULT_IDX;
7061 guint first_sw_dec_idx = DEFAULT_IDX;
7062 guint last_sw_dec_idx = DEFAULT_IDX;
7063 guint new_pos = DEFAULT_IDX;
7064 guint rm_pos = DEFAULT_IDX;
7065 int audio_codec_type;
7066 int video_codec_type;
7067 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7069 if (factories->n_values < MIN_FACTORY_NUM)
7072 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7073 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7076 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7078 for (int i = 0 ; i < factories->n_values ; i++) {
7079 gchar *hw_dec_info = NULL;
7080 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7082 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7084 LOGW("failed to get factory object");
7087 klass = gst_element_factory_get_klass(factory);
7088 factory_name = GST_OBJECT_NAME(factory);
7091 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7093 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7094 if (!player->need_audio_dec_sorting) {
7095 LOGD("sorting is not required");
7098 codec_type = audio_codec_type;
7099 hw_dec_info = player->ini.audiocodec_element_hw;
7100 sw_dec_info = player->ini.audiocodec_element_sw;
7101 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7102 if (!player->need_video_dec_sorting) {
7103 LOGD("sorting is not required");
7106 codec_type = video_codec_type;
7107 hw_dec_info = player->ini.videocodec_element_hw;
7108 sw_dec_info = player->ini.videocodec_element_sw;
7113 if (g_strrstr(factory_name, hw_dec_info)) {
7116 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7117 if (strstr(factory_name, sw_dec_info[j])) {
7118 last_sw_dec_idx = i;
7119 if (first_sw_dec_idx == DEFAULT_IDX) {
7120 first_sw_dec_idx = i;
7125 if (first_sw_dec_idx == DEFAULT_IDX)
7126 LOGW("unknown codec %s", factory_name);
7130 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7133 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7134 if (hw_dec_idx < first_sw_dec_idx)
7136 new_pos = first_sw_dec_idx;
7137 rm_pos = hw_dec_idx + 1;
7138 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7139 if (last_sw_dec_idx < hw_dec_idx)
7141 new_pos = last_sw_dec_idx + 1;
7142 rm_pos = hw_dec_idx;
7147 /* change position - insert H/W decoder according to the new position */
7148 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7150 LOGW("failed to get factory object");
7153 new_factories = g_value_array_copy(factories);
7154 g_value_init (&val, G_TYPE_OBJECT);
7155 g_value_set_object (&val, factory);
7156 g_value_array_insert(new_factories, new_pos, &val);
7157 g_value_unset (&val);
7158 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7160 for (int i = 0 ; i < new_factories->n_values ; i++) {
7161 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7163 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7164 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7166 LOGE("[Re-arranged] failed to get factory object");
7169 return new_factories;
7173 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7174 GstCaps *caps, GstElementFactory *factory, gpointer data)
7176 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7177 mmplayer_t *player = (mmplayer_t *)data;
7179 gchar *factory_name = NULL;
7180 gchar *caps_str = NULL;
7181 const gchar *klass = NULL;
7184 factory_name = GST_OBJECT_NAME(factory);
7185 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7186 caps_str = gst_caps_to_string(caps);
7188 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7190 /* store type string */
7191 if (player->type == NULL) {
7192 player->type = gst_caps_to_string(caps);
7193 __mmplayer_update_content_type_info(player);
7196 /* filtering exclude keyword */
7197 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7198 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7199 LOGW("skipping [%s] by exculde keyword [%s]",
7200 factory_name, player->ini.exclude_element_keyword[idx]);
7202 result = GST_AUTOPLUG_SELECT_SKIP;
7207 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7208 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7209 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7210 factory_name, player->ini.unsupported_codec_keyword[idx]);
7211 result = GST_AUTOPLUG_SELECT_SKIP;
7216 /* exclude webm format */
7217 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7218 * because webm format is not supportable.
7219 * If webm is disabled in "autoplug-continue", there is no state change
7220 * failure or error because the decodebin will expose the pad directly.
7221 * It make MSL invoke _prepare_async_callback.
7222 * So, we need to disable webm format in "autoplug-select" */
7223 if (caps_str && strstr(caps_str, "webm")) {
7224 LOGW("webm is not supported");
7225 result = GST_AUTOPLUG_SELECT_SKIP;
7229 /* check factory class for filtering */
7230 /* NOTE : msl don't need to use image plugins.
7231 * So, those plugins should be skipped for error handling.
7233 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7234 LOGD("skipping [%s] by not required", factory_name);
7235 result = GST_AUTOPLUG_SELECT_SKIP;
7239 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7240 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7241 // TO CHECK : subtitle if needed, add subparse exception.
7242 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7243 result = GST_AUTOPLUG_SELECT_SKIP;
7247 if (g_strrstr(factory_name, "mpegpsdemux")) {
7248 LOGD("skipping PS container - not support");
7249 result = GST_AUTOPLUG_SELECT_SKIP;
7253 if (g_strrstr(factory_name, "mssdemux"))
7254 player->smooth_streaming = TRUE;
7256 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7257 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7260 GstStructure *str = NULL;
7261 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7263 /* don't make video because of not required */
7264 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7265 (!player->set_mode.video_export)) {
7266 LOGD("no need video decoding, expose pad");
7267 result = GST_AUTOPLUG_SELECT_EXPOSE;
7271 /* get w/h for omx state-tune */
7272 /* FIXME: deprecated? */
7273 str = gst_caps_get_structure(caps, 0);
7274 gst_structure_get_int(str, "width", &width);
7277 if (player->v_stream_caps) {
7278 gst_caps_unref(player->v_stream_caps);
7279 player->v_stream_caps = NULL;
7282 player->v_stream_caps = gst_caps_copy(caps);
7283 LOGD("take caps for video state tune");
7284 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7288 if (g_strrstr(klass, "Codec/Decoder")) {
7289 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7290 if (result != GST_AUTOPLUG_SELECT_TRY) {
7291 LOGW("skip add decoder");
7297 MMPLAYER_FREEIF(caps_str);
7303 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7306 //mmplayer_t *player = (mmplayer_t *)data;
7307 GstCaps *caps = NULL;
7309 LOGD("[Decodebin2] pad-removed signal");
7311 caps = gst_pad_query_caps(new_pad, NULL);
7313 LOGW("query caps is NULL");
7317 gchar *caps_str = NULL;
7318 caps_str = gst_caps_to_string(caps);
7320 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7322 MMPLAYER_FREEIF(caps_str);
7323 gst_caps_unref(caps);
7327 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7329 mmplayer_t *player = (mmplayer_t *)data;
7330 GstIterator *iter = NULL;
7331 GValue item = { 0, };
7333 gboolean done = FALSE;
7334 gboolean is_all_drained = TRUE;
7337 MMPLAYER_RETURN_IF_FAIL(player);
7339 LOGD("got drained signal");
7341 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7342 LOGW("Fail to get cmd lock");
7346 if (!__mmplayer_verify_gapless_play_path(player)) {
7347 LOGD("decoding is finished.");
7348 MMPLAYER_CMD_UNLOCK(player);
7352 _mmplayer_set_reconfigure_state(player, TRUE);
7353 MMPLAYER_CMD_UNLOCK(player);
7355 /* check decodebin src pads whether they received EOS or not */
7356 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7359 switch (gst_iterator_next(iter, &item)) {
7360 case GST_ITERATOR_OK:
7361 pad = g_value_get_object(&item);
7362 if (pad && !GST_PAD_IS_EOS(pad)) {
7363 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7364 is_all_drained = FALSE;
7367 g_value_reset(&item);
7369 case GST_ITERATOR_RESYNC:
7370 gst_iterator_resync(iter);
7372 case GST_ITERATOR_ERROR:
7373 case GST_ITERATOR_DONE:
7378 g_value_unset(&item);
7379 gst_iterator_free(iter);
7381 if (!is_all_drained) {
7382 LOGD("Wait util the all pads get EOS.");
7387 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7388 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7390 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7391 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7392 __mmplayer_deactivate_old_path(player);
7398 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7400 mmplayer_t *player = (mmplayer_t *)data;
7401 const gchar *klass = NULL;
7402 gchar *factory_name = NULL;
7404 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7405 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7407 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7409 if (__mmplayer_add_dump_buffer_probe(player, element))
7410 LOGD("add buffer probe");
7412 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7413 gchar *selected = NULL;
7414 selected = g_strdup(GST_ELEMENT_NAME(element));
7415 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7418 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7419 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7420 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7422 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7423 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7425 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7426 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7427 "max-video-width", player->adaptive_info.limit.width,
7428 "max-video-height", player->adaptive_info.limit.height, NULL);
7430 } else if (g_strrstr(klass, "Demuxer")) {
7432 LOGD("plugged element is demuxer. take it");
7434 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7435 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7438 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7439 int surface_type = 0;
7441 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7444 // to support trust-zone only
7445 if (g_strrstr(factory_name, "asfdemux")) {
7446 LOGD("set file-location %s", player->profile.uri);
7447 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7448 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7449 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7450 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7451 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7452 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7453 (__mmplayer_is_only_mp3_type(player->type))) {
7454 LOGD("[mpegaudioparse] set streaming pull mode.");
7455 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7457 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7458 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7461 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7462 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7463 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7465 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7466 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7468 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7469 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7470 (MMPLAYER_IS_DASH_STREAMING(player))) {
7471 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7472 _mm_player_streaming_set_multiqueue(player->streamer, element);
7473 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7482 __mmplayer_release_misc(mmplayer_t *player)
7485 bool cur_mode = player->set_mode.rich_audio;
7488 MMPLAYER_RETURN_IF_FAIL(player);
7490 player->sent_bos = FALSE;
7491 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7493 player->seek_state = MMPLAYER_SEEK_NONE;
7495 player->total_bitrate = 0;
7496 player->total_maximum_bitrate = 0;
7498 player->not_found_demuxer = 0;
7500 player->last_position = 0;
7501 player->duration = 0;
7502 player->http_content_size = 0;
7503 player->not_supported_codec = MISSING_PLUGIN_NONE;
7504 player->can_support_codec = FOUND_PLUGIN_NONE;
7505 player->pending_seek.is_pending = false;
7506 player->pending_seek.pos = 0;
7507 player->msg_posted = FALSE;
7508 player->has_many_types = FALSE;
7509 player->is_subtitle_force_drop = FALSE;
7510 player->play_subtitle = FALSE;
7511 player->adjust_subtitle_pos = 0;
7512 player->has_closed_caption = FALSE;
7513 player->set_mode.video_export = false;
7514 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7515 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7517 player->set_mode.rich_audio = cur_mode;
7519 if (player->audio_device_cb_id > 0 &&
7520 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7521 LOGW("failed to remove audio device_connected_callback");
7522 player->audio_device_cb_id = 0;
7524 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7525 player->bitrate[i] = 0;
7526 player->maximum_bitrate[i] = 0;
7529 /* free memory related to audio effect */
7530 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7532 if (player->adaptive_info.var_list) {
7533 g_list_free_full(player->adaptive_info.var_list, g_free);
7534 player->adaptive_info.var_list = NULL;
7537 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7538 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7539 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7541 /* Reset video360 settings to their defaults in case if the pipeline is to be
7544 player->video360_metadata.is_spherical = -1;
7545 player->is_openal_plugin_used = FALSE;
7547 player->is_content_spherical = FALSE;
7548 player->is_video360_enabled = TRUE;
7549 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7550 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7551 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7552 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7553 player->video360_zoom = 1.0f;
7554 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7555 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7557 player->sound.rg_enable = false;
7559 __mmplayer_initialize_video_roi(player);
7564 __mmplayer_release_misc_post(mmplayer_t *player)
7566 char *original_uri = NULL;
7569 /* player->pipeline is already released before. */
7570 MMPLAYER_RETURN_IF_FAIL(player);
7572 player->video_decoded_cb = NULL;
7573 player->video_decoded_cb_user_param = NULL;
7574 player->video_stream_prerolled = false;
7576 player->audio_decoded_cb = NULL;
7577 player->audio_decoded_cb_user_param = NULL;
7578 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7580 player->audio_stream_changed_cb = NULL;
7581 player->audio_stream_changed_cb_user_param = NULL;
7583 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7585 /* clean found audio decoders */
7586 if (player->audio_decoders) {
7587 GList *a_dec = player->audio_decoders;
7588 for (; a_dec; a_dec = g_list_next(a_dec)) {
7589 gchar *name = a_dec->data;
7590 MMPLAYER_FREEIF(name);
7592 g_list_free(player->audio_decoders);
7593 player->audio_decoders = NULL;
7596 /* clean the uri list except original uri */
7597 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7598 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7600 LOGW("failed to get original uri info");
7602 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7603 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7605 GList *uri_list = player->uri_info.uri_list;
7606 for (; uri_list; uri_list = g_list_next(uri_list)) {
7607 gchar *uri = uri_list->data;
7608 if (original_uri != uri)
7609 MMPLAYER_FREEIF(uri);
7613 /* clear the audio stream buffer list */
7614 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7616 /* clear the video stream bo list */
7617 __mmplayer_video_stream_destroy_bo_list(player);
7618 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7620 if (player->profile.input_mem.buf) {
7621 free(player->profile.input_mem.buf);
7622 player->profile.input_mem.buf = NULL;
7624 player->profile.input_mem.len = 0;
7625 player->profile.input_mem.offset = 0;
7627 player->uri_info.uri_idx = 0;
7632 __mmplayer_check_subtitle(mmplayer_t *player)
7634 MMHandleType attrs = 0;
7635 char *subtitle_uri = NULL;
7639 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7641 /* get subtitle attribute */
7642 attrs = MMPLAYER_GET_ATTRS(player);
7646 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7647 if (!subtitle_uri || !strlen(subtitle_uri))
7650 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7651 player->is_external_subtitle_present = TRUE;
7659 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7661 MMPLAYER_RETURN_IF_FAIL(player);
7663 if (player->eos_timer) {
7664 LOGD("cancel eos timer");
7665 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7666 player->eos_timer = 0;
7673 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7677 MMPLAYER_RETURN_IF_FAIL(player);
7678 MMPLAYER_RETURN_IF_FAIL(sink);
7680 player->sink_elements = g_list_append(player->sink_elements, sink);
7686 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7690 MMPLAYER_RETURN_IF_FAIL(player);
7691 MMPLAYER_RETURN_IF_FAIL(sink);
7693 player->sink_elements = g_list_remove(player->sink_elements, sink);
7699 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7700 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7702 mmplayer_signal_item_t *item = NULL;
7705 MMPLAYER_RETURN_IF_FAIL(player);
7707 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7708 LOGE("invalid signal type [%d]", type);
7712 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7714 LOGE("cannot connect signal [%s]", signal);
7719 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7720 player->signals[type] = g_list_append(player->signals[type], item);
7726 /* NOTE : be careful with calling this api. please refer to below glib comment
7727 * glib comment : Note that there is a bug in GObject that makes this function much
7728 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7729 * will no longer be called, but, the signal handler is not currently disconnected.
7730 * If the instance is itself being freed at the same time than this doesn't matter,
7731 * since the signal will automatically be removed, but if instance persists,
7732 * then the signal handler will leak. You should not remove the signal yourself
7733 * because in a future versions of GObject, the handler will automatically be
7736 * It's possible to work around this problem in a way that will continue to work
7737 * with future versions of GObject by checking that the signal handler is still
7738 * connected before disconnected it:
7740 * if (g_signal_handler_is_connected(instance, id))
7741 * g_signal_handler_disconnect(instance, id);
7744 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7746 GList *sig_list = NULL;
7747 mmplayer_signal_item_t *item = NULL;
7751 MMPLAYER_RETURN_IF_FAIL(player);
7753 LOGD("release signals type : %d", type);
7755 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7756 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7757 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7758 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7759 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7760 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7764 sig_list = player->signals[type];
7766 for (; sig_list; sig_list = sig_list->next) {
7767 item = sig_list->data;
7769 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7770 if (g_signal_handler_is_connected(item->obj, item->sig))
7771 g_signal_handler_disconnect(item->obj, item->sig);
7774 MMPLAYER_FREEIF(item);
7777 g_list_free(player->signals[type]);
7778 player->signals[type] = NULL;
7786 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7788 mmplayer_t *player = 0;
7789 int prev_display_surface_type = 0;
7793 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7795 player = MM_PLAYER_CAST(handle);
7797 /* check video sinkbin is created */
7798 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7799 LOGW("Videosink is already created");
7800 return MM_ERROR_NONE;
7803 LOGD("videosink element is not yet ready");
7805 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7806 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7808 return MM_ERROR_INVALID_ARGUMENT;
7811 /* load previous attributes */
7812 if (player->attrs) {
7813 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7814 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7815 if (prev_display_surface_type == surface_type) {
7816 LOGD("incoming display surface type is same as previous one, do nothing..");
7818 return MM_ERROR_NONE;
7821 LOGE("failed to load attributes");
7823 return MM_ERROR_PLAYER_INTERNAL;
7826 /* videobin is not created yet, so we just set attributes related to display surface */
7827 LOGD("store display attribute for given surface type(%d)", surface_type);
7828 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7829 "display_overlay", wl_surface_id, NULL);
7832 return MM_ERROR_NONE;
7835 /* Note : if silent is true, then subtitle would not be displayed. :*/
7837 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7839 mmplayer_t *player = (mmplayer_t *)hplayer;
7843 /* check player handle */
7844 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7846 player->set_mode.subtitle_off = silent;
7848 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7852 return MM_ERROR_NONE;
7856 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7858 mmplayer_gst_element_t *mainbin = NULL;
7859 mmplayer_gst_element_t *textbin = NULL;
7860 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7861 GstState current_state = GST_STATE_VOID_PENDING;
7862 GstState element_state = GST_STATE_VOID_PENDING;
7863 GstState element_pending_state = GST_STATE_VOID_PENDING;
7865 GstEvent *event = NULL;
7866 int result = MM_ERROR_NONE;
7868 GstClock *curr_clock = NULL;
7869 GstClockTime base_time, start_time, curr_time;
7874 /* check player handle */
7875 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7877 player->pipeline->mainbin &&
7878 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7880 mainbin = player->pipeline->mainbin;
7881 textbin = player->pipeline->textbin;
7883 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7885 // sync clock with current pipeline
7886 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7887 curr_time = gst_clock_get_time(curr_clock);
7889 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7890 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7892 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7893 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7895 if (current_state > GST_STATE_READY) {
7896 // sync state with current pipeline
7897 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7898 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7899 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7901 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7902 if (GST_STATE_CHANGE_FAILURE == ret) {
7903 LOGE("fail to state change.");
7904 result = MM_ERROR_PLAYER_INTERNAL;
7908 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7909 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7912 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7913 gst_object_unref(curr_clock);
7916 // seek to current position
7917 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7918 result = MM_ERROR_PLAYER_INVALID_STATE;
7919 LOGE("gst_element_query_position failed, invalid state");
7923 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7924 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);
7926 _mmplayer_gst_send_event_to_sink(player, event);
7928 result = MM_ERROR_PLAYER_INTERNAL;
7929 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7933 /* sync state with current pipeline */
7934 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7935 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7936 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7938 return MM_ERROR_NONE;
7941 /* release text pipeline resource */
7942 player->textsink_linked = 0;
7944 /* release signal */
7945 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7947 /* release textbin with it's childs */
7948 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7949 MMPLAYER_FREEIF(player->pipeline->textbin);
7950 player->pipeline->textbin = NULL;
7952 /* release subtitle elem */
7953 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7954 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7960 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7962 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7963 GstState current_state = GST_STATE_VOID_PENDING;
7965 MMHandleType attrs = 0;
7966 mmplayer_gst_element_t *mainbin = NULL;
7967 mmplayer_gst_element_t *textbin = NULL;
7969 gchar *subtitle_uri = NULL;
7970 int result = MM_ERROR_NONE;
7971 const gchar *charset = NULL;
7975 /* check player handle */
7976 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7978 player->pipeline->mainbin &&
7979 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7980 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7982 mainbin = player->pipeline->mainbin;
7983 textbin = player->pipeline->textbin;
7985 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7986 if (current_state < GST_STATE_READY) {
7987 result = MM_ERROR_PLAYER_INVALID_STATE;
7988 LOGE("Pipeline is not in proper state");
7992 attrs = MMPLAYER_GET_ATTRS(player);
7994 LOGE("cannot get content attribute");
7995 result = MM_ERROR_PLAYER_INTERNAL;
7999 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8000 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8001 LOGE("subtitle uri is not proper filepath");
8002 result = MM_ERROR_PLAYER_INVALID_URI;
8006 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8007 LOGE("failed to get storage info of subtitle path");
8008 result = MM_ERROR_PLAYER_INVALID_URI;
8012 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8013 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8015 if (!strcmp(filepath, subtitle_uri)) {
8016 LOGD("subtitle path is not changed");
8019 if (mm_player_set_attribute((MMHandleType)player, NULL,
8020 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8021 LOGE("failed to set attribute");
8026 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8027 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8028 player->subtitle_language_list = NULL;
8029 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8031 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8032 if (ret != GST_STATE_CHANGE_SUCCESS) {
8033 LOGE("failed to change state of textbin to READY");
8034 result = MM_ERROR_PLAYER_INTERNAL;
8038 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8039 if (ret != GST_STATE_CHANGE_SUCCESS) {
8040 LOGE("failed to change state of subparse to READY");
8041 result = MM_ERROR_PLAYER_INTERNAL;
8045 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8046 if (ret != GST_STATE_CHANGE_SUCCESS) {
8047 LOGE("failed to change state of filesrc to READY");
8048 result = MM_ERROR_PLAYER_INTERNAL;
8052 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8054 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8056 charset = _mmplayer_get_charset(filepath);
8058 LOGD("detected charset is %s", charset);
8059 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8062 result = _mmplayer_sync_subtitle_pipeline(player);
8069 /* API to switch between external subtitles */
8071 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8073 int result = MM_ERROR_NONE;
8074 mmplayer_t *player = (mmplayer_t *)hplayer;
8079 /* check player handle */
8080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8082 /* filepath can be null in idle state */
8084 /* check file path */
8085 if ((path = strstr(filepath, "file://")))
8086 result = _mmplayer_exist_file_path(path + 7);
8088 result = _mmplayer_exist_file_path(filepath);
8090 if (result != MM_ERROR_NONE) {
8091 LOGE("invalid subtitle path 0x%X", result);
8092 return result; /* file not found or permission denied */
8096 if (!player->pipeline) {
8098 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8099 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8100 LOGE("failed to set attribute");
8101 return MM_ERROR_PLAYER_INTERNAL;
8104 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8105 /* check filepath */
8106 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8108 if (!__mmplayer_check_subtitle(player)) {
8109 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8110 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8111 LOGE("failed to set attribute");
8112 return MM_ERROR_PLAYER_INTERNAL;
8115 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8116 LOGE("fail to create text pipeline");
8117 return MM_ERROR_PLAYER_INTERNAL;
8120 result = _mmplayer_sync_subtitle_pipeline(player);
8122 result = __mmplayer_change_external_subtitle_language(player, filepath);
8125 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8126 player->is_external_subtitle_added_now = TRUE;
8128 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8129 if (!player->subtitle_language_list) {
8130 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8131 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8132 LOGW("subtitle language list is not updated yet");
8134 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8142 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8144 int result = MM_ERROR_NONE;
8145 gchar *change_pad_name = NULL;
8146 GstPad *sinkpad = NULL;
8147 mmplayer_gst_element_t *mainbin = NULL;
8148 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8149 GstCaps *caps = NULL;
8150 gint total_track_num = 0;
8154 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8155 MM_ERROR_PLAYER_NOT_INITIALIZED);
8157 LOGD("Change Track(%d) to %d", type, index);
8159 mainbin = player->pipeline->mainbin;
8161 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8162 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8163 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8164 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8166 /* Changing Video Track is not supported. */
8167 LOGE("Track Type Error");
8171 if (mainbin[elem_idx].gst == NULL) {
8172 result = MM_ERROR_PLAYER_NO_OP;
8173 LOGD("Req track doesn't exist");
8177 total_track_num = player->selector[type].total_track_num;
8178 if (total_track_num <= 0) {
8179 result = MM_ERROR_PLAYER_NO_OP;
8180 LOGD("Language list is not available");
8184 if ((index < 0) || (index >= total_track_num)) {
8185 result = MM_ERROR_INVALID_ARGUMENT;
8186 LOGD("Not a proper index : %d", index);
8190 /*To get the new pad from the selector*/
8191 change_pad_name = g_strdup_printf("sink_%u", index);
8192 if (change_pad_name == NULL) {
8193 result = MM_ERROR_PLAYER_INTERNAL;
8194 LOGD("Pad does not exists");
8198 LOGD("new active pad name: %s", change_pad_name);
8200 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8201 if (sinkpad == NULL) {
8202 LOGD("sinkpad is NULL");
8203 result = MM_ERROR_PLAYER_INTERNAL;
8207 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8208 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8210 caps = gst_pad_get_current_caps(sinkpad);
8211 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8214 gst_object_unref(sinkpad);
8216 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8217 __mmplayer_set_audio_attrs(player, caps);
8220 MMPLAYER_FREEIF(change_pad_name);
8225 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8227 int result = MM_ERROR_NONE;
8228 mmplayer_t *player = NULL;
8229 mmplayer_gst_element_t *mainbin = NULL;
8231 gint current_active_index = 0;
8233 GstState current_state = GST_STATE_VOID_PENDING;
8234 GstEvent *event = NULL;
8239 player = (mmplayer_t *)hplayer;
8240 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8242 if (!player->pipeline) {
8243 LOGE("Track %d pre setting -> %d", type, index);
8245 player->selector[type].active_pad_index = index;
8249 mainbin = player->pipeline->mainbin;
8251 current_active_index = player->selector[type].active_pad_index;
8253 /*If index is same as running index no need to change the pad*/
8254 if (current_active_index == index)
8257 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8258 result = MM_ERROR_PLAYER_INVALID_STATE;
8262 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8263 if (current_state < GST_STATE_PAUSED) {
8264 result = MM_ERROR_PLAYER_INVALID_STATE;
8265 LOGW("Pipeline not in porper state");
8269 result = __mmplayer_change_selector_pad(player, type, index);
8270 if (result != MM_ERROR_NONE) {
8271 LOGE("change selector pad error");
8275 player->selector[type].active_pad_index = index;
8277 if (current_state == GST_STATE_PLAYING) {
8278 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8279 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8280 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8282 _mmplayer_gst_send_event_to_sink(player, event);
8284 result = MM_ERROR_PLAYER_INTERNAL;
8294 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8296 mmplayer_t *player = (mmplayer_t *)hplayer;
8300 /* check player handle */
8301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8303 *silent = player->set_mode.subtitle_off;
8305 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8309 return MM_ERROR_NONE;
8313 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8315 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8316 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8318 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8319 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8323 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8324 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8325 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8326 mmplayer_dump_t *dump_s;
8327 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8328 if (dump_s == NULL) {
8329 LOGE("malloc fail");
8333 dump_s->dump_element_file = NULL;
8334 dump_s->dump_pad = NULL;
8335 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8337 if (dump_s->dump_pad) {
8338 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8339 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]);
8340 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8341 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);
8342 /* add list for removed buffer probe and close FILE */
8343 player->dump_list = g_list_append(player->dump_list, dump_s);
8344 LOGD("%s sink pad added buffer probe for dump", factory_name);
8347 MMPLAYER_FREEIF(dump_s);
8348 LOGE("failed to get %s sink pad added", factory_name);
8355 static GstPadProbeReturn
8356 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8358 FILE *dump_data = (FILE *)u_data;
8360 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8361 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8363 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8365 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8367 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8369 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8371 gst_buffer_unmap(buffer, &probe_info);
8373 return GST_PAD_PROBE_OK;
8377 __mmplayer_release_dump_list(GList *dump_list)
8379 GList *d_list = dump_list;
8384 for (; d_list; d_list = g_list_next(d_list)) {
8385 mmplayer_dump_t *dump_s = d_list->data;
8386 if (dump_s->dump_pad) {
8387 if (dump_s->probe_handle_id)
8388 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8389 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8391 if (dump_s->dump_element_file) {
8392 fclose(dump_s->dump_element_file);
8393 dump_s->dump_element_file = NULL;
8395 MMPLAYER_FREEIF(dump_s);
8397 g_list_free(dump_list);
8402 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8404 mmplayer_t *player = (mmplayer_t *)hplayer;
8408 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8409 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8411 *exist = (bool)player->has_closed_caption;
8415 return MM_ERROR_NONE;
8419 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8424 LOGD("unref internal gst buffer %p", buffer);
8426 gst_buffer_unref((GstBuffer *)buffer);
8433 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8435 mmplayer_t *player = (mmplayer_t *)hplayer;
8439 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8440 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8442 if (MMPLAYER_IS_STREAMING(player))
8443 *timeout = (int)player->ini.live_state_change_timeout;
8445 *timeout = (int)player->ini.localplayback_state_change_timeout;
8447 LOGD("timeout = %d", *timeout);
8450 return MM_ERROR_NONE;
8454 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8458 MMPLAYER_RETURN_IF_FAIL(player);
8460 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8462 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8463 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8464 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8465 player->storage_info[i].id = -1;
8466 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8468 if (path_type != MMPLAYER_PATH_MAX)
8477 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8479 int ret = MM_ERROR_NONE;
8480 mmplayer_t *player = (mmplayer_t *)hplayer;
8481 MMMessageParamType msg_param = {0, };
8484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8486 LOGW("state changed storage %d:%d", id, state);
8488 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8489 return MM_ERROR_NONE;
8491 /* FIXME: text path should be handled seperately. */
8492 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8493 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8494 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8495 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8496 LOGW("external storage is removed");
8498 if (player->msg_posted == FALSE) {
8499 memset(&msg_param, 0, sizeof(MMMessageParamType));
8500 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8501 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8502 player->msg_posted = TRUE;
8505 /* unrealize the player */
8506 ret = _mmplayer_unrealize(hplayer);
8507 if (ret != MM_ERROR_NONE)
8508 LOGE("failed to unrealize");
8516 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8518 int ret = MM_ERROR_NONE;
8519 mmplayer_t *player = (mmplayer_t *)hplayer;
8520 int idx = 0, total = 0;
8521 gchar *result = NULL, *tmp = NULL;
8524 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8525 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8527 total = *num = g_list_length(player->adaptive_info.var_list);
8529 LOGW("There is no stream variant info.");
8533 result = g_strdup("");
8534 for (idx = 0 ; idx < total ; idx++) {
8535 stream_variant_t *v_data = NULL;
8536 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8539 gchar data[64] = {0};
8540 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8542 tmp = g_strconcat(result, data, NULL);
8546 LOGW("There is no variant data in %d", idx);
8551 *var_info = (char *)result;
8553 LOGD("variant info %d:%s", *num, *var_info);
8559 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8561 int ret = MM_ERROR_NONE;
8562 mmplayer_t *player = (mmplayer_t *)hplayer;
8565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8567 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8569 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8570 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8571 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8573 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8574 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8575 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8576 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8578 /* FIXME: seek to current position for applying new variant limitation */
8587 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8589 int ret = MM_ERROR_NONE;
8590 mmplayer_t *player = (mmplayer_t *)hplayer;
8593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8594 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8596 *bandwidth = player->adaptive_info.limit.bandwidth;
8597 *width = player->adaptive_info.limit.width;
8598 *height = player->adaptive_info.limit.height;
8600 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8607 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8609 int ret = MM_ERROR_NONE;
8610 mmplayer_t *player = (mmplayer_t *)hplayer;
8613 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8614 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8615 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8617 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8619 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8620 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8621 else /* live case */
8622 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8624 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8631 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8633 #define IDX_FIRST_SW_CODEC 0
8634 mmplayer_t *player = (mmplayer_t *)hplayer;
8635 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8640 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8641 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8642 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8644 switch (stream_type) {
8645 case MM_PLAYER_STREAM_TYPE_AUDIO:
8646 /* to support audio codec selection, codec info have to be added in ini file as below.
8647 audio codec element hw = xxxx
8648 audio codec element sw = avdec
8649 and in case of audio hw codec is supported and selected,
8650 audio filter elements should be applied depending on the hw capabilities.
8652 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8653 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8654 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8655 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8656 LOGE("There is no audio codec info for codec_type %d", codec_type);
8657 return MM_ERROR_PLAYER_NO_OP;
8660 case MM_PLAYER_STREAM_TYPE_VIDEO:
8661 /* to support video codec selection, codec info have to be added in ini file as below.
8662 video codec element hw = omx
8663 video codec element sw = avdec */
8664 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8665 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8666 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8667 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8668 LOGE("There is no video codec info for codec_type %d", codec_type);
8669 return MM_ERROR_PLAYER_NO_OP;
8673 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8674 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8678 LOGD("update %s codec_type to %d", attr_name, codec_type);
8679 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8682 return MM_ERROR_NONE;
8686 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8688 mmplayer_t *player = (mmplayer_t *)hplayer;
8689 GstElement *rg_vol_element = NULL;
8693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8695 player->sound.rg_enable = enabled;
8697 /* just hold rgvolume enable value if pipeline is not ready */
8698 if (!player->pipeline || !player->pipeline->audiobin) {
8699 LOGD("pipeline is not ready. holding rgvolume enable value");
8700 return MM_ERROR_NONE;
8703 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8705 if (!rg_vol_element) {
8706 LOGD("rgvolume element is not created");
8707 return MM_ERROR_PLAYER_INTERNAL;
8711 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8713 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8717 return MM_ERROR_NONE;
8721 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8723 mmplayer_t *player = (mmplayer_t *)hplayer;
8724 GstElement *rg_vol_element = NULL;
8725 gboolean enable = FALSE;
8729 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8730 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8732 /* just hold enable_rg value if pipeline is not ready */
8733 if (!player->pipeline || !player->pipeline->audiobin) {
8734 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8735 *enabled = player->sound.rg_enable;
8736 return MM_ERROR_NONE;
8739 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8741 if (!rg_vol_element) {
8742 LOGD("rgvolume element is not created");
8743 return MM_ERROR_PLAYER_INTERNAL;
8746 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8747 *enabled = (bool)enable;
8751 return MM_ERROR_NONE;
8755 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8757 mmplayer_t *player = (mmplayer_t *)hplayer;
8758 MMHandleType attrs = 0;
8760 int ret = MM_ERROR_NONE;
8764 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8766 attrs = MMPLAYER_GET_ATTRS(player);
8767 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8769 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8771 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8772 return MM_ERROR_PLAYER_INTERNAL;
8775 player->video_roi.scale_x = scale_x;
8776 player->video_roi.scale_y = scale_y;
8777 player->video_roi.scale_width = scale_width;
8778 player->video_roi.scale_height = scale_height;
8780 /* check video sinkbin is created */
8781 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8782 return MM_ERROR_NONE;
8784 if (!gst_video_overlay_set_video_roi_area(
8785 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8786 scale_x, scale_y, scale_width, scale_height))
8787 ret = MM_ERROR_PLAYER_INTERNAL;
8789 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8790 scale_x, scale_y, scale_width, scale_height);
8798 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8800 mmplayer_t *player = (mmplayer_t *)hplayer;
8801 int ret = MM_ERROR_NONE;
8805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8806 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8808 *scale_x = player->video_roi.scale_x;
8809 *scale_y = player->video_roi.scale_y;
8810 *scale_width = player->video_roi.scale_width;
8811 *scale_height = player->video_roi.scale_height;
8813 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8814 *scale_x, *scale_y, *scale_width, *scale_height);
8820 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8822 mmplayer_t *player = (mmplayer_t *)hplayer;
8826 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8828 player->client_pid = pid;
8830 LOGD("client pid[%d] %p", pid, player);
8834 return MM_ERROR_NONE;
8838 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8840 mmplayer_t *player = (mmplayer_t *)hplayer;
8841 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8842 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8846 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8847 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8850 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8852 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8854 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8855 return MM_ERROR_NONE;
8857 /* in case of audio codec default type is HW */
8859 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8860 if (player->ini.support_audio_effect)
8861 return MM_ERROR_NONE;
8862 elem_id = MMPLAYER_A_FILTER;
8864 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8865 if (player->ini.support_replaygain_control)
8866 return MM_ERROR_NONE;
8867 elem_id = MMPLAYER_A_RGVOL;
8869 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8870 if (player->ini.support_pitch_control)
8871 return MM_ERROR_NONE;
8872 elem_id = MMPLAYER_A_PITCH;
8874 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8875 if (player->ini.support_audio_effect)
8876 return MM_ERROR_NONE;
8878 /* default case handling is not required */
8881 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8882 LOGW("audio control option [%d] is not available", opt);
8885 /* setting pcm exporting option is allowed before READY state */
8886 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8887 return MM_ERROR_PLAYER_INVALID_STATE;
8889 /* check whether the audio filter exist or not after READY state,
8890 because the sw codec could be added during auto-plugging in some cases */
8891 if (!player->pipeline ||
8892 !player->pipeline->audiobin ||
8893 !player->pipeline->audiobin[elem_id].gst) {
8894 LOGW("there is no audio elem [%d]", elem_id);
8899 LOGD("audio control opt %d, available %d", opt, *available);
8903 return MM_ERROR_NONE;
8907 __mmplayer_update_duration_value(mmplayer_t *player)
8909 gboolean ret = FALSE;
8910 gint64 dur_nsec = 0;
8911 LOGD("try to update duration");
8913 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8914 player->duration = dur_nsec;
8915 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8919 if (player->duration < 0) {
8920 LOGW("duration is Non-Initialized !!!");
8921 player->duration = 0;
8924 /* update streaming service type */
8925 player->streaming_type = _mmplayer_get_stream_service_type(player);
8927 /* check duration is OK */
8928 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8929 /* FIXIT : find another way to get duration here. */
8930 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8936 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8938 /* update audio params
8939 NOTE : We need original audio params and it can be only obtained from src pad of audio
8940 decoder. Below code only valid when we are not using 'resampler' just before
8941 'audioconverter'. */
8942 GstCaps *caps_a = NULL;
8944 gint samplerate = 0, channels = 0;
8945 GstStructure *p = NULL;
8946 GstElement *aconv = NULL;
8948 LOGD("try to update audio attrs");
8950 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8952 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8953 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8954 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8955 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8957 LOGE("there is no audio converter");
8961 pad = gst_element_get_static_pad(aconv, "sink");
8964 LOGW("failed to get pad from audio converter");
8968 caps_a = gst_pad_get_current_caps(pad);
8970 LOGW("not ready to get audio caps");
8971 gst_object_unref(pad);
8975 p = gst_caps_get_structure(caps_a, 0);
8977 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8979 gst_structure_get_int(p, "rate", &samplerate);
8980 gst_structure_get_int(p, "channels", &channels);
8982 mm_player_set_attribute((MMHandleType)player, NULL,
8983 "content_audio_samplerate", samplerate,
8984 "content_audio_channels", channels, NULL);
8986 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8988 gst_caps_unref(caps_a);
8989 gst_object_unref(pad);
8995 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8997 LOGD("try to update video attrs");
8999 GstCaps *caps_v = NULL;
9003 GstStructure *p = NULL;
9005 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9006 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9008 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9010 LOGD("no videosink sink pad");
9014 caps_v = gst_pad_get_current_caps(pad);
9015 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9016 if (!caps_v && player->v_stream_caps) {
9017 caps_v = player->v_stream_caps;
9018 gst_caps_ref(caps_v);
9022 LOGD("no negitiated caps from videosink");
9023 gst_object_unref(pad);
9027 p = gst_caps_get_structure(caps_v, 0);
9028 gst_structure_get_int(p, "width", &width);
9029 gst_structure_get_int(p, "height", &height);
9031 mm_player_set_attribute((MMHandleType)player, NULL,
9032 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9034 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9036 SECURE_LOGD("width : %d height : %d", width, height);
9038 gst_caps_unref(caps_v);
9039 gst_object_unref(pad);
9042 mm_player_set_attribute((MMHandleType)player, NULL,
9043 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9044 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9051 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9053 gboolean ret = FALSE;
9054 guint64 data_size = 0;
9058 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9059 if (!player->duration)
9062 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9063 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9064 if (stat(path, &sb) == 0)
9065 data_size = (guint64)sb.st_size;
9067 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9068 data_size = player->http_content_size;
9071 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9074 guint64 bitrate = 0;
9075 guint64 msec_dur = 0;
9077 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9079 bitrate = data_size * 8 * 1000 / msec_dur;
9080 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9081 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9082 mm_player_set_attribute((MMHandleType)player, NULL,
9083 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9086 LOGD("player duration is less than 0");
9090 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9091 if (player->total_bitrate) {
9092 mm_player_set_attribute((MMHandleType)player, NULL,
9093 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9102 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9104 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9105 data->uri_type = uri_type;
9109 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9111 int ret = MM_ERROR_PLAYER_INVALID_URI;
9113 char *buffer = NULL;
9114 char *seperator = strchr(path, ',');
9115 char ext[100] = {0,}, size[100] = {0,};
9118 if ((buffer = strstr(path, "ext="))) {
9119 buffer += strlen("ext=");
9121 if (strlen(buffer)) {
9122 strncpy(ext, buffer, 99);
9124 if ((seperator = strchr(ext, ','))
9125 || (seperator = strchr(ext, ' '))
9126 || (seperator = strchr(ext, '\0'))) {
9127 seperator[0] = '\0';
9132 if ((buffer = strstr(path, "size="))) {
9133 buffer += strlen("size=");
9135 if (strlen(buffer) > 0) {
9136 strncpy(size, buffer, 99);
9138 if ((seperator = strchr(size, ','))
9139 || (seperator = strchr(size, ' '))
9140 || (seperator = strchr(size, '\0'))) {
9141 seperator[0] = '\0';
9144 mem_size = atoi(size);
9149 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9151 if (mem_size && param) {
9152 if (data->input_mem.buf)
9153 free(data->input_mem.buf);
9154 data->input_mem.buf = malloc(mem_size);
9156 if (data->input_mem.buf) {
9157 memcpy(data->input_mem.buf, param, mem_size);
9158 data->input_mem.len = mem_size;
9159 ret = MM_ERROR_NONE;
9161 LOGE("failed to alloc mem %d", mem_size);
9162 ret = MM_ERROR_PLAYER_INTERNAL;
9165 data->input_mem.offset = 0;
9166 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9173 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9175 gchar *location = NULL;
9178 int ret = MM_ERROR_NONE;
9180 if ((path = strstr(uri, "file://"))) {
9181 location = g_filename_from_uri(uri, NULL, &err);
9182 if (!location || (err != NULL)) {
9183 LOGE("Invalid URI '%s' for filesrc: %s", path,
9184 (err != NULL) ? err->message : "unknown error");
9188 MMPLAYER_FREEIF(location);
9190 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9191 return MM_ERROR_PLAYER_INVALID_URI;
9193 LOGD("path from uri: %s", location);
9196 path = (location != NULL) ? (location) : ((char *)uri);
9199 ret = _mmplayer_exist_file_path(path);
9201 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9202 if (ret == MM_ERROR_NONE) {
9203 if (_mmplayer_is_sdp_file(path)) {
9204 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9205 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9206 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9208 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9209 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9211 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9212 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9214 LOGE("invalid uri, could not play..");
9215 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9218 MMPLAYER_FREEIF(location);
9223 static mmplayer_video_decoded_data_info_t *
9224 __mmplayer_create_stream_from_pad(GstPad *pad)
9226 GstCaps *caps = NULL;
9227 GstStructure *structure = NULL;
9228 unsigned int fourcc = 0;
9229 const gchar *string_format = NULL;
9230 mmplayer_video_decoded_data_info_t *stream = NULL;
9232 MMPixelFormatType format;
9235 caps = gst_pad_get_current_caps(pad);
9237 LOGE("Caps is NULL.");
9242 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9244 structure = gst_caps_get_structure(caps, 0);
9245 gst_structure_get_int(structure, "width", &width);
9246 gst_structure_get_int(structure, "height", &height);
9247 string_format = gst_structure_get_string(structure, "format");
9250 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9251 format = _mmplayer_get_pixtype(fourcc);
9252 gst_video_info_from_caps(&info, caps);
9253 gst_caps_unref(caps);
9256 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9257 LOGE("Wrong condition!!");
9261 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9263 LOGE("failed to alloc mem for video data");
9267 stream->width = width;
9268 stream->height = height;
9269 stream->format = format;
9270 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9276 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9278 unsigned int pitch = 0;
9279 unsigned int size = 0;
9281 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9284 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9285 bo = gst_tizen_memory_get_bos(mem, index);
9287 stream->bo[index] = tbm_bo_ref(bo);
9289 LOGE("failed to get bo for index %d", index);
9292 for (index = 0; index < stream->plane_num; index++) {
9293 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9294 stream->stride[index] = pitch;
9296 stream->elevation[index] = size / pitch;
9298 stream->elevation[index] = stream->height;
9303 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9305 if (stream->format == MM_PIXEL_FORMAT_I420) {
9306 int ret = TBM_SURFACE_ERROR_NONE;
9307 tbm_surface_h surface;
9308 tbm_surface_info_s info;
9310 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9312 ret = tbm_surface_get_info(surface, &info);
9313 if (ret != TBM_SURFACE_ERROR_NONE) {
9314 tbm_surface_destroy(surface);
9318 tbm_surface_destroy(surface);
9319 stream->stride[0] = info.planes[0].stride;
9320 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9321 stream->stride[1] = info.planes[1].stride;
9322 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9323 stream->stride[2] = info.planes[2].stride;
9324 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9325 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9326 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9327 stream->stride[0] = stream->width * 4;
9328 stream->elevation[0] = stream->height;
9329 stream->bo_size = stream->stride[0] * stream->height;
9331 LOGE("Not support format %d", stream->format);
9339 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9341 tbm_bo_handle thandle;
9343 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9344 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9345 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9349 unsigned char *src = NULL;
9350 unsigned char *dest = NULL;
9351 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9353 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9355 LOGE("fail to gst_memory_map");
9359 if (!mapinfo.data) {
9360 LOGE("data pointer is wrong");
9364 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9365 if (!stream->bo[0]) {
9366 LOGE("Fail to tbm_bo_alloc!!");
9370 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9372 LOGE("thandle pointer is wrong");
9376 if (stream->format == MM_PIXEL_FORMAT_I420) {
9377 src_stride[0] = GST_ROUND_UP_4(stream->width);
9378 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9379 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9380 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9383 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9384 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9386 for (i = 0; i < 3; i++) {
9387 src = mapinfo.data + src_offset[i];
9388 dest = thandle.ptr + dest_offset[i];
9393 for (j = 0; j < stream->height >> k; j++) {
9394 memcpy(dest, src, stream->width>>k);
9395 src += src_stride[i];
9396 dest += stream->stride[i];
9399 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9400 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9402 LOGE("Not support format %d", stream->format);
9406 tbm_bo_unmap(stream->bo[0]);
9407 gst_memory_unmap(mem, &mapinfo);
9413 tbm_bo_unmap(stream->bo[0]);
9416 gst_memory_unmap(mem, &mapinfo);
9422 __mmplayer_set_pause_state(mmplayer_t *player)
9424 if (player->sent_bos)
9427 /* rtsp case, get content attrs by GstMessage */
9428 if (MMPLAYER_IS_RTSP_STREAMING(player))
9431 /* it's first time to update all content attrs. */
9432 _mmplayer_update_content_attrs(player, ATTR_ALL);
9436 __mmplayer_set_playing_state(mmplayer_t *player)
9438 gchar *audio_codec = NULL;
9440 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9441 /* initialize because auto resume is done well. */
9442 player->resumed_by_rewind = FALSE;
9443 player->playback_rate = 1.0;
9446 if (player->sent_bos)
9449 /* try to get content metadata */
9451 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9452 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9453 * legacy mmfw-player api
9455 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9457 if ((player->cmd == MMPLAYER_COMMAND_START)
9458 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9459 __mmplayer_handle_missed_plugin(player);
9462 /* check audio codec field is set or not
9463 * we can get it from typefinder or codec's caps.
9465 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9467 /* The codec format can't be sent for audio only case like amr, mid etc.
9468 * Because, parser don't make related TAG.
9469 * So, if it's not set yet, fill it with found data.
9472 if (g_strrstr(player->type, "audio/midi"))
9473 audio_codec = "MIDI";
9474 else if (g_strrstr(player->type, "audio/x-amr"))
9475 audio_codec = "AMR";
9476 else if (g_strrstr(player->type, "audio/mpeg")
9477 && !g_strrstr(player->type, "mpegversion=(int)1"))
9478 audio_codec = "AAC";
9480 audio_codec = "unknown";
9482 if (mm_player_set_attribute((MMHandleType)player, NULL,
9483 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9484 LOGE("failed to set attribute");
9486 LOGD("set audio codec type with caps");