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);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
177 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
178 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
179 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
180 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
181 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
182 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
183 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
187 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
188 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
189 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
191 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
192 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
193 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
194 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
196 static void __mmplayer_set_pause_state(mmplayer_t *player);
197 static void __mmplayer_set_playing_state(mmplayer_t *player);
198 /*===========================================================================================
200 | FUNCTION DEFINITIONS |
202 ========================================================================================== */
204 /* This function should be called after the pipeline goes PAUSED or higher
207 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
209 static gboolean has_duration = FALSE;
210 static gboolean has_video_attrs = FALSE;
211 static gboolean has_audio_attrs = FALSE;
212 static gboolean has_bitrate = FALSE;
213 gboolean missing_only = FALSE;
214 gboolean all = FALSE;
215 MMHandleType attrs = 0;
219 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
221 /* check player state here */
222 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
223 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
224 /* give warning now only */
225 LOGW("be careful. content attributes may not available in this state ");
228 /* get content attribute first */
229 attrs = MMPLAYER_GET_ATTRS(player);
231 LOGE("cannot get content attribute");
235 /* get update flag */
237 if (flag & ATTR_MISSING_ONLY) {
239 LOGD("updating missed attr only");
242 if (flag & ATTR_ALL) {
244 has_duration = FALSE;
245 has_video_attrs = FALSE;
246 has_audio_attrs = FALSE;
249 LOGD("updating all attrs");
252 if (missing_only && all) {
253 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
254 missing_only = FALSE;
257 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
258 has_duration = __mmplayer_update_duration_value(player);
260 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
261 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
263 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
264 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
266 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
267 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
275 _mmplayer_get_stream_service_type(mmplayer_t *player)
277 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
281 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
283 player->pipeline->mainbin &&
284 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
285 STREAMING_SERVICE_NONE);
287 /* streaming service type if streaming */
288 if (!MMPLAYER_IS_STREAMING(player))
289 return STREAMING_SERVICE_NONE;
291 streaming_type = (player->duration == 0) ?
292 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
294 switch (streaming_type) {
295 case STREAMING_SERVICE_LIVE:
296 LOGD("it's live streaming");
298 case STREAMING_SERVICE_VOD:
299 LOGD("it's vod streaming");
302 LOGE("should not get here");
308 return streaming_type;
311 /* this function sets the player state and also report
312 * it to applicaton by calling callback function
315 _mmplayer_set_state(mmplayer_t *player, int state)
317 MMMessageParamType msg = {0, };
319 MMPLAYER_RETURN_IF_FAIL(player);
321 if (MMPLAYER_CURRENT_STATE(player) == state) {
322 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
323 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
327 /* update player states */
328 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
329 MMPLAYER_CURRENT_STATE(player) = state;
331 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
332 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
335 MMPLAYER_PRINT_STATE(player);
337 switch (MMPLAYER_CURRENT_STATE(player)) {
338 case MM_PLAYER_STATE_NULL:
339 case MM_PLAYER_STATE_READY:
341 case MM_PLAYER_STATE_PAUSED:
342 __mmplayer_set_pause_state(player);
344 case MM_PLAYER_STATE_PLAYING:
345 __mmplayer_set_playing_state(player);
347 case MM_PLAYER_STATE_NONE:
349 LOGW("invalid target state, there is nothing to do.");
354 /* post message to application */
355 if (MMPLAYER_TARGET_STATE(player) == state) {
356 /* fill the message with state of player */
357 msg.union_type = MM_MSG_UNION_STATE;
358 msg.state.previous = MMPLAYER_PREV_STATE(player);
359 msg.state.current = MMPLAYER_CURRENT_STATE(player);
361 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
363 /* state changed by resource callback */
364 if (player->interrupted_by_resource)
365 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
366 else /* state changed by usecase */
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
370 LOGD("intermediate state, do nothing.");
371 MMPLAYER_PRINT_STATE(player);
375 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
376 && !player->sent_bos) {
377 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
378 player->sent_bos = TRUE;
385 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
387 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
388 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
390 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
392 LOGD("incomming command : %d ", command);
394 current_state = MMPLAYER_CURRENT_STATE(player);
395 pending_state = MMPLAYER_PENDING_STATE(player);
397 MMPLAYER_PRINT_STATE(player);
400 case MMPLAYER_COMMAND_CREATE:
402 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
404 if (current_state == MM_PLAYER_STATE_NULL ||
405 current_state == MM_PLAYER_STATE_READY ||
406 current_state == MM_PLAYER_STATE_PAUSED ||
407 current_state == MM_PLAYER_STATE_PLAYING)
412 case MMPLAYER_COMMAND_DESTROY:
414 /* destroy can called anytime */
416 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
420 case MMPLAYER_COMMAND_REALIZE:
422 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
424 if (pending_state != MM_PLAYER_STATE_NONE) {
427 /* need ready state to realize */
428 if (current_state == MM_PLAYER_STATE_READY)
431 if (current_state != MM_PLAYER_STATE_NULL)
437 case MMPLAYER_COMMAND_UNREALIZE:
439 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
441 if (current_state == MM_PLAYER_STATE_NULL)
446 case MMPLAYER_COMMAND_START:
448 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
450 if (pending_state == MM_PLAYER_STATE_NONE) {
451 if (current_state == MM_PLAYER_STATE_PLAYING)
453 else if (current_state != MM_PLAYER_STATE_READY &&
454 current_state != MM_PLAYER_STATE_PAUSED)
456 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
458 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
459 LOGD("player is going to paused state, just change the pending state as playing");
466 case MMPLAYER_COMMAND_STOP:
468 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
470 if (current_state == MM_PLAYER_STATE_READY)
473 /* need playing/paused state to stop */
474 if (current_state != MM_PLAYER_STATE_PLAYING &&
475 current_state != MM_PLAYER_STATE_PAUSED)
480 case MMPLAYER_COMMAND_PAUSE:
482 if (MMPLAYER_IS_LIVE_STREAMING(player))
485 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
486 goto NOT_COMPLETED_SEEK;
488 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
490 if (pending_state == MM_PLAYER_STATE_NONE) {
491 if (current_state == MM_PLAYER_STATE_PAUSED)
493 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
495 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
497 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
498 if (current_state == MM_PLAYER_STATE_PAUSED)
499 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
506 case MMPLAYER_COMMAND_RESUME:
508 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
509 goto NOT_COMPLETED_SEEK;
511 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
513 if (pending_state == MM_PLAYER_STATE_NONE) {
514 if (current_state == MM_PLAYER_STATE_PLAYING)
516 else if (current_state != MM_PLAYER_STATE_PAUSED)
518 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
520 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
521 LOGD("player is going to paused state, just change the pending state as playing");
531 player->cmd = command;
533 return MM_ERROR_NONE;
536 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
537 MMPLAYER_STATE_GET_NAME(current_state), command);
538 return MM_ERROR_PLAYER_INVALID_STATE;
541 LOGW("not completed seek");
542 return MM_ERROR_PLAYER_DOING_SEEK;
545 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
546 return MM_ERROR_PLAYER_NO_OP;
549 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
550 return MM_ERROR_PLAYER_NO_OP;
553 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
555 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
556 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
559 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
560 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
562 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
563 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
565 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
566 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
569 LOGE("invalid mmplayer resource type %d", type);
570 return MM_ERROR_PLAYER_INTERNAL;
573 if (player->hw_resource[type] != NULL) {
574 LOGD("[%d type] resource was already acquired", type);
575 return MM_ERROR_NONE;
578 LOGD("mark for acquire [%d type] resource", type);
579 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
580 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
581 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
582 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
583 return MM_ERROR_PLAYER_INTERNAL;
586 rm_ret = mm_resource_manager_commit(player->resource_manager);
587 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
588 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
589 return MM_ERROR_PLAYER_INTERNAL;
593 return MM_ERROR_NONE;
596 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
598 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
602 if (player->hw_resource[type] == NULL) {
603 LOGD("there is no acquired [%d type] resource", type);
604 return MM_ERROR_NONE;
607 LOGD("mark for release [%d type] resource", type);
608 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
609 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
610 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
611 return MM_ERROR_PLAYER_INTERNAL;
614 player->hw_resource[type] = NULL;
616 rm_ret = mm_resource_manager_commit(player->resource_manager);
617 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
618 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
619 return MM_ERROR_PLAYER_INTERNAL;
623 return MM_ERROR_NONE;
627 __mmplayer_initialize_gapless_play(mmplayer_t *player)
633 player->smooth_streaming = FALSE;
634 player->videodec_linked = 0;
635 player->audiodec_linked = 0;
636 player->textsink_linked = 0;
637 player->is_external_subtitle_present = FALSE;
638 player->is_external_subtitle_added_now = FALSE;
639 player->not_supported_codec = MISSING_PLUGIN_NONE;
640 player->can_support_codec = FOUND_PLUGIN_NONE;
641 player->pending_seek.is_pending = false;
642 player->pending_seek.pos = 0;
643 player->msg_posted = FALSE;
644 player->has_many_types = FALSE;
645 player->no_more_pad = FALSE;
646 player->not_found_demuxer = 0;
647 player->seek_state = MMPLAYER_SEEK_NONE;
648 player->is_subtitle_force_drop = FALSE;
649 player->play_subtitle = FALSE;
650 player->adjust_subtitle_pos = 0;
652 player->total_bitrate = 0;
653 player->total_maximum_bitrate = 0;
655 _mmplayer_track_initialize(player);
656 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
658 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
659 player->bitrate[i] = 0;
660 player->maximum_bitrate[i] = 0;
663 if (player->v_stream_caps) {
664 gst_caps_unref(player->v_stream_caps);
665 player->v_stream_caps = NULL;
668 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
670 /* clean found audio decoders */
671 if (player->audio_decoders) {
672 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
673 player->audio_decoders = NULL;
676 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
681 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
683 LOGI("set pipeline reconfigure state %d", state);
684 MMPLAYER_RECONFIGURE_LOCK(player);
685 player->gapless.reconfigure = state;
686 if (!state) /* wake up the waiting job */
687 MMPLAYER_RECONFIGURE_SIGNAL(player);
688 MMPLAYER_RECONFIGURE_UNLOCK(player);
692 __mmplayer_gapless_play_thread(gpointer data)
694 mmplayer_t *player = (mmplayer_t *)data;
695 mmplayer_gst_element_t *mainbin = NULL;
697 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
699 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
700 while (!player->gapless_play_thread_exit) {
701 LOGD("gapless play thread started. waiting for signal.");
702 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
704 LOGD("reconfigure pipeline for gapless play.");
706 if (player->gapless_play_thread_exit) {
707 _mmplayer_set_reconfigure_state(player, FALSE);
708 LOGD("exiting gapless play thread");
712 mainbin = player->pipeline->mainbin;
714 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
715 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
716 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
717 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
718 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
720 /* Initialize Player values */
721 __mmplayer_initialize_gapless_play(player);
723 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
725 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
731 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
733 GSource *source = NULL;
737 source = g_main_context_find_source_by_id(context, source_id);
738 if (source != NULL) {
739 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
740 g_source_destroy(source);
747 _mmplayer_watcher_removed_notify(gpointer data)
749 mmplayer_t *player = (mmplayer_t *)data;
750 MMPLAYER_RETURN_IF_FAIL(player);
752 MMPLAYER_BUS_WATCHER_LOCK(player);
753 player->bus_watcher = 0;
754 MMPLAYER_BUS_WATCHER_SIGNAL(player);
755 MMPLAYER_BUS_WATCHER_UNLOCK(player);
759 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
764 MMPLAYER_RETURN_IF_FAIL(player);
766 /* disconnecting bus watch */
767 if (player->bus_watcher > 0) {
768 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
769 MMPLAYER_BUS_WATCHER_LOCK(player);
770 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
771 while (player->bus_watcher > 0)
772 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
773 MMPLAYER_BUS_WATCHER_UNLOCK(player);
775 g_mutex_clear(&player->bus_watcher_mutex);
776 g_cond_clear(&player->bus_watcher_cond);
783 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
785 mmplayer_t *player = (mmplayer_t *)hplayer;
786 GstMessage *msg = NULL;
787 GQueue *queue = NULL;
790 MMPLAYER_RETURN_IF_FAIL(player);
792 /* destroy the gst bus msg thread */
793 if (player->bus_msg_thread) {
794 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
795 player->bus_msg_thread_exit = TRUE;
796 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
797 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
799 LOGD("gst bus msg thread exit.");
800 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
801 player->bus_msg_thread = NULL;
803 g_mutex_clear(&player->bus_msg_thread_mutex);
804 g_cond_clear(&player->bus_msg_thread_cond);
807 g_mutex_lock(&player->bus_msg_q_lock);
808 queue = player->bus_msg_q;
809 while (!g_queue_is_empty(queue)) {
810 msg = (GstMessage *)g_queue_pop_head(queue);
815 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
816 gst_message_unref(msg);
818 g_mutex_unlock(&player->bus_msg_q_lock);
824 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
826 GstElement *parent = NULL;
828 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
829 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
832 MMPLAYER_FSINK_LOCK(player);
834 /* get parent of fakesink */
835 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
837 LOGD("fakesink already removed");
841 gst_element_set_locked_state(fakesink->gst, TRUE);
843 /* setting the state to NULL never returns async
844 * so no need to wait for completion of state transiton
846 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
847 LOGE("fakesink state change failure!");
848 /* FIXIT : should I return here? or try to proceed to next? */
851 /* remove fakesink from it's parent */
852 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
853 LOGE("failed to remove fakesink");
855 gst_object_unref(parent);
860 gst_object_unref(parent);
862 LOGD("state-holder removed");
864 gst_element_set_locked_state(fakesink->gst, FALSE);
866 MMPLAYER_FSINK_UNLOCK(player);
871 gst_element_set_locked_state(fakesink->gst, FALSE);
873 MMPLAYER_FSINK_UNLOCK(player);
877 static GstPadProbeReturn
878 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
880 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
881 return GST_PAD_PROBE_OK;
885 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
887 gint64 stop_running_time = 0;
888 gint64 position_running_time = 0;
892 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
893 if ((player->gapless.update_segment[idx] == TRUE) ||
894 !(player->track[idx].event_probe_id)) {
896 LOGW("[%d] skip", idx);
901 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
903 gst_segment_to_running_time(&player->gapless.segment[idx],
904 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
905 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
907 gst_segment_to_running_time(&player->gapless.segment[idx],
908 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
910 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
912 gst_segment_to_running_time(&player->gapless.segment[idx],
913 GST_FORMAT_TIME, player->duration);
916 position_running_time =
917 gst_segment_to_running_time(&player->gapless.segment[idx],
918 GST_FORMAT_TIME, player->gapless.segment[idx].position);
920 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
921 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
923 GST_TIME_ARGS(stop_running_time),
924 GST_TIME_ARGS(position_running_time),
925 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
926 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
928 position_running_time = MAX(position_running_time, stop_running_time);
929 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
930 GST_FORMAT_TIME, player->gapless.segment[idx].start);
931 position_running_time = MAX(0, position_running_time);
932 position = MAX(position, position_running_time);
936 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
937 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
938 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
940 player->gapless.start_time[stream_type] += position;
946 static GstPadProbeReturn
947 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
949 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
950 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
951 mmplayer_t *player = (mmplayer_t *)data;
952 GstCaps *caps = NULL;
953 GstStructure *str = NULL;
954 const gchar *name = NULL;
955 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
956 gboolean caps_ret = TRUE;
958 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
959 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
960 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
961 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
962 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
965 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
969 if (strstr(name, "audio")) {
970 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
971 } else if (strstr(name, "video")) {
972 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
974 /* text track is not supportable */
975 LOGE("invalid name %s", name);
979 switch (GST_EVENT_TYPE(event)) {
982 /* in case of gapless, drop eos event not to send it to sink */
983 if (player->gapless.reconfigure && !player->msg_posted) {
984 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
985 ret = GST_PAD_PROBE_DROP;
989 case GST_EVENT_STREAM_START:
991 __mmplayer_gst_selector_update_start_time(player, stream_type);
994 case GST_EVENT_FLUSH_STOP:
996 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
997 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
998 player->gapless.start_time[stream_type] = 0;
1001 case GST_EVENT_SEGMENT:
1006 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1007 gst_event_copy_segment(event, &segment);
1009 if (segment.format != GST_FORMAT_TIME)
1012 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1013 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1014 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1015 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1016 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1017 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1019 /* keep the all the segment ev to cover the seeking */
1020 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1021 player->gapless.update_segment[stream_type] = TRUE;
1023 if (!player->gapless.running)
1026 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1028 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1030 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1031 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1032 gst_event_unref(event);
1033 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1039 gdouble proportion = 0.0;
1040 GstClockTimeDiff diff = 0;
1041 GstClockTime timestamp = 0;
1042 gint64 running_time_diff = -1;
1043 GstQOSType type = 0;
1044 GstEvent *tmpev = NULL;
1046 running_time_diff = player->gapless.segment[stream_type].base;
1048 if (running_time_diff <= 0) /* don't need to adjust */
1051 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1052 gst_event_unref(event);
1054 if (timestamp < running_time_diff) {
1055 LOGW("QOS event from previous group");
1056 ret = GST_PAD_PROBE_DROP;
1061 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1062 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1063 stream_type, GST_TIME_ARGS(timestamp),
1064 GST_TIME_ARGS(running_time_diff),
1065 GST_TIME_ARGS(timestamp - running_time_diff));
1068 timestamp -= running_time_diff;
1070 /* That case is invalid for QoS events */
1071 if (diff < 0 && -diff > timestamp) {
1072 LOGW("QOS event from previous group");
1073 ret = GST_PAD_PROBE_DROP;
1077 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1078 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1088 gst_caps_unref(caps);
1092 /* create fakesink for audio or video path witout audiobin or videobin */
1094 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1096 GstElement *pipeline = NULL;
1097 GstElement *fakesink = NULL;
1098 GstPad *sinkpad = NULL;
1101 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1103 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1106 fakesink = gst_element_factory_make("fakesink", NULL);
1107 if (fakesink == NULL) {
1108 LOGE("failed to create fakesink");
1112 /* store it as it's sink element */
1113 __mmplayer_add_sink(player, fakesink);
1115 gst_bin_add(GST_BIN(pipeline), fakesink);
1118 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1120 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1122 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1123 LOGE("failed to link fakesink");
1124 gst_object_unref(GST_OBJECT(fakesink));
1128 if (strstr(name, "video")) {
1129 if (player->v_stream_caps) {
1130 gst_caps_unref(player->v_stream_caps);
1131 player->v_stream_caps = NULL;
1133 if (player->ini.set_dump_element_flag)
1134 __mmplayer_add_dump_buffer_probe(player, fakesink);
1137 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1138 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1142 gst_object_unref(GST_OBJECT(sinkpad));
1149 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1151 GstElement *pipeline = NULL;
1152 GstElement *selector = NULL;
1153 GstPad *srcpad = NULL;
1156 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1158 selector = gst_element_factory_make("input-selector", NULL);
1160 LOGE("failed to create input-selector");
1163 g_object_set(selector, "sync-streams", TRUE, NULL);
1165 player->pipeline->mainbin[elem_idx].id = elem_idx;
1166 player->pipeline->mainbin[elem_idx].gst = selector;
1168 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1170 srcpad = gst_element_get_static_pad(selector, "src");
1172 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1173 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1174 __mmplayer_gst_selector_blocked, NULL, NULL);
1175 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1176 __mmplayer_gst_selector_event_probe, player, NULL);
1178 gst_element_set_state(selector, GST_STATE_PAUSED);
1180 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1181 gst_bin_add(GST_BIN(pipeline), selector);
1183 gst_object_unref(GST_OBJECT(srcpad));
1190 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1192 mmplayer_t *player = (mmplayer_t *)data;
1193 GstElement *selector = NULL;
1194 GstCaps *caps = NULL;
1195 GstStructure *str = NULL;
1196 const gchar *name = NULL;
1197 GstPad *sinkpad = NULL;
1198 gboolean first_track = FALSE;
1199 gboolean caps_ret = TRUE;
1201 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1202 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1205 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1206 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1208 LOGD("pad-added signal handling");
1210 /* get mimetype from caps */
1211 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1215 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1217 LOGD("detected mimetype : %s", name);
1220 if (strstr(name, "video")) {
1222 gchar *caps_str = NULL;
1224 caps_str = gst_caps_to_string(caps);
1225 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1226 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1227 player->set_mode.video_zc = true;
1229 MMPLAYER_FREEIF(caps_str);
1231 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1232 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1234 LOGD("surface type : %d", stype);
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || !MMPLAYER_USE_DECODEBIN(player)) {
1237 __mmplayer_gst_create_sinkbin(elem, pad, player);
1241 /* in case of exporting video frame, it requires the 360 video filter.
1242 * it will be handled in _no_more_pads(). */
1243 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1244 __mmplayer_gst_make_fakesink(player, pad, name);
1248 LOGD("video selector is required");
1249 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1250 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1251 } else if (strstr(name, "audio")) {
1252 gint samplerate = 0;
1255 if (MMPLAYER_IS_MS_BUFF_SRC(player) || !MMPLAYER_USE_DECODEBIN(player) || player->build_audio_offload) {
1256 if (player->build_audio_offload)
1257 player->no_more_pad = TRUE; /* remove state holder */
1258 __mmplayer_gst_create_sinkbin(elem, pad, player);
1262 gst_structure_get_int(str, "rate", &samplerate);
1263 gst_structure_get_int(str, "channels", &channels);
1265 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1266 __mmplayer_gst_make_fakesink(player, pad, name);
1270 LOGD("audio selector is required");
1271 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1272 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1274 } else if (strstr(name, "text")) {
1275 LOGD("text selector is required");
1276 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1277 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1279 LOGE("invalid caps info");
1283 /* check selector and create it */
1284 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1285 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1290 LOGD("input-selector is already created.");
1294 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1296 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1298 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1299 LOGE("failed to link selector");
1300 gst_object_unref(GST_OBJECT(selector));
1305 LOGD("this track will be activated");
1306 g_object_set(selector, "active-pad", sinkpad, NULL);
1309 if (MMPLAYER_USE_DECODEBIN(player))
1310 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1316 gst_caps_unref(caps);
1319 gst_object_unref(GST_OBJECT(sinkpad));
1327 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1329 GstPad *srcpad = NULL;
1332 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1334 LOGD("type %d", type);
1337 LOGD("there is no %d track", type);
1341 srcpad = gst_element_get_static_pad(selector, "src");
1343 LOGE("failed to get srcpad from selector");
1347 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1349 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1351 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1352 if (player->track[type].block_id) {
1353 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1354 player->track[type].block_id = 0;
1358 gst_object_unref(GST_OBJECT(srcpad));
1367 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1369 gint active_index = 0;
1372 MMPLAYER_RETURN_IF_FAIL(player);
1374 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1376 /* change track to active pad */
1377 active_index = player->track[type].active_track_index;
1378 if ((active_index != DEFAULT_TRACK) &&
1379 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1380 LOGW("failed to change %d type track to %d", type, active_index);
1381 player->track[type].active_track_index = DEFAULT_TRACK;
1385 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1386 mm_player_set_attribute((MMHandleType)player, NULL,
1387 "content_text_track_num", player->track[type].total_track_num,
1388 "current_text_track_index", player->track[type].active_track_index, NULL);
1395 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1398 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1400 if (!audio_selector) {
1401 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1403 /* in case the source is changed, output can be changed. */
1404 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1405 LOGD("remove previous audiobin if it exist");
1407 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1408 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1410 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1411 MMPLAYER_FREEIF(player->pipeline->audiobin);
1414 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1415 _mmplayer_pipeline_complete(NULL, player);
1420 /* apply the audio track information */
1421 if (MMPLAYER_USE_DECODEBIN(player))
1422 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1424 /* create audio sink path */
1425 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1426 LOGE("failed to create audio sink path");
1435 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1438 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1440 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1441 LOGD("text path is not supproted");
1445 /* apply the text track information */
1446 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1448 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1449 player->has_closed_caption = TRUE;
1451 /* create text decode path */
1452 player->no_more_pad = TRUE;
1454 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1455 LOGE("failed to create text sink path");
1464 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1466 gint64 dur_bytes = 0L;
1469 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1470 player->pipeline->mainbin && player->streamer, FALSE);
1472 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1473 LOGE("fail to get duration.");
1475 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1476 * use file information was already set on Q2 when it was created. */
1477 _mm_player_streaming_set_queue2(player->streamer,
1478 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1479 TRUE, /* use_buffering */
1480 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1481 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1488 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1490 mmplayer_t *player = NULL;
1491 GstElement *video_selector = NULL;
1492 GstElement *audio_selector = NULL;
1493 GstElement *text_selector = NULL;
1496 player = (mmplayer_t *)data;
1498 LOGD("no-more-pad signal handling");
1500 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1501 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1502 LOGW("player is shutting down");
1506 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1507 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1508 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1509 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1510 LOGE("failed to set queue2 buffering");
1515 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1516 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1517 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1519 if (!video_selector && !audio_selector && !text_selector) {
1520 LOGW("there is no selector");
1521 player->no_more_pad = TRUE;
1525 /* create video path followed by video-select */
1526 if (video_selector && !audio_selector && !text_selector)
1527 player->no_more_pad = TRUE;
1529 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1532 /* create audio path followed by audio-select */
1533 if (audio_selector && !text_selector)
1534 player->no_more_pad = TRUE;
1536 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1539 /* create text path followed by text-select */
1540 __mmplayer_create_text_sink_path(player, text_selector);
1543 _mmplayer_set_reconfigure_state(player, FALSE);
1548 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1550 gboolean ret = FALSE;
1551 GstElement *pipeline = NULL;
1552 GstPad *sinkpad = NULL;
1555 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1556 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1558 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1560 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1562 LOGE("failed to get pad from sinkbin");
1568 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1569 LOGE("failed to link sinkbin for reusing");
1570 goto EXIT; /* exit either pass or fail */
1574 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1575 LOGE("failed to set state(READY) to sinkbin");
1580 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1581 LOGE("failed to add sinkbin to pipeline");
1586 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1587 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1592 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1593 LOGE("failed to set state(PAUSED) to sinkbin");
1602 gst_object_unref(GST_OBJECT(sinkpad));
1610 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1612 mmplayer_t *player = NULL;
1613 GstCaps *caps = NULL;
1614 gchar *caps_str = NULL;
1615 GstStructure *str = NULL;
1616 const gchar *name = NULL;
1617 GstElement *sinkbin = NULL;
1618 gboolean reusing = FALSE;
1619 gboolean caps_ret = TRUE;
1620 gchar *sink_pad_name = "sink";
1623 player = (mmplayer_t *)data;
1626 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1627 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1629 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1633 caps_str = gst_caps_to_string(caps);
1635 LOGD("detected mimetype : %s", name);
1637 if (strstr(name, "audio")) {
1638 if (player->pipeline->audiobin == NULL) {
1639 const gchar *audio_format = gst_structure_get_string(str, "format");
1641 LOGD("original audio format %s", audio_format);
1642 mm_player_set_attribute((MMHandleType)player, NULL,
1643 "content_audio_format", audio_format, strlen(audio_format), NULL);
1646 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1647 LOGE("failed to create audiobin. continuing without audio");
1651 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1652 LOGD("creating audiobin success");
1655 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1656 LOGD("reusing audiobin");
1657 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1659 } else if (strstr(name, "video")) {
1660 /* 1. zero copy is updated at _decode_pad_added()
1661 * 2. NULL surface type is handled in _decode_pad_added() */
1662 LOGD("zero copy %d", player->set_mode.video_zc);
1663 if (player->pipeline->videobin == NULL) {
1664 int surface_type = 0;
1665 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1666 LOGD("display_surface_type (%d)", surface_type);
1668 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1669 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1670 LOGE("failed to acquire video overlay resource");
1674 player->interrupted_by_resource = FALSE;
1676 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1677 LOGE("failed to create videobin. continuing without video");
1681 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1682 LOGD("creating videosink bin success");
1685 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1686 LOGD("re-using videobin");
1687 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1689 } else if (strstr(name, "text")) {
1690 if (player->pipeline->textbin == NULL) {
1691 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1692 LOGE("failed to create text sink bin. continuing without text");
1696 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1697 player->textsink_linked = 1;
1698 LOGD("creating textsink bin success");
1700 if (!player->textsink_linked) {
1701 LOGD("re-using textbin");
1703 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1704 player->textsink_linked = 1;
1706 /* linked textbin exist which means that the external subtitle path exist already */
1707 LOGW("ignoring internal subtutle since external subtitle is available");
1710 sink_pad_name = "text_sink";
1712 LOGW("unknown mime type %s, ignoring it", name);
1716 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1719 LOGD("[handle: %p] success to create and link sink bin", player);
1721 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1722 * streaming task. if the task blocked, then buffer will not flow to the next element
1723 *(autoplugging element). so this is special hack for streaming. please try to remove it
1725 /* dec stream count. we can remove fakesink if it's zero */
1726 if (player->num_dynamic_pad)
1727 player->num_dynamic_pad--;
1729 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1731 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1732 _mmplayer_pipeline_complete(NULL, player);
1736 MMPLAYER_FREEIF(caps_str);
1739 gst_caps_unref(caps);
1745 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1747 int required_angle = 0; /* Angle required for straight view */
1748 int rotation_angle = 0;
1750 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1751 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1753 /* Counter clockwise */
1754 switch (orientation) {
1759 required_angle = 270;
1762 required_angle = 180;
1765 required_angle = 90;
1769 rotation_angle = display_angle + required_angle;
1770 if (rotation_angle >= 360)
1771 rotation_angle -= 360;
1773 /* chech if supported or not */
1774 if (rotation_angle % 90) {
1775 LOGD("not supported rotation angle = %d", rotation_angle);
1779 switch (rotation_angle) {
1781 *value = MM_DISPLAY_ROTATION_NONE;
1784 *value = MM_DISPLAY_ROTATION_90;
1787 *value = MM_DISPLAY_ROTATION_180;
1790 *value = MM_DISPLAY_ROTATION_270;
1794 LOGD("setting rotation property value : %d", *value);
1800 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1802 int display_rotation = 0;
1803 gchar *org_orient = NULL;
1804 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1807 LOGE("cannot get content attribute");
1808 return MM_ERROR_PLAYER_INTERNAL;
1811 if (display_angle) {
1812 /* update user roation */
1813 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1815 /* Counter clockwise */
1816 switch (display_rotation) {
1817 case MM_DISPLAY_ROTATION_NONE:
1820 case MM_DISPLAY_ROTATION_90:
1821 *display_angle = 90;
1823 case MM_DISPLAY_ROTATION_180:
1824 *display_angle = 180;
1826 case MM_DISPLAY_ROTATION_270:
1827 *display_angle = 270;
1830 LOGW("wrong angle type : %d", display_rotation);
1833 LOGD("check user angle: %d", *display_angle);
1837 /* Counter clockwise */
1838 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1841 if (!strcmp(org_orient, "rotate-90"))
1843 else if (!strcmp(org_orient, "rotate-180"))
1845 else if (!strcmp(org_orient, "rotate-270"))
1848 LOGD("original rotation is %s", org_orient);
1850 LOGD("content_video_orientation get fail");
1853 LOGD("check orientation: %d", *orientation);
1856 return MM_ERROR_NONE;
1859 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1861 int rotation_value = 0;
1862 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1863 int display_angle = 0;
1866 /* check video sinkbin is created */
1867 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1870 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1872 /* get rotation value to set */
1873 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1874 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1875 LOGD("set video param : rotate %d", rotation_value);
1878 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1880 MMHandleType attrs = 0;
1884 /* check video sinkbin is created */
1885 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1888 attrs = MMPLAYER_GET_ATTRS(player);
1889 MMPLAYER_RETURN_IF_FAIL(attrs);
1891 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1892 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1893 LOGD("set video param : visible %d", visible);
1896 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1898 MMHandleType attrs = 0;
1899 int display_method = 0;
1902 /* check video sinkbin is created */
1903 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1906 attrs = MMPLAYER_GET_ATTRS(player);
1907 MMPLAYER_RETURN_IF_FAIL(attrs);
1909 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1910 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1911 LOGD("set video param : method %d", display_method);
1914 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1916 MMHandleType attrs = 0;
1920 /* check video sinkbin is created */
1921 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1924 attrs = MMPLAYER_GET_ATTRS(player);
1925 MMPLAYER_RETURN_IF_FAIL(attrs);
1927 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1928 MMPLAYER_RETURN_IF_FAIL(handle);
1930 gst_video_overlay_set_video_roi_area(
1931 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1932 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1933 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1934 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1937 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1939 MMHandleType attrs = 0;
1944 int win_roi_width = 0;
1945 int win_roi_height = 0;
1948 /* check video sinkbin is created */
1949 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1952 attrs = MMPLAYER_GET_ATTRS(player);
1953 MMPLAYER_RETURN_IF_FAIL(attrs);
1955 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1956 MMPLAYER_RETURN_IF_FAIL(handle);
1958 /* It should be set after setting window */
1959 mm_attrs_multiple_get(attrs, NULL,
1960 "display_win_roi_x", &win_roi_x,
1961 "display_win_roi_y", &win_roi_y,
1962 "display_win_roi_width", &win_roi_width,
1963 "display_win_roi_height", &win_roi_height, NULL);
1965 /* After setting window handle, set display roi area */
1966 gst_video_overlay_set_display_roi_area(
1967 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1968 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1969 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1970 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1973 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1975 MMHandleType attrs = 0;
1978 /* check video sinkbin is created */
1979 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1982 attrs = MMPLAYER_GET_ATTRS(player);
1983 MMPLAYER_RETURN_IF_FAIL(attrs);
1985 /* common case if using overlay surface */
1986 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1987 MMPLAYER_RETURN_IF_FAIL(handle);
1989 /* default is using wl_surface_id */
1990 LOGD("set video param : wl_surface_id %d", handle);
1991 gst_video_overlay_set_wl_window_wl_surface_id(
1992 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1997 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1999 gboolean update_all_param = FALSE;
2003 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2004 LOGW("videosink is not ready yet");
2005 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2008 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2009 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2010 return MM_ERROR_PLAYER_INTERNAL;
2013 LOGD("param_name : %s", param_name);
2014 if (!g_strcmp0(param_name, "update_all_param"))
2015 update_all_param = TRUE;
2017 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2018 __mmplayer_video_param_set_display_overlay(player);
2019 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2020 __mmplayer_video_param_set_display_method(player);
2021 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2022 __mmplayer_video_param_set_display_visible(player);
2023 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2024 __mmplayer_video_param_set_display_rotation(player);
2025 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2026 __mmplayer_video_param_set_roi_area(player);
2027 if (update_all_param)
2028 __mmplayer_video_param_set_video_roi_area(player);
2032 return MM_ERROR_NONE;
2036 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2038 gboolean disable_overlay = FALSE;
2039 mmplayer_t *player = (mmplayer_t *)hplayer;
2042 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2043 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2044 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2045 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2047 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2048 LOGW("Display control is not supported");
2049 return MM_ERROR_PLAYER_INTERNAL;
2052 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2054 if (audio_only == (bool)disable_overlay) {
2055 LOGE("It's the same with current setting: (%d)", audio_only);
2056 return MM_ERROR_NONE;
2060 LOGE("disable overlay");
2061 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2063 /* release overlay resource */
2064 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2065 LOGE("failed to release overlay resource");
2069 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2070 LOGE("failed to acquire video overlay resource");
2073 player->interrupted_by_resource = FALSE;
2075 LOGD("enable overlay");
2076 __mmplayer_video_param_set_display_overlay(player);
2077 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2082 return MM_ERROR_NONE;
2086 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2088 mmplayer_t *player = (mmplayer_t *)hplayer;
2089 gboolean disable_overlay = FALSE;
2093 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2094 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2095 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2096 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2097 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2099 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2100 LOGW("Display control is not supported");
2101 return MM_ERROR_PLAYER_INTERNAL;
2104 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2106 *paudio_only = (bool)disable_overlay;
2108 LOGD("audio_only : %d", *paudio_only);
2112 return MM_ERROR_NONE;
2116 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2118 GList *bucket = element_bucket;
2119 mmplayer_gst_element_t *element = NULL;
2120 mmplayer_gst_element_t *prv_element = NULL;
2121 GstElement *tee_element = NULL;
2122 gint successful_link_count = 0;
2126 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2128 prv_element = (mmplayer_gst_element_t *)bucket->data;
2129 bucket = bucket->next;
2131 for (; bucket; bucket = bucket->next) {
2132 element = (mmplayer_gst_element_t *)bucket->data;
2134 if (element && element->gst) {
2135 if (prv_element && prv_element->gst) {
2136 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2138 prv_element->gst = tee_element;
2140 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2141 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2142 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2146 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2147 LOGD("linking [%s] to [%s] success",
2148 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2149 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2150 successful_link_count++;
2151 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2152 LOGD("keep audio-tee element for next audio pipeline branch");
2153 tee_element = prv_element->gst;
2156 LOGD("linking [%s] to [%s] failed",
2157 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2158 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2164 prv_element = element;
2169 return successful_link_count;
2173 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2175 GList *bucket = element_bucket;
2176 mmplayer_gst_element_t *element = NULL;
2177 int successful_add_count = 0;
2181 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2182 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2184 for (; bucket; bucket = bucket->next) {
2185 element = (mmplayer_gst_element_t *)bucket->data;
2187 if (element && element->gst) {
2188 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2189 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2190 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2191 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2194 successful_add_count++;
2200 return successful_add_count;
2204 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2206 mmplayer_t *player = (mmplayer_t *)data;
2207 GstCaps *caps = NULL;
2208 GstStructure *str = NULL;
2210 gboolean caps_ret = TRUE;
2214 MMPLAYER_RETURN_IF_FAIL(pad);
2215 MMPLAYER_RETURN_IF_FAIL(unused);
2216 MMPLAYER_RETURN_IF_FAIL(data);
2218 caps = gst_pad_get_current_caps(pad);
2222 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2226 LOGD("name = %s", name);
2228 if (strstr(name, "audio")) {
2229 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2231 if (player->audio_stream_changed_cb) {
2232 LOGE("call the audio stream changed cb");
2233 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2235 } else if (strstr(name, "video")) {
2236 if ((name = gst_structure_get_string(str, "format")))
2237 player->set_mode.video_zc = name[0] == 'S';
2239 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2240 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2242 LOGW("invalid caps info");
2247 gst_caps_unref(caps);
2255 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2260 MMPLAYER_RETURN_IF_FAIL(player);
2262 if (player->audio_stream_buff_list) {
2263 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2264 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2267 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2268 __mmplayer_audio_stream_send_data(player, tmp);
2270 MMPLAYER_FREEIF(tmp->pcm_data);
2271 MMPLAYER_FREEIF(tmp);
2274 g_list_free(player->audio_stream_buff_list);
2275 player->audio_stream_buff_list = NULL;
2282 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2284 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2287 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2289 audio_stream.bitrate = a_buffer->bitrate;
2290 audio_stream.channel = a_buffer->channel;
2291 audio_stream.channel_mask = a_buffer->channel_mask;
2292 audio_stream.data_size = a_buffer->data_size;
2293 audio_stream.data = a_buffer->pcm_data;
2294 audio_stream.pcm_format = a_buffer->pcm_format;
2296 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2298 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2304 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2306 mmplayer_t *player = (mmplayer_t *)data;
2307 const gchar *pcm_format = NULL;
2310 guint64 channel_mask = 0;
2311 void *a_data = NULL;
2313 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2314 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2318 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2320 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2321 a_data = mapinfo.data;
2322 a_size = mapinfo.size;
2324 GstCaps *caps = gst_pad_get_current_caps(pad);
2325 GstStructure *structure = gst_caps_get_structure(caps, 0);
2327 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2329 pcm_format = gst_structure_get_string(structure, "format");
2330 gst_structure_get_int(structure, "rate", &rate);
2331 gst_structure_get_int(structure, "channels", &channel);
2332 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2333 gst_caps_unref(GST_CAPS(caps));
2335 /* In case of the sync is false, use buffer list. *
2336 * The num of buffer list depends on the num of audio channels */
2337 if (player->audio_stream_buff_list) {
2338 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2339 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2341 if (channel_mask == tmp->channel_mask) {
2343 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2345 if (tmp->data_size + a_size < tmp->buff_size) {
2346 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2347 tmp->data_size += a_size;
2349 /* send data to client */
2350 __mmplayer_audio_stream_send_data(player, tmp);
2352 if (a_size > tmp->buff_size) {
2353 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2354 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2355 if (tmp->pcm_data == NULL) {
2356 LOGE("failed to realloc data.");
2359 tmp->buff_size = a_size;
2361 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2362 memcpy(tmp->pcm_data, a_data, a_size);
2363 tmp->data_size = a_size;
2368 LOGE("data is empty in list.");
2374 /* create new audio stream data for newly found audio channel */
2375 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2376 if (a_buffer == NULL) {
2377 LOGE("failed to alloc data.");
2380 a_buffer->bitrate = rate;
2381 a_buffer->channel = channel;
2382 a_buffer->channel_mask = channel_mask;
2383 a_buffer->data_size = a_size;
2384 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2386 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2387 /* If sync is FALSE, use buffer list to reduce the IPC. */
2388 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2389 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2390 if (a_buffer->pcm_data == NULL) {
2391 LOGE("failed to alloc data.");
2392 MMPLAYER_FREEIF(a_buffer);
2395 memcpy(a_buffer->pcm_data, a_data, a_size);
2397 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2399 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2401 /* If sync is TRUE, send data directly. */
2402 a_buffer->pcm_data = a_data;
2403 __mmplayer_audio_stream_send_data(player, a_buffer);
2404 MMPLAYER_FREEIF(a_buffer);
2408 gst_buffer_unmap(buffer, &mapinfo);
2413 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2415 mmplayer_t *player = (mmplayer_t *)data;
2416 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2417 GstPad *sinkpad = NULL;
2418 GstElement *queue = NULL, *sink = NULL;
2421 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2423 queue = gst_element_factory_make("queue", NULL);
2424 if (queue == NULL) {
2425 LOGD("fail make queue");
2429 sink = gst_element_factory_make("fakesink", NULL);
2431 LOGD("fail make fakesink");
2435 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2437 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2438 LOGW("failed to link queue & sink");
2442 sinkpad = gst_element_get_static_pad(queue, "sink");
2444 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2445 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2449 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2451 gst_object_unref(sinkpad);
2452 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2453 g_object_set(sink, "sync", TRUE, NULL);
2454 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2456 /* keep the first sink reference only */
2457 if (!audiobin[MMPLAYER_A_SINK].gst) {
2458 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2459 audiobin[MMPLAYER_A_SINK].gst = sink;
2463 _mmplayer_add_signal_connection(player,
2465 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2467 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2470 __mmplayer_add_sink(player, sink);
2472 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2473 LOGE("failed to sync state");
2477 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2478 LOGE("failed to sync state");
2486 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2488 gst_object_unref(GST_OBJECT(queue));
2492 gst_object_unref(GST_OBJECT(sink));
2496 gst_object_unref(GST_OBJECT(sinkpad));
2504 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2506 mmplayer_t *player = (mmplayer_t *)data;
2509 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2511 player->no_more_pad = TRUE;
2512 _mmplayer_pipeline_complete(NULL, player);
2519 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2521 #define MAX_PROPS_LEN 128
2522 mmplayer_gst_element_t *audiobin = NULL;
2523 gint latency_mode = 0;
2524 gchar *stream_type = NULL;
2525 gchar *latency = NULL;
2527 gchar stream_props[MAX_PROPS_LEN] = {0,};
2528 GstStructure *props = NULL;
2531 * It should be set after player creation through attribute.
2532 * But, it can not be changed during playing.
2535 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2537 audiobin = player->pipeline->audiobin;
2539 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2540 if (player->sound.mute) {
2541 LOGD("mute enabled");
2542 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2545 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2546 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2549 snprintf(stream_props, sizeof(stream_props) - 1,
2550 "props,application.process.id.origin=%d", player->client_pid);
2552 snprintf(stream_props, sizeof(stream_props) - 1,
2553 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2554 stream_type, stream_id, player->client_pid);
2556 props = gst_structure_from_string(stream_props, NULL);
2557 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2558 LOGI("props result[%s].", stream_props);
2559 gst_structure_free(props);
2561 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2563 switch (latency_mode) {
2564 case AUDIO_LATENCY_MODE_LOW:
2565 latency = g_strdup("low");
2567 case AUDIO_LATENCY_MODE_MID:
2568 latency = g_strdup("mid");
2570 case AUDIO_LATENCY_MODE_HIGH:
2571 latency = g_strdup("high");
2574 latency = g_strdup("mid");
2578 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2580 LOGD("audiosink property - latency=%s", latency);
2582 MMPLAYER_FREEIF(latency);
2588 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2590 mmplayer_gst_element_t *audiobin = NULL;
2593 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2594 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2596 audiobin = player->pipeline->audiobin;
2598 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2599 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2600 LOGE("failed to create media stream info");
2601 return MM_ERROR_PLAYER_INTERNAL;
2604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2606 if (player->video360_yaw_radians <= M_PI &&
2607 player->video360_yaw_radians >= -M_PI &&
2608 player->video360_pitch_radians <= M_PI_2 &&
2609 player->video360_pitch_radians >= -M_PI_2) {
2610 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2611 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2612 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2613 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2614 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2615 "source-orientation-y", player->video360_metadata.init_view_heading,
2616 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2620 return MM_ERROR_NONE;
2624 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2626 mmplayer_gst_element_t *audiobin = NULL;
2627 GstPad *sink_pad = NULL;
2628 GstCaps *acaps = NULL;
2630 int pitch_control = 0;
2631 double pitch_value = 1.0;
2634 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2635 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2637 audiobin = player->pipeline->audiobin;
2639 LOGD("make element for normal audio playback");
2641 /* audio bin structure for playback. {} means optional.
2642 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2644 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2645 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2648 /* for pitch control */
2649 mm_attrs_multiple_get(player->attrs, NULL,
2650 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2651 MM_PLAYER_PITCH_VALUE, &pitch_value,
2654 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2655 if (pitch_control && (player->videodec_linked == 0)) {
2656 GstElementFactory *factory;
2658 factory = gst_element_factory_find("pitch");
2660 gst_object_unref(factory);
2663 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2666 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2667 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2669 LOGW("there is no pitch element");
2674 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2676 /* replaygain volume */
2677 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2678 if (player->sound.rg_enable)
2679 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2686 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2687 /* currently, only openalsink uses volume element */
2688 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2689 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2691 if (player->sound.mute) {
2692 LOGD("mute enabled");
2693 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2697 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2699 /* audio effect element. if audio effect is enabled */
2700 if ((strcmp(player->ini.audioeffect_element, ""))
2702 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2703 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2705 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2707 if ((!player->bypass_audio_effect)
2708 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2709 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2710 if (!_mmplayer_audio_effect_custom_apply(player))
2711 LOGI("apply audio effect(custom) setting success");
2715 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2716 && (player->set_mode.rich_audio)) {
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2721 /* create audio sink */
2722 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2723 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2724 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2726 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2727 if (player->is_360_feature_enabled &&
2728 player->is_content_spherical &&
2730 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2731 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2732 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2734 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2738 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2739 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2740 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2741 gst_caps_unref(acaps);
2743 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2745 player->is_openal_plugin_used = TRUE;
2747 if (player->is_360_feature_enabled && player->is_content_spherical)
2748 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2749 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2752 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2753 (player->videodec_linked && player->ini.use_system_clock)) {
2754 LOGD("system clock will be used.");
2755 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2758 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2759 __mmplayer_gst_set_pulsesink_property(player);
2760 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2761 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2766 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2767 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2769 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2770 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2771 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2772 gst_object_unref(GST_OBJECT(sink_pad));
2774 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2777 return MM_ERROR_NONE;
2779 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2781 return MM_ERROR_PLAYER_INTERNAL;
2785 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2787 mmplayer_gst_element_t *audiobin = NULL;
2788 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2790 gchar *dst_format = NULL;
2792 int dst_samplerate = 0;
2793 int dst_channels = 0;
2794 GstCaps *caps = NULL;
2795 char *caps_str = NULL;
2798 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2799 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2801 audiobin = player->pipeline->audiobin;
2803 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2805 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2807 [case 1] extract interleave audio pcm without playback
2808 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2809 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2811 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2813 [case 2] deinterleave for each channel without playback
2814 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2815 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2817 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2818 - fakesink (sync or not)
2821 [case 3] [case 1(sync only)] + playback
2822 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2824 * src - ... - tee - queue1 - playback path
2825 - queue2 - [case1 pipeline with sync]
2827 [case 4] [case 2(sync only)] + playback
2828 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2830 * src - ... - tee - queue1 - playback path
2831 - queue2 - [case2 pipeline with sync]
2835 /* 1. create tee and playback path
2836 'tee' should be added at first to copy the decoded stream
2838 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2839 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2840 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2842 /* tee - path 1 : for playback path */
2843 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2844 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2846 /* tee - path 2 : for extract path */
2847 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2848 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2851 /* if there is tee, 'tee - path 2' is linked here */
2853 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2856 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2858 /* 2. decide the extract pcm format */
2859 mm_attrs_multiple_get(player->attrs, NULL,
2860 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2861 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2862 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2865 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2866 dst_format, dst_len, dst_samplerate, dst_channels);
2868 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2869 mm_attrs_multiple_get(player->attrs, NULL,
2870 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2871 "content_audio_samplerate", &dst_samplerate,
2872 "content_audio_channels", &dst_channels,
2875 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2876 dst_format, dst_len, dst_samplerate, dst_channels);
2878 /* If there is no enough information, set it to platform default value. */
2879 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2880 LOGD("set platform default format");
2881 dst_format = DEFAULT_PCM_OUT_FORMAT;
2883 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2884 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2887 /* 3. create capsfilter */
2888 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2889 caps = gst_caps_new_simple("audio/x-raw",
2890 "format", G_TYPE_STRING, dst_format,
2891 "rate", G_TYPE_INT, dst_samplerate,
2892 "channels", G_TYPE_INT, dst_channels,
2895 caps_str = gst_caps_to_string(caps);
2896 LOGD("new caps : %s", caps_str);
2898 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2901 gst_caps_unref(caps);
2902 MMPLAYER_FREEIF(caps_str);
2904 /* 4-1. create deinterleave to extract pcm for each channel */
2905 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2906 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2907 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2909 /* audiosink will be added after getting signal for each channel */
2910 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2911 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2912 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2913 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2914 player->no_more_pad = FALSE;
2916 /* 4-2. create fakesink to extract interlevaed pcm */
2917 LOGD("add audio fakesink for interleaved audio");
2918 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2919 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2920 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2921 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2923 _mmplayer_add_signal_connection(player,
2924 G_OBJECT(audiobin[extract_sink_id].gst),
2925 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2927 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2930 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2934 return MM_ERROR_NONE;
2936 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2938 return MM_ERROR_PLAYER_INTERNAL;
2942 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2944 int ret = MM_ERROR_NONE;
2945 mmplayer_gst_element_t *audiobin = NULL;
2946 GList *element_bucket = NULL;
2949 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2950 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2952 audiobin = player->pipeline->audiobin;
2954 if (player->build_audio_offload) { /* skip all the audio filters */
2955 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2957 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2958 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2959 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2961 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2965 /* FIXME: need to mention the supportable condition at API reference */
2966 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2967 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2969 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2971 if (ret != MM_ERROR_NONE)
2974 LOGD("success to make audio bin element");
2975 *bucket = element_bucket;
2978 return MM_ERROR_NONE;
2981 LOGE("failed to make audio bin element");
2982 g_list_free(element_bucket);
2986 return MM_ERROR_PLAYER_INTERNAL;
2990 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2992 mmplayer_gst_element_t *first_element = NULL;
2993 mmplayer_gst_element_t *audiobin = NULL;
2995 GstPad *ghostpad = NULL;
2996 GList *element_bucket = NULL;
3000 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3003 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3005 LOGE("failed to allocate memory for audiobin");
3006 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3010 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3011 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3012 if (!audiobin[MMPLAYER_A_BIN].gst) {
3013 LOGE("failed to create audiobin");
3018 player->pipeline->audiobin = audiobin;
3020 /* create audio filters and audiosink */
3021 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3024 /* adding created elements to bin */
3025 LOGD("adding created elements to bin");
3026 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3029 /* linking elements in the bucket by added order. */
3030 LOGD("Linking elements in the bucket by added order.");
3031 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3034 /* get first element's sinkpad for creating ghostpad */
3035 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3036 if (!first_element) {
3037 LOGE("failed to get first elem");
3041 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3043 LOGE("failed to get pad from first element of audiobin");
3047 ghostpad = gst_ghost_pad_new("sink", pad);
3049 LOGE("failed to create ghostpad");
3053 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3054 LOGE("failed to add ghostpad to audiobin");
3058 gst_object_unref(pad);
3060 g_list_free(element_bucket);
3063 return MM_ERROR_NONE;
3066 LOGD("ERROR : releasing audiobin");
3069 gst_object_unref(GST_OBJECT(pad));
3072 gst_object_unref(GST_OBJECT(ghostpad));
3075 g_list_free(element_bucket);
3077 /* release element which are not added to bin */
3078 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3079 /* NOTE : skip bin */
3080 if (audiobin[i].gst) {
3081 GstObject *parent = NULL;
3082 parent = gst_element_get_parent(audiobin[i].gst);
3085 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3086 audiobin[i].gst = NULL;
3088 gst_object_unref(GST_OBJECT(parent));
3092 /* release audiobin with it's childs */
3093 if (audiobin[MMPLAYER_A_BIN].gst)
3094 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3096 MMPLAYER_FREEIF(audiobin);
3098 player->pipeline->audiobin = NULL;
3100 return MM_ERROR_PLAYER_INTERNAL;
3104 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3106 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3110 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3112 int ret = MM_ERROR_NONE;
3114 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3115 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3117 MMPLAYER_VIDEO_BO_LOCK(player);
3119 if (player->video_bo_list) {
3120 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3121 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3122 if (tmp && tmp->bo == bo) {
3124 LOGD("release bo %p", bo);
3125 tbm_bo_unref(tmp->bo);
3126 MMPLAYER_VIDEO_BO_UNLOCK(player);
3127 MMPLAYER_VIDEO_BO_SIGNAL(player);
3132 /* hw codec is running or the list was reset for DRC. */
3133 LOGW("there is no bo list.");
3135 MMPLAYER_VIDEO_BO_UNLOCK(player);
3137 LOGW("failed to find bo %p", bo);
3141 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3147 tbm_bo_unref(tmp->bo);
3152 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3155 MMPLAYER_RETURN_IF_FAIL(player);
3157 MMPLAYER_VIDEO_BO_LOCK(player);
3158 if (player->video_bo_list) {
3159 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3160 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3161 player->video_bo_list = NULL;
3163 player->video_bo_size = 0;
3164 MMPLAYER_VIDEO_BO_UNLOCK(player);
3171 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3174 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3175 gboolean ret = TRUE;
3177 /* check DRC, if it is, destroy the prev bo list to create again */
3178 if (player->video_bo_size != size) {
3179 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3180 __mmplayer_video_stream_destroy_bo_list(player);
3181 player->video_bo_size = size;
3184 MMPLAYER_VIDEO_BO_LOCK(player);
3186 if ((!player->video_bo_list) ||
3187 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3189 /* create bo list */
3191 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3193 if (player->video_bo_list) {
3194 /* if bo list did not created all, try it again. */
3195 idx = g_list_length(player->video_bo_list);
3196 LOGD("bo list exist(len: %d)", idx);
3199 for (; idx < player->ini.num_of_video_bo; idx++) {
3200 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3202 LOGE("Fail to alloc bo_info.");
3205 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3207 LOGE("Fail to tbm_bo_alloc.");
3208 MMPLAYER_FREEIF(bo_info);
3211 bo_info->used = FALSE;
3212 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3215 /* update video num buffers */
3216 LOGD("video_num_buffers : %d", idx);
3217 mm_player_set_attribute((MMHandleType)player, NULL,
3218 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3219 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3223 MMPLAYER_VIDEO_BO_UNLOCK(player);
3229 /* get bo from list*/
3230 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3231 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3232 if (tmp && (tmp->used == FALSE)) {
3233 LOGD("found bo %p to use", tmp->bo);
3235 MMPLAYER_VIDEO_BO_UNLOCK(player);
3236 return tbm_bo_ref(tmp->bo);
3240 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3241 MMPLAYER_VIDEO_BO_UNLOCK(player);
3245 if (player->ini.video_bo_timeout <= 0) {
3246 MMPLAYER_VIDEO_BO_WAIT(player);
3248 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3249 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3256 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3258 mmplayer_t *player = (mmplayer_t *)data;
3260 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3262 /* send prerolled pkt */
3263 player->video_stream_prerolled = false;
3265 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3267 /* not to send prerolled pkt again */
3268 player->video_stream_prerolled = true;
3272 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3274 mmplayer_t *player = (mmplayer_t *)data;
3275 mmplayer_video_decoded_data_info_t *stream = NULL;
3276 GstMemory *mem = NULL;
3279 MMPLAYER_RETURN_IF_FAIL(player);
3280 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3282 if (player->video_stream_prerolled) {
3283 player->video_stream_prerolled = false;
3284 LOGD("skip the prerolled pkt not to send it again");
3288 /* clear stream data structure */
3289 stream = __mmplayer_create_stream_from_pad(pad);
3291 LOGE("failed to alloc stream");
3295 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3297 /* set size and timestamp */
3298 mem = gst_buffer_peek_memory(buffer, 0);
3299 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3300 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3302 /* check zero-copy */
3303 if (player->set_mode.video_zc &&
3304 player->set_mode.video_export &&
3305 gst_is_tizen_memory(mem)) {
3306 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3307 stream->internal_buffer = gst_buffer_ref(buffer);
3308 } else { /* sw codec */
3309 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3312 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3316 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3317 LOGE("failed to send video decoded data.");
3324 LOGE("release video stream resource.");
3325 if (gst_is_tizen_memory(mem)) {
3327 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3329 tbm_bo_unref(stream->bo[i]);
3332 /* unref gst buffer */
3333 if (stream->internal_buffer)
3334 gst_buffer_unref(stream->internal_buffer);
3337 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3339 MMPLAYER_FREEIF(stream);
3344 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3346 mmplayer_gst_element_t *videobin = NULL;
3349 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3351 videobin = player->pipeline->videobin;
3353 /* Set spatial media metadata and/or user settings to the element.
3355 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3356 "projection-type", player->video360_metadata.projection_type, NULL);
3358 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3359 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3361 if (player->video360_metadata.full_pano_width_pixels &&
3362 player->video360_metadata.full_pano_height_pixels &&
3363 player->video360_metadata.cropped_area_image_width &&
3364 player->video360_metadata.cropped_area_image_height) {
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3367 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3368 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3369 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3370 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3371 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3375 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3376 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3377 "horizontal-fov", player->video360_horizontal_fov,
3378 "vertical-fov", player->video360_vertical_fov, NULL);
3381 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3382 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3383 "zoom", 1.0f / player->video360_zoom, NULL);
3386 if (player->video360_yaw_radians <= M_PI &&
3387 player->video360_yaw_radians >= -M_PI &&
3388 player->video360_pitch_radians <= M_PI_2 &&
3389 player->video360_pitch_radians >= -M_PI_2) {
3390 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3391 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3392 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3393 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3394 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3395 "pose-yaw", player->video360_metadata.init_view_heading,
3396 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3399 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3400 "passthrough", !player->is_video360_enabled, NULL);
3407 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3409 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3410 GList *element_bucket = NULL;
3413 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3415 /* create video360 filter */
3416 if (player->is_360_feature_enabled && player->is_content_spherical) {
3417 LOGD("create video360 element");
3418 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3419 __mmplayer_gst_set_video360_property(player);
3423 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3424 LOGD("skip creating the videoconv and rotator");
3425 return MM_ERROR_NONE;
3428 /* in case of sw codec & overlay surface type, except 360 playback.
3429 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3430 LOGD("create video converter: %s", video_csc);
3431 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3434 *bucket = element_bucket;
3436 return MM_ERROR_NONE;
3438 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3439 g_list_free(element_bucket);
3443 return MM_ERROR_PLAYER_INTERNAL;
3447 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3449 gchar *factory_name = NULL;
3451 switch (surface_type) {
3452 case MM_DISPLAY_SURFACE_OVERLAY:
3453 if (strlen(player->ini.videosink_element_overlay) > 0)
3454 factory_name = player->ini.videosink_element_overlay;
3456 case MM_DISPLAY_SURFACE_REMOTE:
3457 case MM_DISPLAY_SURFACE_NULL:
3458 if (strlen(player->ini.videosink_element_fake) > 0)
3459 factory_name = player->ini.videosink_element_fake;
3462 LOGE("unidentified surface type");
3466 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3467 return factory_name;
3471 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3473 gchar *factory_name = NULL;
3474 mmplayer_gst_element_t *videobin = NULL;
3479 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3481 videobin = player->pipeline->videobin;
3482 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3484 attrs = MMPLAYER_GET_ATTRS(player);
3486 LOGE("cannot get content attribute");
3487 return MM_ERROR_PLAYER_INTERNAL;
3490 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3491 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3492 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3493 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3494 "use-tbm", use_tbm, NULL);
3497 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3498 return MM_ERROR_PLAYER_INTERNAL;
3500 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3503 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3504 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3507 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3509 LOGD("disable last-sample");
3510 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3513 if (player->set_mode.video_export) {
3515 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3516 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3517 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3519 _mmplayer_add_signal_connection(player,
3520 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3521 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3523 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3526 _mmplayer_add_signal_connection(player,
3527 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3528 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3530 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3534 if (videobin[MMPLAYER_V_SINK].gst) {
3535 GstPad *sink_pad = NULL;
3536 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3538 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3539 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3540 gst_object_unref(GST_OBJECT(sink_pad));
3542 LOGE("failed to get sink pad from videosink");
3546 return MM_ERROR_NONE;
3551 * - video overlay surface(arm/x86) : tizenwlsink
3554 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3557 GList *element_bucket = NULL;
3558 mmplayer_gst_element_t *first_element = NULL;
3559 mmplayer_gst_element_t *videobin = NULL;
3560 gchar *videosink_factory_name = NULL;
3563 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3566 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3568 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3570 player->pipeline->videobin = videobin;
3573 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3574 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3575 if (!videobin[MMPLAYER_V_BIN].gst) {
3576 LOGE("failed to create videobin");
3580 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3583 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3584 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3586 /* additional setting for sink plug-in */
3587 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3588 LOGE("failed to set video property");
3592 /* store it as it's sink element */
3593 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3595 /* adding created elements to bin */
3596 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3597 LOGE("failed to add elements");
3601 /* Linking elements in the bucket by added order */
3602 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3603 LOGE("failed to link elements");
3607 /* get first element's sinkpad for creating ghostpad */
3608 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3609 if (!first_element) {
3610 LOGE("failed to get first element from bucket");
3614 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3616 LOGE("failed to get pad from first element");
3620 /* create ghostpad */
3621 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3622 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3623 LOGE("failed to add ghostpad to videobin");
3626 gst_object_unref(pad);
3628 /* done. free allocated variables */
3629 g_list_free(element_bucket);
3633 return MM_ERROR_NONE;
3636 LOGE("ERROR : releasing videobin");
3637 g_list_free(element_bucket);
3640 gst_object_unref(GST_OBJECT(pad));
3642 /* release videobin with it's childs */
3643 if (videobin[MMPLAYER_V_BIN].gst)
3644 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3646 MMPLAYER_FREEIF(videobin);
3647 player->pipeline->videobin = NULL;
3649 return MM_ERROR_PLAYER_INTERNAL;
3653 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3655 GList *element_bucket = NULL;
3656 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3658 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3659 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3660 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3661 "signal-handoffs", FALSE,
3664 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3665 _mmplayer_add_signal_connection(player,
3666 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3667 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3669 G_CALLBACK(__mmplayer_update_subtitle),
3672 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3673 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3675 if (!player->play_subtitle) {
3676 LOGD("add textbin sink as sink element of whole pipeline.");
3677 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3680 /* adding created elements to bin */
3681 LOGD("adding created elements to bin");
3682 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3683 LOGE("failed to add elements");
3687 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3688 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3689 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3691 /* linking elements in the bucket by added order. */
3692 LOGD("Linking elements in the bucket by added order.");
3693 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3694 LOGE("failed to link elements");
3698 /* done. free allocated variables */
3699 g_list_free(element_bucket);
3701 if (textbin[MMPLAYER_T_QUEUE].gst) {
3703 GstPad *ghostpad = NULL;
3705 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3707 LOGE("failed to get sink pad of text queue");
3711 ghostpad = gst_ghost_pad_new("text_sink", pad);
3712 gst_object_unref(pad);
3715 LOGE("failed to create ghostpad of textbin");
3719 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3720 LOGE("failed to add ghostpad to textbin");
3721 gst_object_unref(ghostpad);
3726 return MM_ERROR_NONE;
3729 g_list_free(element_bucket);
3731 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3732 LOGE("remove textbin sink from sink list");
3733 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3736 /* release element at __mmplayer_gst_create_text_sink_bin */
3737 return MM_ERROR_PLAYER_INTERNAL;
3741 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3743 mmplayer_gst_element_t *textbin = NULL;
3744 GList *element_bucket = NULL;
3745 int surface_type = 0;
3750 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3753 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3755 LOGE("failed to allocate memory for textbin");
3756 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3760 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3761 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3762 if (!textbin[MMPLAYER_T_BIN].gst) {
3763 LOGE("failed to create textbin");
3768 player->pipeline->textbin = textbin;
3771 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3772 LOGD("surface type for subtitle : %d", surface_type);
3773 switch (surface_type) {
3774 case MM_DISPLAY_SURFACE_OVERLAY:
3775 case MM_DISPLAY_SURFACE_NULL:
3776 case MM_DISPLAY_SURFACE_REMOTE:
3777 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3778 LOGE("failed to make plain text elements");
3789 return MM_ERROR_NONE;
3793 LOGD("ERROR : releasing textbin");
3795 g_list_free(element_bucket);
3797 /* release signal */
3798 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3800 /* release element which are not added to bin */
3801 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3802 /* NOTE : skip bin */
3803 if (textbin[i].gst) {
3804 GstObject *parent = NULL;
3805 parent = gst_element_get_parent(textbin[i].gst);
3808 gst_object_unref(GST_OBJECT(textbin[i].gst));
3809 textbin[i].gst = NULL;
3811 gst_object_unref(GST_OBJECT(parent));
3816 /* release textbin with it's childs */
3817 if (textbin[MMPLAYER_T_BIN].gst)
3818 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3820 MMPLAYER_FREEIF(textbin);
3821 player->pipeline->textbin = NULL;
3824 return MM_ERROR_PLAYER_INTERNAL;
3828 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3830 mmplayer_gst_element_t *mainbin = NULL;
3831 mmplayer_gst_element_t *textbin = NULL;
3832 MMHandleType attrs = 0;
3833 GstElement *subsrc = NULL;
3834 GstElement *subparse = NULL;
3835 gchar *subtitle_uri = NULL;
3836 const gchar *charset = NULL;
3842 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3844 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3846 mainbin = player->pipeline->mainbin;
3848 attrs = MMPLAYER_GET_ATTRS(player);
3850 LOGE("cannot get content attribute");
3851 return MM_ERROR_PLAYER_INTERNAL;
3854 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3855 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3856 LOGE("subtitle uri is not proper filepath.");
3857 return MM_ERROR_PLAYER_INVALID_URI;
3860 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3861 LOGE("failed to get storage info of subtitle path");
3862 return MM_ERROR_PLAYER_INVALID_URI;
3865 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3867 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3868 player->subtitle_language_list = NULL;
3869 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3871 /* create the subtitle source */
3872 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3874 LOGE("failed to create filesrc element");
3877 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3879 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3880 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3882 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3883 LOGW("failed to add queue");
3884 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3885 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3886 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3891 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3893 LOGE("failed to create subparse element");
3897 charset = _mmplayer_get_charset(subtitle_uri);
3899 LOGD("detected charset is %s", charset);
3900 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3903 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3904 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3906 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3907 LOGW("failed to add subparse");
3908 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3909 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3910 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3914 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3915 LOGW("failed to link subsrc and subparse");
3919 player->play_subtitle = TRUE;
3920 player->adjust_subtitle_pos = 0;
3922 LOGD("play subtitle using subtitle file");
3924 if (player->pipeline->textbin == NULL) {
3925 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3926 LOGE("failed to create text sink bin. continuing without text");
3930 textbin = player->pipeline->textbin;
3932 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3933 LOGW("failed to add textbin");
3935 /* release signal */
3936 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3938 /* release textbin with it's childs */
3939 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3940 MMPLAYER_FREEIF(player->pipeline->textbin);
3941 player->pipeline->textbin = textbin = NULL;
3945 LOGD("link text input selector and textbin ghost pad");
3947 player->textsink_linked = 1;
3948 player->external_text_idx = 0;
3949 LOGI("textsink is linked");
3951 textbin = player->pipeline->textbin;
3952 LOGD("text bin has been created. reuse it.");
3953 player->external_text_idx = 1;
3956 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3957 LOGW("failed to link subparse and textbin");
3961 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3963 LOGE("failed to get sink pad from textsink to probe data");
3967 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3968 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3970 gst_object_unref(pad);
3973 /* create dot. for debugging */
3974 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3977 return MM_ERROR_NONE;
3980 /* release text pipeline resource */
3981 player->textsink_linked = 0;
3983 /* release signal */
3984 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3986 if (player->pipeline->textbin) {
3987 LOGE("remove textbin");
3989 /* release textbin with it's childs */
3990 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3991 MMPLAYER_FREEIF(player->pipeline->textbin);
3992 player->pipeline->textbin = NULL;
3996 /* release subtitle elem */
3997 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3998 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4000 return MM_ERROR_PLAYER_INTERNAL;
4004 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4006 mmplayer_t *player = (mmplayer_t *)data;
4007 MMMessageParamType msg = {0, };
4008 GstClockTime duration = 0;
4009 gpointer text = NULL;
4010 guint text_size = 0;
4011 gboolean ret = TRUE;
4012 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4016 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4017 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4019 if (player->is_subtitle_force_drop) {
4020 LOGW("subtitle is dropped forcedly.");
4024 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4025 text = mapinfo.data;
4026 text_size = mapinfo.size;
4028 if (player->set_mode.subtitle_off) {
4029 LOGD("subtitle is OFF.");
4033 if (!text || (text_size == 0)) {
4034 LOGD("There is no subtitle to be displayed.");
4038 msg.data = (void *)text;
4040 duration = GST_BUFFER_DURATION(buffer);
4042 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4043 if (player->duration > GST_BUFFER_PTS(buffer))
4044 duration = player->duration - GST_BUFFER_PTS(buffer);
4047 LOGI("subtitle duration is invalid, subtitle duration change "
4048 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4050 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4052 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4054 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4055 gst_buffer_unmap(buffer, &mapinfo);
4062 static GstPadProbeReturn
4063 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4065 mmplayer_t *player = (mmplayer_t *)u_data;
4066 GstClockTime cur_timestamp = 0;
4067 gint64 adjusted_timestamp = 0;
4068 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4070 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4072 if (player->set_mode.subtitle_off) {
4073 LOGD("subtitle is OFF.");
4077 if (player->adjust_subtitle_pos == 0) {
4078 LOGD("nothing to do");
4082 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4083 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4085 if (adjusted_timestamp < 0) {
4086 LOGD("adjusted_timestamp under zero");
4091 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4092 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4093 GST_TIME_ARGS(cur_timestamp),
4094 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4096 return GST_PAD_PROBE_OK;
4100 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4104 /* check player and subtitlebin are created */
4105 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4106 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4108 if (position == 0) {
4109 LOGD("nothing to do");
4111 return MM_ERROR_NONE;
4114 /* check current postion */
4115 player->adjust_subtitle_pos = position;
4117 LOGD("save adjust_subtitle_pos in player");
4121 return MM_ERROR_NONE;
4125 * This function is to create audio or video pipeline for playing.
4127 * @param player [in] handle of player
4129 * @return This function returns zero on success.
4134 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4136 int ret = MM_ERROR_NONE;
4137 mmplayer_gst_element_t *mainbin = NULL;
4138 MMHandleType attrs = 0;
4141 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4143 /* get profile attribute */
4144 attrs = MMPLAYER_GET_ATTRS(player);
4146 LOGE("failed to get content attribute");
4150 /* create pipeline handles */
4151 if (player->pipeline) {
4152 LOGE("pipeline should be released before create new one");
4156 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4158 /* create mainbin */
4159 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4160 if (mainbin == NULL)
4163 /* create pipeline */
4164 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4165 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4166 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4167 LOGE("failed to create pipeline");
4172 player->pipeline->mainbin = mainbin;
4174 /* create the source and decoder elements */
4175 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4176 ret = _mmplayer_gst_build_es_pipeline(player);
4178 if (MMPLAYER_USE_DECODEBIN(player))
4179 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4181 ret = _mmplayer_gst_build_pipeline_with_src(player);
4184 if (ret != MM_ERROR_NONE) {
4185 LOGE("failed to create some elements");
4189 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4190 if (__mmplayer_check_subtitle(player)
4191 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4192 LOGE("failed to create text pipeline");
4195 ret = _mmplayer_gst_add_bus_watch(player);
4196 if (ret != MM_ERROR_NONE) {
4197 LOGE("failed to add bus watch");
4202 return MM_ERROR_NONE;
4205 _mmplayer_bus_watcher_remove(player);
4206 __mmplayer_gst_destroy_pipeline(player);
4207 return MM_ERROR_PLAYER_INTERNAL;
4211 __mmplayer_reset_gapless_state(mmplayer_t *player)
4214 MMPLAYER_RETURN_IF_FAIL(player
4216 && player->pipeline->audiobin
4217 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4219 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4226 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4229 int ret = MM_ERROR_NONE;
4233 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4235 /* cleanup stuffs */
4236 MMPLAYER_FREEIF(player->type);
4237 player->no_more_pad = FALSE;
4238 player->num_dynamic_pad = 0;
4240 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4241 player->subtitle_language_list = NULL;
4242 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4244 MMPLAYER_RECONFIGURE_LOCK(player);
4245 __mmplayer_reset_gapless_state(player);
4246 MMPLAYER_RECONFIGURE_UNLOCK(player);
4248 if (player->streamer) {
4249 _mm_player_streaming_initialize(player->streamer, FALSE);
4250 _mm_player_streaming_destroy(player->streamer);
4251 player->streamer = NULL;
4254 /* cleanup unlinked mime type */
4255 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4256 MMPLAYER_FREEIF(player->unlinked_video_mime);
4257 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4259 /* cleanup running stuffs */
4260 _mmplayer_cancel_eos_timer(player);
4262 /* cleanup gst stuffs */
4263 if (player->pipeline) {
4264 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4265 GstTagList *tag_list = player->pipeline->tag_list;
4267 /* first we need to disconnect all signal hander */
4268 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4271 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4272 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4273 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4274 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4275 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4276 gst_object_unref(bus);
4278 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4279 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4280 if (ret != MM_ERROR_NONE) {
4281 LOGE("fail to change state to NULL");
4282 return MM_ERROR_PLAYER_INTERNAL;
4285 LOGW("succeeded in changing state to NULL");
4287 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4290 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4291 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4293 /* free avsysaudiosink
4294 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4295 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4297 MMPLAYER_FREEIF(audiobin);
4298 MMPLAYER_FREEIF(videobin);
4299 MMPLAYER_FREEIF(textbin);
4300 MMPLAYER_FREEIF(mainbin);
4304 gst_tag_list_unref(tag_list);
4306 MMPLAYER_FREEIF(player->pipeline);
4308 MMPLAYER_FREEIF(player->album_art);
4310 if (player->v_stream_caps) {
4311 gst_caps_unref(player->v_stream_caps);
4312 player->v_stream_caps = NULL;
4315 if (player->a_stream_caps) {
4316 gst_caps_unref(player->a_stream_caps);
4317 player->a_stream_caps = NULL;
4320 if (player->s_stream_caps) {
4321 gst_caps_unref(player->s_stream_caps);
4322 player->s_stream_caps = NULL;
4324 _mmplayer_track_destroy(player);
4326 if (player->sink_elements)
4327 g_list_free(player->sink_elements);
4328 player->sink_elements = NULL;
4330 if (player->bufmgr) {
4331 tbm_bufmgr_deinit(player->bufmgr);
4332 player->bufmgr = NULL;
4335 LOGW("finished destroy pipeline");
4343 __mmplayer_gst_realize(mmplayer_t *player)
4346 int ret = MM_ERROR_NONE;
4350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4352 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4354 ret = __mmplayer_gst_create_pipeline(player);
4356 LOGE("failed to create pipeline");
4360 /* set pipeline state to READY */
4361 /* NOTE : state change to READY must be performed sync. */
4362 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4363 ret = _mmplayer_gst_set_state(player,
4364 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4366 if (ret != MM_ERROR_NONE) {
4367 /* return error if failed to set state */
4368 LOGE("failed to set READY state");
4372 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4374 /* create dot before error-return. for debugging */
4375 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4383 __mmplayer_gst_unrealize(mmplayer_t *player)
4385 int ret = MM_ERROR_NONE;
4389 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4391 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4392 MMPLAYER_PRINT_STATE(player);
4394 /* release miscellaneous information */
4395 __mmplayer_release_misc(player);
4397 /* destroy pipeline */
4398 ret = __mmplayer_gst_destroy_pipeline(player);
4399 if (ret != MM_ERROR_NONE) {
4400 LOGE("failed to destory pipeline");
4404 /* release miscellaneous information.
4405 these info needs to be released after pipeline is destroyed. */
4406 __mmplayer_release_misc_post(player);
4408 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4416 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4421 LOGW("set_message_callback is called with invalid player handle");
4422 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4425 player->msg_cb = callback;
4426 player->msg_cb_param = user_param;
4428 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4432 return MM_ERROR_NONE;
4436 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4438 int ret = MM_ERROR_NONE;
4443 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4444 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4445 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4447 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4449 if (strstr(uri, "es_buff://")) {
4450 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4451 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4452 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4453 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4455 tmp = g_ascii_strdown(uri, strlen(uri));
4456 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4457 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4459 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4461 } else if (strstr(uri, "mms://")) {
4462 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4463 } else if ((path = strstr(uri, "mem://"))) {
4464 ret = __mmplayer_set_mem_uri(data, path, param);
4466 ret = __mmplayer_set_file_uri(data, uri);
4469 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4470 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4471 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4472 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4474 /* dump parse result */
4475 SECURE_LOGW("incoming uri : %s", uri);
4476 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4477 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4485 __mmplayer_can_do_interrupt(mmplayer_t *player)
4487 if (!player || !player->pipeline || !player->attrs) {
4488 LOGW("not initialized");
4492 if (player->audio_decoded_cb) {
4493 LOGW("not support in pcm extraction mode");
4497 /* check if seeking */
4498 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4499 MMMessageParamType msg_param;
4500 memset(&msg_param, 0, sizeof(MMMessageParamType));
4501 msg_param.code = MM_ERROR_PLAYER_SEEK;
4502 player->seek_state = MMPLAYER_SEEK_NONE;
4503 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4507 /* check other thread */
4508 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4509 LOGW("locked already, cmd state : %d", player->cmd);
4511 /* check application command */
4512 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4513 LOGW("playing.. should wait cmd lock then, will be interrupted");
4515 /* lock will be released at mrp_resource_release_cb() */
4516 MMPLAYER_CMD_LOCK(player);
4519 LOGW("nothing to do");
4522 LOGW("can interrupt immediately");
4526 FAILED: /* with CMD UNLOCKED */
4529 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4534 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4537 mmplayer_t *player = NULL;
4538 MMMessageParamType msg = {0, };
4540 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4545 LOGE("user_data is null");
4548 player = (mmplayer_t *)user_data;
4550 if (!__mmplayer_can_do_interrupt(player)) {
4551 LOGW("no need to interrupt, so leave");
4552 /* FIXME: there is no way to avoid releasing resource. */
4556 player->interrupted_by_resource = TRUE;
4558 /* get last play position */
4559 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4560 msg.union_type = MM_MSG_UNION_TIME;
4561 msg.time.elapsed = pos;
4562 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4564 LOGW("failed to get play position.");
4567 LOGD("video resource conflict so, resource will be freed by unrealizing");
4568 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4569 LOGE("failed to unrealize");
4571 /* lock is called in __mmplayer_can_do_interrupt() */
4572 MMPLAYER_CMD_UNLOCK(player);
4574 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4575 player->hw_resource[res_idx] = NULL;
4579 return TRUE; /* release all the resources */
4583 __mmplayer_initialize_video_roi(mmplayer_t *player)
4585 player->video_roi.scale_x = 0.0;
4586 player->video_roi.scale_y = 0.0;
4587 player->video_roi.scale_width = 1.0;
4588 player->video_roi.scale_height = 1.0;
4592 _mmplayer_create_player(MMHandleType handle)
4594 int ret = MM_ERROR_PLAYER_INTERNAL;
4595 bool enabled = false;
4597 mmplayer_t *player = MM_PLAYER_CAST(handle);
4601 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4603 /* initialize player state */
4604 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4605 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4606 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4607 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4609 /* check current state */
4610 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4612 /* construct attributes */
4613 player->attrs = _mmplayer_construct_attribute(handle);
4615 if (!player->attrs) {
4616 LOGE("Failed to construct attributes");
4620 /* initialize gstreamer with configured parameter */
4621 if (!__mmplayer_init_gstreamer(player)) {
4622 LOGE("Initializing gstreamer failed");
4623 _mmplayer_deconstruct_attribute(handle);
4627 /* create lock. note that g_tread_init() has already called in gst_init() */
4628 g_mutex_init(&player->fsink_lock);
4630 /* create update tag lock */
4631 g_mutex_init(&player->update_tag_lock);
4633 /* create gapless play mutex */
4634 g_mutex_init(&player->gapless_play_thread_mutex);
4636 /* create gapless play cond */
4637 g_cond_init(&player->gapless_play_thread_cond);
4639 /* create gapless play thread */
4640 player->gapless_play_thread =
4641 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4642 if (!player->gapless_play_thread) {
4643 LOGE("failed to create gapless play thread");
4644 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4645 g_mutex_clear(&player->gapless_play_thread_mutex);
4646 g_cond_clear(&player->gapless_play_thread_cond);
4650 player->bus_msg_q = g_queue_new();
4651 if (!player->bus_msg_q) {
4652 LOGE("failed to create queue for bus_msg");
4653 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4657 ret = _mmplayer_initialize_video_capture(player);
4658 if (ret != MM_ERROR_NONE) {
4659 LOGE("failed to initialize video capture");
4663 /* initialize resource manager */
4664 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4665 __resource_release_cb, player, &player->resource_manager)
4666 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4667 LOGE("failed to initialize resource manager");
4668 ret = MM_ERROR_PLAYER_INTERNAL;
4672 /* create video bo lock and cond */
4673 g_mutex_init(&player->video_bo_mutex);
4674 g_cond_init(&player->video_bo_cond);
4676 /* create subtitle info lock and cond */
4677 g_mutex_init(&player->subtitle_info_mutex);
4678 g_cond_init(&player->subtitle_info_cond);
4680 player->streaming_type = STREAMING_SERVICE_NONE;
4682 /* give default value of audio effect setting */
4683 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4684 player->sound.rg_enable = false;
4685 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4687 player->play_subtitle = FALSE;
4688 player->has_closed_caption = FALSE;
4689 player->pending_resume = FALSE;
4690 if (player->ini.dump_element_keyword[0][0] == '\0')
4691 player->ini.set_dump_element_flag = FALSE;
4693 player->ini.set_dump_element_flag = TRUE;
4695 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4696 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4697 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4699 /* Set video360 settings to their defaults for just-created player.
4702 player->is_360_feature_enabled = FALSE;
4703 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4704 LOGI("spherical feature info: %d", enabled);
4706 player->is_360_feature_enabled = TRUE;
4708 LOGE("failed to get spherical feature info");
4711 player->is_content_spherical = FALSE;
4712 player->is_video360_enabled = TRUE;
4713 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4714 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4715 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4716 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4717 player->video360_zoom = 1.0f;
4718 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4719 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4721 __mmplayer_initialize_video_roi(player);
4723 /* set player state to null */
4724 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4725 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4729 return MM_ERROR_NONE;
4733 g_mutex_clear(&player->fsink_lock);
4734 /* free update tag lock */
4735 g_mutex_clear(&player->update_tag_lock);
4736 g_queue_free(player->bus_msg_q);
4737 player->bus_msg_q = NULL;
4738 /* free gapless play thread */
4739 if (player->gapless_play_thread) {
4740 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4741 player->gapless_play_thread_exit = TRUE;
4742 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4743 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4745 g_thread_join(player->gapless_play_thread);
4746 player->gapless_play_thread = NULL;
4748 g_mutex_clear(&player->gapless_play_thread_mutex);
4749 g_cond_clear(&player->gapless_play_thread_cond);
4752 /* release attributes */
4753 _mmplayer_deconstruct_attribute(handle);
4761 __mmplayer_init_gstreamer(mmplayer_t *player)
4763 static gboolean initialized = FALSE;
4764 static const int max_argc = 50;
4766 gchar **argv = NULL;
4767 gchar **argv2 = NULL;
4773 LOGD("gstreamer already initialized.");
4778 argc = malloc(sizeof(int));
4779 argv = malloc(sizeof(gchar *) * max_argc);
4780 argv2 = malloc(sizeof(gchar *) * max_argc);
4782 if (!argc || !argv || !argv2)
4785 memset(argv, 0, sizeof(gchar *) * max_argc);
4786 memset(argv2, 0, sizeof(gchar *) * max_argc);
4790 argv[0] = g_strdup("mmplayer");
4793 for (i = 0; i < 5; i++) {
4794 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4795 if (strlen(player->ini.gst_param[i]) > 0) {
4796 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4801 /* we would not do fork for scanning plugins */
4802 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4805 /* check disable registry scan */
4806 if (player->ini.skip_rescan) {
4807 argv[*argc] = g_strdup("--gst-disable-registry-update");
4811 /* check disable segtrap */
4812 if (player->ini.disable_segtrap) {
4813 argv[*argc] = g_strdup("--gst-disable-segtrap");
4817 LOGD("initializing gstreamer with following parameter");
4818 LOGD("argc : %d", *argc);
4821 for (i = 0; i < arg_count; i++) {
4823 LOGD("argv[%d] : %s", i, argv2[i]);
4826 /* initializing gstreamer */
4827 if (!gst_init_check(argc, &argv, &err)) {
4828 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4835 for (i = 0; i < arg_count; i++) {
4837 LOGD("release - argv[%d] : %s", i, argv2[i]);
4839 MMPLAYER_FREEIF(argv2[i]);
4842 MMPLAYER_FREEIF(argv);
4843 MMPLAYER_FREEIF(argv2);
4844 MMPLAYER_FREEIF(argc);
4854 for (i = 0; i < arg_count; i++) {
4855 LOGD("free[%d] : %s", i, argv2[i]);
4856 MMPLAYER_FREEIF(argv2[i]);
4859 MMPLAYER_FREEIF(argv);
4860 MMPLAYER_FREEIF(argv2);
4861 MMPLAYER_FREEIF(argc);
4867 __mmplayer_check_async_state_transition(mmplayer_t *player)
4869 GstState element_state = GST_STATE_VOID_PENDING;
4870 GstState element_pending_state = GST_STATE_VOID_PENDING;
4871 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4872 GstElement *element = NULL;
4873 gboolean async = FALSE;
4875 /* check player handle */
4876 MMPLAYER_RETURN_IF_FAIL(player &&
4878 player->pipeline->mainbin &&
4879 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4882 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4884 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4885 LOGD("don't need to check the pipeline state");
4889 MMPLAYER_PRINT_STATE(player);
4891 /* wait for state transition */
4892 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4893 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4895 if (ret == GST_STATE_CHANGE_FAILURE) {
4896 LOGE(" [%s] state : %s pending : %s",
4897 GST_ELEMENT_NAME(element),
4898 gst_element_state_get_name(element_state),
4899 gst_element_state_get_name(element_pending_state));
4901 /* dump state of all element */
4902 _mmplayer_dump_pipeline_state(player);
4907 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4912 _mmplayer_destroy(MMHandleType handle)
4914 mmplayer_t *player = MM_PLAYER_CAST(handle);
4918 /* check player handle */
4919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4921 /* destroy can called at anytime */
4922 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4924 /* check async state transition */
4925 __mmplayer_check_async_state_transition(player);
4927 /* release gapless play thread */
4928 if (player->gapless_play_thread) {
4929 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4930 player->gapless_play_thread_exit = TRUE;
4931 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4932 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4934 LOGD("waitting for gapless play thread exit");
4935 g_thread_join(player->gapless_play_thread);
4936 g_mutex_clear(&player->gapless_play_thread_mutex);
4937 g_cond_clear(&player->gapless_play_thread_cond);
4938 LOGD("gapless play thread released");
4941 _mmplayer_release_video_capture(player);
4943 /* de-initialize resource manager */
4944 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4945 player->resource_manager))
4946 LOGE("failed to deinitialize resource manager");
4948 /* release miscellaneous information */
4949 __mmplayer_release_misc(player);
4951 /* release pipeline */
4952 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4953 LOGE("failed to destory pipeline");
4954 return MM_ERROR_PLAYER_INTERNAL;
4957 g_queue_free(player->bus_msg_q);
4959 /* release subtitle info lock and cond */
4960 g_mutex_clear(&player->subtitle_info_mutex);
4961 g_cond_clear(&player->subtitle_info_cond);
4963 __mmplayer_release_dump_list(player->dump_list);
4965 /* release miscellaneous information.
4966 these info needs to be released after pipeline is destroyed. */
4967 __mmplayer_release_misc_post(player);
4969 /* release attributes */
4970 _mmplayer_deconstruct_attribute(handle);
4972 if (player->uri_info.uri_list) {
4973 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
4974 player->uri_info.uri_list = NULL;
4978 g_mutex_clear(&player->fsink_lock);
4981 g_mutex_clear(&player->update_tag_lock);
4983 /* release video bo lock and cond */
4984 g_mutex_clear(&player->video_bo_mutex);
4985 g_cond_clear(&player->video_bo_cond);
4989 return MM_ERROR_NONE;
4993 _mmplayer_realize(MMHandleType hplayer)
4995 mmplayer_t *player = (mmplayer_t *)hplayer;
4996 int ret = MM_ERROR_NONE;
4999 MMHandleType attrs = 0;
5000 int video_codec_type = 0;
5001 int audio_codec_type = 0;
5002 int default_codec_type = 0;
5005 /* check player handle */
5006 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5008 /* check current state */
5009 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5011 attrs = MMPLAYER_GET_ATTRS(player);
5013 LOGE("fail to get attributes.");
5014 return MM_ERROR_PLAYER_INTERNAL;
5016 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5017 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5019 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5020 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5022 if (ret != MM_ERROR_NONE) {
5023 LOGE("failed to parse profile");
5028 if (uri && (strstr(uri, "es_buff://"))) {
5029 if (strstr(uri, "es_buff://push_mode"))
5030 player->es_player_push_mode = TRUE;
5032 player->es_player_push_mode = FALSE;
5035 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5036 LOGW("mms protocol is not supported format.");
5037 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5040 if (MMPLAYER_IS_STREAMING(player))
5041 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5043 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5045 player->smooth_streaming = FALSE;
5046 player->videodec_linked = 0;
5047 player->audiodec_linked = 0;
5048 player->textsink_linked = 0;
5049 player->is_external_subtitle_present = FALSE;
5050 player->is_external_subtitle_added_now = FALSE;
5051 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5052 player->video360_metadata.is_spherical = -1;
5053 player->is_openal_plugin_used = FALSE;
5054 player->subtitle_language_list = NULL;
5055 player->is_subtitle_force_drop = FALSE;
5057 _mmplayer_track_initialize(player);
5058 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5060 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5061 gint prebuffer_ms = 0, rebuffer_ms = 0;
5063 player->streamer = _mm_player_streaming_create();
5064 _mm_player_streaming_initialize(player->streamer, TRUE);
5066 mm_attrs_multiple_get(player->attrs, NULL,
5067 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5068 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5070 if (prebuffer_ms > 0) {
5071 prebuffer_ms = MAX(prebuffer_ms, 1000);
5072 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5075 if (rebuffer_ms > 0) {
5076 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5077 rebuffer_ms = MAX(rebuffer_ms, 1000);
5078 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5081 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5082 player->streamer->buffering_req.rebuffer_time);
5085 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5086 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5087 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5089 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5091 if (audio_codec_type != default_codec_type) {
5092 LOGD("audio dec sorting is required");
5093 player->need_audio_dec_sorting = TRUE;
5096 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5097 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5098 LOGD("video dec sorting is required");
5099 player->need_video_dec_sorting = TRUE;
5102 /* realize pipeline */
5103 ret = __mmplayer_gst_realize(player);
5104 if (ret != MM_ERROR_NONE)
5105 LOGE("fail to realize the player.");
5107 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5115 _mmplayer_unrealize(MMHandleType hplayer)
5117 mmplayer_t *player = (mmplayer_t *)hplayer;
5118 int ret = MM_ERROR_NONE;
5122 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5124 MMPLAYER_CMD_UNLOCK(player);
5125 _mmplayer_bus_watcher_remove(player);
5126 /* destroy the gst bus msg thread which is created during realize.
5127 this funct have to be called before getting cmd lock. */
5128 _mmplayer_bus_msg_thread_destroy(player);
5129 MMPLAYER_CMD_LOCK(player);
5131 /* check current state */
5132 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5134 /* check async state transition */
5135 __mmplayer_check_async_state_transition(player);
5137 /* unrealize pipeline */
5138 ret = __mmplayer_gst_unrealize(player);
5140 if (!player->interrupted_by_resource) {
5141 int rm_ret = MM_ERROR_NONE;
5142 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5144 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5145 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5146 if (rm_ret != MM_ERROR_NONE)
5147 LOGE("failed to release [%d] resources", res_idx);
5156 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5158 mmplayer_t *player = (mmplayer_t *)hplayer;
5160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5162 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5166 _mmplayer_get_state(MMHandleType hplayer, int *state)
5168 mmplayer_t *player = (mmplayer_t *)hplayer;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5172 *state = MMPLAYER_CURRENT_STATE(player);
5174 return MM_ERROR_NONE;
5178 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5180 GstElement *vol_element = NULL;
5181 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5185 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5187 /* check pipeline handle */
5188 if (!player->pipeline || !player->pipeline->audiobin) {
5189 LOGD("'%s' will be applied when audiobin is created", prop_name);
5191 /* NOTE : stored value will be used in create_audiobin
5192 * returning MM_ERROR_NONE here makes application to able to
5193 * set audio volume or mute at anytime.
5195 return MM_ERROR_NONE;
5198 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5199 volume_elem_id = MMPLAYER_A_SINK;
5201 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5203 LOGE("failed to get vol element %d", volume_elem_id);
5204 return MM_ERROR_PLAYER_INTERNAL;
5207 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5209 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5210 LOGE("there is no '%s' property", prop_name);
5211 return MM_ERROR_PLAYER_INTERNAL;
5214 if (!strcmp(prop_name, "volume")) {
5215 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5216 } else if (!strcmp(prop_name, "mute")) {
5217 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5219 LOGE("invalid property %s", prop_name);
5220 return MM_ERROR_PLAYER_INTERNAL;
5223 return MM_ERROR_NONE;
5227 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5229 int ret = MM_ERROR_NONE;
5230 mmplayer_t *player = (mmplayer_t *)hplayer;
5233 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235 LOGD("volume = %f", volume);
5237 /* invalid factor range or not */
5238 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5239 LOGE("Invalid volume value");
5240 return MM_ERROR_INVALID_ARGUMENT;
5243 player->sound.volume = volume;
5245 ret = __mmplayer_gst_set_volume_property(player, "volume");
5252 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5254 mmplayer_t *player = (mmplayer_t *)hplayer;
5258 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5259 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5261 *volume = player->sound.volume;
5263 LOGD("current vol = %f", *volume);
5266 return MM_ERROR_NONE;
5270 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5272 int ret = MM_ERROR_NONE;
5273 mmplayer_t *player = (mmplayer_t *)hplayer;
5276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5278 LOGD("mute = %d", mute);
5280 player->sound.mute = mute;
5282 ret = __mmplayer_gst_set_volume_property(player, "mute");
5289 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5291 mmplayer_t *player = (mmplayer_t *)hplayer;
5295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5296 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5298 *mute = player->sound.mute;
5300 LOGD("current mute = %d", *mute);
5304 return MM_ERROR_NONE;
5308 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5310 mmplayer_t *player = (mmplayer_t *)hplayer;
5314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5316 player->audio_stream_changed_cb = callback;
5317 player->audio_stream_changed_cb_user_param = user_param;
5318 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5322 return MM_ERROR_NONE;
5326 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5328 mmplayer_t *player = (mmplayer_t *)hplayer;
5332 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5334 player->audio_decoded_cb = callback;
5335 player->audio_decoded_cb_user_param = user_param;
5336 player->audio_extract_opt = opt;
5337 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5341 return MM_ERROR_NONE;
5345 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5347 mmplayer_t *player = (mmplayer_t *)hplayer;
5351 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5353 if (callback && !player->bufmgr)
5354 player->bufmgr = tbm_bufmgr_init(-1);
5356 player->set_mode.video_export = (callback) ? true : false;
5357 player->video_decoded_cb = callback;
5358 player->video_decoded_cb_user_param = user_param;
5360 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5364 return MM_ERROR_NONE;
5368 _mmplayer_start(MMHandleType hplayer)
5370 mmplayer_t *player = (mmplayer_t *)hplayer;
5371 gint ret = MM_ERROR_NONE;
5375 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5377 /* check current state */
5378 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5380 /* start pipeline */
5381 ret = _mmplayer_gst_start(player);
5382 if (ret != MM_ERROR_NONE)
5383 LOGE("failed to start player.");
5385 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5386 LOGD("force playing start even during buffering");
5387 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5395 /* NOTE: post "not supported codec message" to application
5396 * when one codec is not found during AUTOPLUGGING in MSL.
5397 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5398 * And, if any codec is not found, don't send message here.
5399 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5402 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5404 MMMessageParamType msg_param;
5405 memset(&msg_param, 0, sizeof(MMMessageParamType));
5406 gboolean post_msg_direct = FALSE;
5410 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5412 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5413 player->not_supported_codec, player->can_support_codec);
5415 if (player->not_found_demuxer) {
5416 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5417 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5419 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5420 MMPLAYER_FREEIF(msg_param.data);
5422 return MM_ERROR_NONE;
5425 if (player->not_supported_codec) {
5426 if (player->can_support_codec) {
5427 // There is one codec to play
5428 post_msg_direct = TRUE;
5430 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5431 post_msg_direct = TRUE;
5434 if (post_msg_direct) {
5435 MMMessageParamType msg_param;
5436 memset(&msg_param, 0, sizeof(MMMessageParamType));
5438 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5439 LOGW("not found AUDIO codec, posting error code to application.");
5441 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5442 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5443 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5444 LOGW("not found VIDEO codec, posting error code to application.");
5446 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5447 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5450 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5452 MMPLAYER_FREEIF(msg_param.data);
5454 return MM_ERROR_NONE;
5456 // no any supported codec case
5457 LOGW("not found any codec, posting error code to application.");
5459 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5460 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5461 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5463 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5464 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5467 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5469 MMPLAYER_FREEIF(msg_param.data);
5475 return MM_ERROR_NONE;
5478 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5480 GstState element_state = GST_STATE_VOID_PENDING;
5481 GstState element_pending_state = GST_STATE_VOID_PENDING;
5482 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5483 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5485 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5487 MMPLAYER_RECONFIGURE_LOCK(player);
5488 if (!player->gapless.reconfigure) {
5489 MMPLAYER_RECONFIGURE_UNLOCK(player);
5493 LOGI("reconfigure is under process");
5494 MMPLAYER_RECONFIGURE_WAIT(player);
5495 MMPLAYER_RECONFIGURE_UNLOCK(player);
5496 LOGI("reconfigure is completed.");
5498 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5499 &element_state, &element_pending_state, timeout * GST_SECOND);
5500 if (result == GST_STATE_CHANGE_FAILURE)
5501 LOGW("failed to get pipeline state in %d sec", timeout);
5506 /* NOTE : it should be able to call 'stop' anytime*/
5508 _mmplayer_stop(MMHandleType hplayer)
5510 mmplayer_t *player = (mmplayer_t *)hplayer;
5511 int ret = MM_ERROR_NONE;
5515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5517 /* check current state */
5518 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5520 /* need to wait till the rebuilding pipeline is completed */
5521 __mmplayer_check_pipeline_reconfigure_state(player);
5522 MMPLAYER_RECONFIGURE_LOCK(player);
5523 __mmplayer_reset_gapless_state(player);
5524 MMPLAYER_RECONFIGURE_UNLOCK(player);
5526 /* NOTE : application should not wait for EOS after calling STOP */
5527 _mmplayer_cancel_eos_timer(player);
5530 player->seek_state = MMPLAYER_SEEK_NONE;
5533 ret = _mmplayer_gst_stop(player);
5535 if (ret != MM_ERROR_NONE)
5536 LOGE("failed to stop player.");
5544 _mmplayer_pause(MMHandleType hplayer)
5546 mmplayer_t *player = (mmplayer_t *)hplayer;
5547 gint64 pos_nsec = 0;
5548 gboolean async = FALSE;
5549 gint ret = MM_ERROR_NONE;
5553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5555 /* check current state */
5556 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5558 /* check pipline reconfigure state */
5559 __mmplayer_check_pipeline_reconfigure_state(player);
5561 switch (MMPLAYER_CURRENT_STATE(player)) {
5562 case MM_PLAYER_STATE_READY:
5564 /* check prepare async or not.
5565 * In the case of streaming playback, it's recommned to avoid blocking wait.
5567 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5568 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5570 /* Changing back sync of rtspsrc to async */
5571 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5572 LOGD("async prepare working mode for rtsp");
5578 case MM_PLAYER_STATE_PLAYING:
5580 /* NOTE : store current point to overcome some bad operation
5581 *(returning zero when getting current position in paused state) of some
5584 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5585 LOGW("getting current position failed in paused");
5587 player->last_position = pos_nsec;
5589 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5590 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5591 This causes problem is position calculation during normal pause resume scenarios also.
5592 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5593 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5594 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5595 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5601 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5602 LOGD("doing async pause in case of ms buff src");
5606 /* pause pipeline */
5607 ret = _mmplayer_gst_pause(player, async);
5609 if (ret != MM_ERROR_NONE)
5610 LOGE("failed to pause player. ret : 0x%x", ret);
5612 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5613 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5614 LOGE("failed to update display_rotation");
5622 /* in case of streaming, pause could take long time.*/
5624 _mmplayer_abort_pause(MMHandleType hplayer)
5626 mmplayer_t *player = (mmplayer_t *)hplayer;
5627 int ret = MM_ERROR_NONE;
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5633 player->pipeline->mainbin,
5634 MM_ERROR_PLAYER_NOT_INITIALIZED);
5636 LOGD("set the pipeline state to READY");
5638 /* set state to READY */
5639 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5640 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5641 if (ret != MM_ERROR_NONE) {
5642 LOGE("fail to change state to READY");
5643 return MM_ERROR_PLAYER_INTERNAL;
5646 LOGD("succeeded in changing state to READY");
5651 _mmplayer_resume(MMHandleType hplayer)
5653 mmplayer_t *player = (mmplayer_t *)hplayer;
5654 int ret = MM_ERROR_NONE;
5655 gboolean async = FALSE;
5659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5661 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5662 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5663 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5667 /* Changing back sync mode rtspsrc to async */
5668 LOGD("async resume for rtsp case");
5672 /* check current state */
5673 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5675 ret = _mmplayer_gst_resume(player, async);
5676 if (ret != MM_ERROR_NONE)
5677 LOGE("failed to resume player.");
5679 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5680 LOGD("force resume even during buffering");
5681 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5690 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5692 mmplayer_t *player = (mmplayer_t *)hplayer;
5693 gint64 pos_nsec = 0;
5694 int ret = MM_ERROR_NONE;
5696 signed long long start = 0, stop = 0;
5697 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5700 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5701 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5703 /* The sound of video is not supported under 0.0 and over 2.0. */
5704 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5705 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5708 _mmplayer_set_mute(hplayer, mute);
5710 if (player->playback_rate == rate)
5711 return MM_ERROR_NONE;
5713 /* If the position is reached at start potion during fast backward, EOS is posted.
5714 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5716 player->playback_rate = rate;
5718 current_state = MMPLAYER_CURRENT_STATE(player);
5720 if (current_state != MM_PLAYER_STATE_PAUSED)
5721 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5723 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5725 if ((current_state == MM_PLAYER_STATE_PAUSED)
5726 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5727 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5728 pos_nsec = player->last_position;
5733 stop = GST_CLOCK_TIME_NONE;
5735 start = GST_CLOCK_TIME_NONE;
5739 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5740 player->playback_rate,
5742 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5743 GST_SEEK_TYPE_SET, start,
5744 GST_SEEK_TYPE_SET, stop)) {
5745 LOGE("failed to set speed playback");
5746 return MM_ERROR_PLAYER_SEEK;
5749 LOGD("succeeded to set speed playback as %0.1f", rate);
5753 return MM_ERROR_NONE;;
5757 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5759 mmplayer_t *player = (mmplayer_t *)hplayer;
5760 int ret = MM_ERROR_NONE;
5764 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5766 /* check pipline reconfigure state */
5767 __mmplayer_check_pipeline_reconfigure_state(player);
5769 ret = _mmplayer_gst_set_position(player, position, FALSE);
5777 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5779 mmplayer_t *player = (mmplayer_t *)hplayer;
5780 int ret = MM_ERROR_NONE;
5782 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5783 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5785 if (g_strrstr(player->type, "video/mpegts"))
5786 __mmplayer_update_duration_value(player);
5788 *duration = player->duration;
5793 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5795 mmplayer_t *player = (mmplayer_t *)hplayer;
5796 int ret = MM_ERROR_NONE;
5798 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5800 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5806 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5808 mmplayer_t *player = (mmplayer_t *)hplayer;
5809 int ret = MM_ERROR_NONE;
5813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5815 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5823 __mmplayer_is_midi_type(gchar *str_caps)
5825 if ((g_strrstr(str_caps, "audio/midi")) ||
5826 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5827 (g_strrstr(str_caps, "application/x-smaf")) ||
5828 (g_strrstr(str_caps, "audio/x-imelody")) ||
5829 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5830 (g_strrstr(str_caps, "audio/xmf")) ||
5831 (g_strrstr(str_caps, "audio/mxmf"))) {
5840 __mmplayer_is_only_mp3_type(gchar *str_caps)
5842 if (g_strrstr(str_caps, "application/x-id3") ||
5843 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5849 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5851 GstStructure *caps_structure = NULL;
5852 gint samplerate = 0;
5856 MMPLAYER_RETURN_IF_FAIL(player && caps);
5858 caps_structure = gst_caps_get_structure(caps, 0);
5860 /* set stream information */
5861 gst_structure_get_int(caps_structure, "rate", &samplerate);
5862 gst_structure_get_int(caps_structure, "channels", &channels);
5864 mm_player_set_attribute((MMHandleType)player, NULL,
5865 "content_audio_samplerate", samplerate,
5866 "content_audio_channels", channels, NULL);
5868 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5872 __mmplayer_update_content_type_info(mmplayer_t *player)
5875 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5877 if (__mmplayer_is_midi_type(player->type)) {
5878 player->bypass_audio_effect = TRUE;
5882 if (!player->streamer) {
5883 LOGD("no need to check streaming type");
5887 if (g_strrstr(player->type, "application/x-hls")) {
5888 /* If it can't know exact type when it parses uri because of redirection case,
5889 * it will be fixed by typefinder or when doing autoplugging.
5891 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5892 player->streamer->is_adaptive_streaming = TRUE;
5893 } else if (g_strrstr(player->type, "application/dash+xml")) {
5894 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5895 player->streamer->is_adaptive_streaming = TRUE;
5898 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5899 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5900 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5902 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5903 if (player->streamer->is_adaptive_streaming)
5904 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5906 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5910 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5915 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5916 GstCaps *caps, gpointer data)
5918 mmplayer_t *player = (mmplayer_t *)data;
5922 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5924 /* store type string */
5925 MMPLAYER_FREEIF(player->type);
5926 player->type = gst_caps_to_string(caps);
5928 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5929 player, player->type, probability, gst_caps_get_size(caps));
5931 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5932 (g_strrstr(player->type, "audio/x-raw-int"))) {
5933 LOGE("not support media format");
5935 if (player->msg_posted == FALSE) {
5936 MMMessageParamType msg_param;
5937 memset(&msg_param, 0, sizeof(MMMessageParamType));
5939 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5940 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5942 /* don't post more if one was sent already */
5943 player->msg_posted = TRUE;
5948 __mmplayer_update_content_type_info(player);
5950 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5953 pad = gst_element_get_static_pad(tf, "src");
5955 LOGE("fail to get typefind src pad.");
5959 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5960 gboolean async = FALSE;
5961 LOGE("failed to autoplug %s", player->type);
5963 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5965 if (async && player->msg_posted == FALSE)
5966 __mmplayer_handle_missed_plugin(player);
5968 gst_object_unref(GST_OBJECT(pad));
5975 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5977 GstElement *decodebin = NULL;
5981 /* create decodebin */
5982 decodebin = gst_element_factory_make("decodebin", NULL);
5985 LOGE("fail to create decodebin");
5989 /* raw pad handling signal */
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5991 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5993 /* no-more-pad pad handling signal */
5994 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5995 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5997 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5998 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6000 /* This signal is emitted when a pad for which there is no further possible
6001 decoding is added to the decodebin.*/
6002 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6003 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6005 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6006 before looking for any elements that can handle that stream.*/
6007 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6008 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6010 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6011 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6012 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6014 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6015 before looking for any elements that can handle that stream.*/
6016 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6017 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6019 /* This signal is emitted once decodebin has finished decoding all the data.*/
6020 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6021 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6023 /* This signal is emitted when a element is added to the bin.*/
6024 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6025 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6032 __mmplayer_gst_make_queue2(mmplayer_t *player)
6034 GstElement *queue2 = NULL;
6035 gint64 dur_bytes = 0L;
6036 mmplayer_gst_element_t *mainbin = NULL;
6037 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6040 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6042 mainbin = player->pipeline->mainbin;
6044 queue2 = gst_element_factory_make("queue2", "queue2");
6046 LOGE("failed to create buffering queue element");
6050 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6051 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6053 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6055 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6056 * skip the pull mode(file or ring buffering) setting. */
6057 if (dur_bytes > 0) {
6058 if (!g_strrstr(player->type, "video/mpegts")) {
6059 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6060 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6066 _mm_player_streaming_set_queue2(player->streamer,
6070 (guint64)dur_bytes); /* no meaning at the moment */
6076 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6078 mmplayer_gst_element_t *mainbin = NULL;
6079 GstElement *decodebin = NULL;
6080 GstElement *queue2 = NULL;
6081 GstPad *sinkpad = NULL;
6082 GstPad *qsrcpad = NULL;
6085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6087 mainbin = player->pipeline->mainbin;
6089 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6091 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6092 LOGW("need to check: muxed buffer is not null");
6095 queue2 = __mmplayer_gst_make_queue2(player);
6097 LOGE("failed to make queue2");
6101 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6102 LOGE("failed to add buffering queue");
6106 sinkpad = gst_element_get_static_pad(queue2, "sink");
6107 qsrcpad = gst_element_get_static_pad(queue2, "src");
6109 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6110 LOGE("failed to link [%s:%s]-[%s:%s]",
6111 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6115 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6116 LOGE("failed to sync queue2 state with parent");
6120 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6121 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6125 gst_object_unref(GST_OBJECT(sinkpad));
6129 /* create decodebin */
6130 decodebin = _mmplayer_gst_make_decodebin(player);
6132 LOGE("failed to make decodebin");
6136 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6137 LOGE("failed to add decodebin");
6141 /* to force caps on the decodebin element and avoid reparsing stuff by
6142 * typefind. It also avoids a deadlock in the way typefind activates pads in
6143 * the state change */
6144 g_object_set(decodebin, "sink-caps", caps, NULL);
6146 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6148 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6149 LOGE("failed to link [%s:%s]-[%s:%s]",
6150 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6154 gst_object_unref(GST_OBJECT(sinkpad));
6156 gst_object_unref(GST_OBJECT(qsrcpad));
6159 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6160 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6162 /* set decodebin property about buffer in streaming playback. *
6163 * in case of HLS/DASH, it does not need to have big buffer *
6164 * because it is kind of adaptive streaming. */
6165 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6166 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6167 gint high_percent = 0;
6169 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6170 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6172 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6174 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6176 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6177 "high-percent", high_percent,
6178 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6179 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6180 "max-size-buffers", 0, NULL); // disable or automatic
6183 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6184 LOGE("failed to sync decodebin state with parent");
6195 gst_object_unref(GST_OBJECT(sinkpad));
6198 gst_object_unref(GST_OBJECT(qsrcpad));
6201 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6202 * You need to explicitly set elements to the NULL state before
6203 * dropping the final reference, to allow them to clean up.
6205 gst_element_set_state(queue2, GST_STATE_NULL);
6207 /* And, it still has a parent "player".
6208 * You need to let the parent manage the object instead of unreffing the object directly.
6210 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6211 gst_object_unref(queue2);
6216 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6217 * You need to explicitly set elements to the NULL state before
6218 * dropping the final reference, to allow them to clean up.
6220 gst_element_set_state(decodebin, GST_STATE_NULL);
6222 /* And, it still has a parent "player".
6223 * You need to let the parent manage the object instead of unreffing the object directly.
6226 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6227 gst_object_unref(decodebin);
6235 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6239 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6240 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6242 LOGD("class : %s, mime : %s", factory_class, mime);
6244 /* add missing plugin */
6245 /* NOTE : msl should check missing plugin for image mime type.
6246 * Some motion jpeg clips can have playable audio track.
6247 * So, msl have to play audio after displaying popup written video format not supported.
6249 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6250 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6251 LOGD("not found demuxer");
6252 player->not_found_demuxer = TRUE;
6253 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6259 if (!g_strrstr(factory_class, "Demuxer")) {
6260 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6261 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6262 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6264 /* check that clip have multi tracks or not */
6265 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6266 LOGD("video plugin is already linked");
6268 LOGW("add VIDEO to missing plugin");
6269 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6270 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6272 } else if (g_str_has_prefix(mime, "audio")) {
6273 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6274 LOGD("audio plugin is already linked");
6276 LOGW("add AUDIO to missing plugin");
6277 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6278 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6286 return MM_ERROR_NONE;
6290 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6292 mmplayer_t *player = (mmplayer_t *)data;
6296 MMPLAYER_RETURN_IF_FAIL(player);
6298 /* remove fakesink. */
6299 if (!_mmplayer_gst_remove_fakesink(player,
6300 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6301 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6302 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6303 * source element are not same. To overcome this situation, this function will called
6304 * several places and several times. Therefore, this is not an error case.
6309 LOGD("[handle: %p] pipeline has completely constructed", player);
6311 if ((player->msg_posted == FALSE) &&
6312 (player->cmd >= MMPLAYER_COMMAND_START))
6313 __mmplayer_handle_missed_plugin(player);
6315 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6319 __mmplayer_check_profile(void)
6322 static int profile_tv = -1;
6324 if (__builtin_expect(profile_tv != -1, 1))
6327 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6328 switch (*profileName) {
6343 __mmplayer_get_next_uri(mmplayer_t *player)
6345 mmplayer_parse_profile_t profile;
6347 guint num_of_list = 0;
6350 num_of_list = g_list_length(player->uri_info.uri_list);
6351 uri_idx = player->uri_info.uri_idx;
6353 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6354 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6355 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6357 LOGW("next uri does not exist");
6361 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6362 LOGE("failed to parse profile");
6366 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6367 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6368 LOGW("uri type is not supported(%d)", profile.uri_type);
6372 LOGD("success to find next uri %d", uri_idx);
6376 if (!uri || uri_idx == num_of_list) {
6377 LOGE("failed to find next uri");
6381 player->uri_info.uri_idx = uri_idx;
6382 if (mm_player_set_attribute((MMHandleType)player, NULL,
6383 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6384 LOGE("failed to set attribute");
6388 SECURE_LOGD("next playback uri: %s", uri);
6393 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6395 #define REPEAT_COUNT_INFINITE -1
6396 #define REPEAT_COUNT_MIN 2
6397 #define ORIGINAL_URI_ONLY 1
6399 MMHandleType attrs = 0;
6403 guint num_of_uri = 0;
6404 int profile_tv = -1;
6408 LOGD("checking for gapless play option");
6410 if (player->build_audio_offload) {
6411 LOGE("offload path is not supportable.");
6415 if (player->pipeline->textbin) {
6416 LOGE("subtitle path is enabled. gapless play is not supported.");
6420 attrs = MMPLAYER_GET_ATTRS(player);
6422 LOGE("fail to get attributes.");
6426 mm_attrs_multiple_get(player->attrs, NULL,
6427 "content_video_found", &video,
6428 "profile_play_count", &count,
6429 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6431 /* gapless playback is not supported in case of video at TV profile. */
6432 profile_tv = __mmplayer_check_profile();
6433 if (profile_tv && video) {
6434 LOGW("not support video gapless playback");
6438 /* check repeat count in case of audio */
6440 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6441 LOGW("gapless is disabled");
6445 num_of_uri = g_list_length(player->uri_info.uri_list);
6447 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6449 if (num_of_uri == ORIGINAL_URI_ONLY) {
6450 /* audio looping path */
6451 if (count >= REPEAT_COUNT_MIN) {
6452 /* decrease play count */
6453 /* we succeeded to rewind. update play count and then wait for next EOS */
6455 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6456 } else if (count != REPEAT_COUNT_INFINITE) {
6457 LOGD("there is no next uri and no repeat");
6460 LOGD("looping cnt %d", count);
6462 /* gapless playback path */
6463 if (!__mmplayer_get_next_uri(player)) {
6464 LOGE("failed to get next uri");
6471 LOGE("unable to play gapless path. EOS will be posted soon");
6476 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6478 mmplayer_track_t *selector = &player->track[type];
6479 mmplayer_gst_element_t *sinkbin = NULL;
6480 main_element_id_e selectorId = MMPLAYER_M_NUM;
6481 main_element_id_e sinkId = MMPLAYER_M_NUM;
6482 GstPad *srcpad = NULL;
6483 GstPad *sinkpad = NULL;
6484 gboolean send_notice = FALSE;
6487 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6489 LOGD("type %d", type);
6492 case MM_PLAYER_TRACK_TYPE_AUDIO:
6493 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6494 sinkId = MMPLAYER_A_BIN;
6495 sinkbin = player->pipeline->audiobin;
6497 case MM_PLAYER_TRACK_TYPE_VIDEO:
6498 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6499 sinkId = MMPLAYER_V_BIN;
6500 sinkbin = player->pipeline->videobin;
6503 case MM_PLAYER_TRACK_TYPE_TEXT:
6504 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6505 sinkId = MMPLAYER_T_BIN;
6506 sinkbin = player->pipeline->textbin;
6509 LOGE("requested type is not supportable");
6514 if (player->pipeline->mainbin[selectorId].gst) {
6517 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6519 if (selector->event_probe_id != 0)
6520 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6521 selector->event_probe_id = 0;
6523 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6524 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6526 if (srcpad && sinkpad) {
6527 /* after getting drained signal there is no data flows, so no need to do pad_block */
6528 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6529 gst_pad_unlink(srcpad, sinkpad);
6531 /* send custom event to sink pad to handle it at video sink */
6533 LOGD("send custom event to sinkpad");
6534 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6535 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6536 gst_pad_send_event(sinkpad, event);
6540 gst_object_unref(sinkpad);
6543 gst_object_unref(srcpad);
6546 LOGD("selector release");
6548 /* release and unref requests pad from the selector */
6549 for (n = 0; n < selector->streams->len; n++) {
6550 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6551 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6554 g_ptr_array_set_size(selector->streams, 0);
6556 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6557 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6559 player->pipeline->mainbin[selectorId].gst = NULL;
6567 __mmplayer_deactivate_old_path(mmplayer_t *player)
6570 MMPLAYER_RETURN_IF_FAIL(player);
6572 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6573 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6574 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6575 LOGE("deactivate selector error");
6579 _mmplayer_track_destroy(player);
6580 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6582 if (player->streamer) {
6583 _mm_player_streaming_initialize(player->streamer, FALSE);
6584 _mm_player_streaming_destroy(player->streamer);
6585 player->streamer = NULL;
6588 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6594 if (!player->msg_posted) {
6595 MMMessageParamType msg = {0,};
6598 msg.code = MM_ERROR_PLAYER_INTERNAL;
6599 LOGE("gapless_uri_play> deactivate error");
6601 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6602 player->msg_posted = TRUE;
6608 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6610 int result = MM_ERROR_NONE;
6611 mmplayer_t *player = (mmplayer_t *)hplayer;
6614 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6615 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6617 if (mm_player_set_attribute(hplayer, NULL,
6618 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6619 LOGE("failed to set attribute");
6620 result = MM_ERROR_PLAYER_INTERNAL;
6622 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6623 LOGE("failed to add the original uri in the uri list.");
6631 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6633 mmplayer_t *player = (mmplayer_t *)hplayer;
6634 guint num_of_list = 0;
6638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6639 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6641 if (player->pipeline && player->pipeline->textbin) {
6642 LOGE("subtitle path is enabled.");
6643 return MM_ERROR_PLAYER_INVALID_STATE;
6646 num_of_list = g_list_length(player->uri_info.uri_list);
6648 if (is_first_path) {
6649 if (num_of_list == 0) {
6650 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6651 SECURE_LOGD("add original path : %s", uri);
6653 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6654 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6656 SECURE_LOGD("change original path : %s", uri);
6659 MMHandleType attrs = 0;
6660 attrs = MMPLAYER_GET_ATTRS(player);
6662 if (num_of_list == 0) {
6663 char *original_uri = NULL;
6666 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6668 if (!original_uri) {
6669 LOGE("there is no original uri.");
6670 return MM_ERROR_PLAYER_INVALID_STATE;
6673 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6674 player->uri_info.uri_idx = 0;
6676 SECURE_LOGD("add original path at first : %s", original_uri);
6680 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6681 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6685 return MM_ERROR_NONE;
6689 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6691 mmplayer_t *player = (mmplayer_t *)hplayer;
6692 char *next_uri = NULL;
6693 guint num_of_list = 0;
6696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6698 num_of_list = g_list_length(player->uri_info.uri_list);
6700 if (num_of_list > 0) {
6701 gint uri_idx = player->uri_info.uri_idx;
6703 if (uri_idx < num_of_list-1)
6708 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6709 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6711 *uri = g_strdup(next_uri);
6715 return MM_ERROR_NONE;
6719 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6720 GstCaps *caps, gpointer data)
6722 mmplayer_t *player = (mmplayer_t *)data;
6723 const gchar *klass = NULL;
6724 const gchar *mime = NULL;
6725 gchar *caps_str = NULL;
6727 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6728 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6729 caps_str = gst_caps_to_string(caps);
6731 LOGW("unknown type of caps : %s from %s",
6732 caps_str, GST_ELEMENT_NAME(elem));
6734 MMPLAYER_FREEIF(caps_str);
6736 /* There is no available codec. */
6737 __mmplayer_check_not_supported_codec(player, klass, mime);
6741 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6742 GstCaps *caps, gpointer data)
6744 mmplayer_t *player = (mmplayer_t *)data;
6745 const char *mime = NULL;
6746 gboolean ret = TRUE;
6748 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6749 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6751 if (g_str_has_prefix(mime, "audio")) {
6752 GstStructure *caps_structure = NULL;
6753 gint samplerate = 0;
6755 gchar *caps_str = NULL;
6757 caps_structure = gst_caps_get_structure(caps, 0);
6758 gst_structure_get_int(caps_structure, "rate", &samplerate);
6759 gst_structure_get_int(caps_structure, "channels", &channels);
6761 if ((channels > 0 && samplerate == 0)) {
6762 LOGD("exclude audio...");
6766 caps_str = gst_caps_to_string(caps);
6767 /* set it directly because not sent by TAG */
6768 if (g_strrstr(caps_str, "mobile-xmf"))
6769 mm_player_set_attribute((MMHandleType)player, NULL,
6770 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6772 MMPLAYER_FREEIF(caps_str);
6773 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6774 LOGD("already video linked");
6777 LOGD("found new stream");
6784 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6786 gboolean ret = FALSE;
6787 GDBusConnection *conn = NULL;
6789 GVariant *result = NULL;
6790 const gchar *dbus_device_type = NULL;
6791 const gchar *dbus_ret = NULL;
6794 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6796 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6801 result = g_dbus_connection_call_sync(conn,
6802 "org.pulseaudio.Server",
6803 "/org/pulseaudio/StreamManager",
6804 "org.pulseaudio.StreamManager",
6805 "GetCurrentMediaRoutingPath",
6806 g_variant_new("(s)", "out"),
6807 G_VARIANT_TYPE("(ss)"),
6808 G_DBUS_CALL_FLAGS_NONE,
6812 if (!result || err) {
6813 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6818 /* device type is listed in stream-map.json at mmfw-sysconf */
6819 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6821 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6822 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6825 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6826 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6827 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6828 LOGD("audio offload is supportable");
6834 LOGD("audio offload is not supportable");
6837 g_variant_unref(result);
6839 g_object_unref(conn);
6844 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6846 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6847 gint64 position = 0;
6849 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6850 player->pipeline && player->pipeline->mainbin);
6852 MMPLAYER_CMD_LOCK(player);
6853 current_state = MMPLAYER_CURRENT_STATE(player);
6855 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6856 LOGW("getting current position failed in paused");
6858 _mmplayer_unrealize((MMHandleType)player);
6859 _mmplayer_realize((MMHandleType)player);
6861 _mmplayer_set_position((MMHandleType)player, position);
6863 /* async not to be blocked in streaming case */
6864 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6866 _mmplayer_pause((MMHandleType)player);
6868 if (current_state == MM_PLAYER_STATE_PLAYING)
6869 _mmplayer_start((MMHandleType)player);
6870 MMPLAYER_CMD_UNLOCK(player);
6872 LOGD("rebuilding audio pipeline is completed.");
6875 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6877 mmplayer_t *player = (mmplayer_t *)user_data;
6878 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6879 gboolean is_supportable = FALSE;
6881 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6882 LOGW("failed to get device type");
6884 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6886 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6887 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6888 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6889 LOGD("ignore this dev connected info");
6893 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6894 if (player->build_audio_offload == is_supportable) {
6895 LOGD("keep current pipeline without re-building");
6899 /* rebuild pipeline */
6900 LOGD("re-build pipeline - offload: %d", is_supportable);
6901 player->build_audio_offload = FALSE;
6902 __mmplayer_rebuild_audio_pipeline(player);
6908 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6910 unsigned int id = 0;
6912 if (player->audio_device_cb_id != 0) {
6913 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6917 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6918 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6919 LOGD("added device connected cb (%u)", id);
6920 player->audio_device_cb_id = id;
6922 LOGW("failed to add device connected cb");
6929 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6931 mmplayer_t *player = (mmplayer_t *)hplayer;
6934 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6935 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6937 *activated = player->build_audio_offload;
6939 LOGD("offload activated : %d", (int)*activated);
6942 return MM_ERROR_NONE;
6946 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6949 this function need to be updated according to the supported media format
6950 @see player->ini.audio_offload_media_format */
6952 if (__mmplayer_is_only_mp3_type(player->type)) {
6953 LOGD("offload supportable media format type");
6961 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6963 gboolean ret = FALSE;
6964 GstElementFactory *factory = NULL;
6967 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6969 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6970 if (!__mmplayer_is_offload_supported_type(player))
6973 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6974 LOGD("there is no audio offload sink");
6978 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6979 LOGW("there is no audio device type to support offload");
6983 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6985 LOGW("there is no installed audio offload sink element");
6988 gst_object_unref(factory);
6990 if (_mmplayer_acquire_hw_resource(player,
6991 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6992 LOGE("failed to acquire audio offload decoder resource");
6996 if (!__mmplayer_add_audio_device_connected_cb(player))
6999 if (!__mmplayer_is_audio_offload_device_type(player))
7002 LOGD("audio offload can be built");
7007 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7013 static GstAutoplugSelectResult
7014 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7016 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7017 int audio_offload = 0;
7019 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7020 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7022 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7023 LOGD("expose audio path to build offload output path");
7024 player->build_audio_offload = TRUE;
7025 /* update codec info */
7026 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7027 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7028 player->audiodec_linked = 1;
7030 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7034 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7035 And need to consider the multi-track audio content.
7036 There is no HW audio decoder in public. */
7038 /* set stream information */
7039 if (!player->audiodec_linked)
7040 _mmplayer_set_audio_attrs(player, caps);
7042 /* update codec info */
7043 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7044 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7045 player->audiodec_linked = 1;
7047 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7049 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7050 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7052 /* mark video decoder for acquire */
7053 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7054 LOGW("video decoder resource is already acquired, skip it.");
7055 ret = GST_AUTOPLUG_SELECT_SKIP;
7059 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7060 LOGE("failed to acquire video decoder resource");
7061 ret = GST_AUTOPLUG_SELECT_SKIP;
7064 player->interrupted_by_resource = FALSE;
7067 /* update codec info */
7068 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7069 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7070 player->videodec_linked = 1;
7078 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7079 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7081 #define DEFAULT_IDX 0xFFFF
7082 #define MIN_FACTORY_NUM 2
7083 mmplayer_t *player = (mmplayer_t *)data;
7084 GValueArray *new_factories = NULL;
7085 GValue val = { 0, };
7086 GstElementFactory *factory = NULL;
7087 const gchar *klass = NULL;
7088 gchar *factory_name = NULL;
7089 guint hw_dec_idx = DEFAULT_IDX;
7090 guint first_sw_dec_idx = DEFAULT_IDX;
7091 guint last_sw_dec_idx = DEFAULT_IDX;
7092 guint new_pos = DEFAULT_IDX;
7093 guint rm_pos = DEFAULT_IDX;
7094 int audio_codec_type;
7095 int video_codec_type;
7096 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7098 if (factories->n_values < MIN_FACTORY_NUM)
7101 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7102 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7105 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7107 for (int i = 0 ; i < factories->n_values ; i++) {
7108 gchar *hw_dec_info = NULL;
7109 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7111 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7113 LOGW("failed to get factory object");
7116 klass = gst_element_factory_get_klass(factory);
7117 factory_name = GST_OBJECT_NAME(factory);
7120 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7122 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7123 if (!player->need_audio_dec_sorting) {
7124 LOGD("sorting is not required");
7127 codec_type = audio_codec_type;
7128 hw_dec_info = player->ini.audiocodec_element_hw;
7129 sw_dec_info = player->ini.audiocodec_element_sw;
7130 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7131 if (!player->need_video_dec_sorting) {
7132 LOGD("sorting is not required");
7135 codec_type = video_codec_type;
7136 hw_dec_info = player->ini.videocodec_element_hw;
7137 sw_dec_info = player->ini.videocodec_element_sw;
7142 if (g_strrstr(factory_name, hw_dec_info)) {
7145 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7146 if (strstr(factory_name, sw_dec_info[j])) {
7147 last_sw_dec_idx = i;
7148 if (first_sw_dec_idx == DEFAULT_IDX) {
7149 first_sw_dec_idx = i;
7154 if (first_sw_dec_idx == DEFAULT_IDX)
7155 LOGW("unknown codec %s", factory_name);
7159 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7162 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7163 if (hw_dec_idx < first_sw_dec_idx)
7165 new_pos = first_sw_dec_idx;
7166 rm_pos = hw_dec_idx + 1;
7167 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7168 if (last_sw_dec_idx < hw_dec_idx)
7170 new_pos = last_sw_dec_idx + 1;
7171 rm_pos = hw_dec_idx;
7176 /* change position - insert H/W decoder according to the new position */
7177 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7179 LOGW("failed to get factory object");
7182 new_factories = g_value_array_copy(factories);
7183 g_value_init (&val, G_TYPE_OBJECT);
7184 g_value_set_object (&val, factory);
7185 g_value_array_insert(new_factories, new_pos, &val);
7186 g_value_unset (&val);
7187 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7189 for (int i = 0 ; i < new_factories->n_values ; i++) {
7190 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7192 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7193 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7195 LOGE("[Re-arranged] failed to get factory object");
7198 return new_factories;
7202 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7203 GstCaps *caps, GstElementFactory *factory, gpointer data)
7205 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7206 mmplayer_t *player = (mmplayer_t *)data;
7208 gchar *factory_name = NULL;
7209 gchar *caps_str = NULL;
7210 const gchar *klass = NULL;
7213 factory_name = GST_OBJECT_NAME(factory);
7214 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7215 caps_str = gst_caps_to_string(caps);
7217 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7219 /* store type string */
7220 if (player->type == NULL) {
7221 player->type = gst_caps_to_string(caps);
7222 __mmplayer_update_content_type_info(player);
7225 /* filtering exclude keyword */
7226 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7227 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7228 LOGW("skipping [%s] by exculde keyword [%s]",
7229 factory_name, player->ini.exclude_element_keyword[idx]);
7231 result = GST_AUTOPLUG_SELECT_SKIP;
7236 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7237 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7238 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7239 factory_name, player->ini.unsupported_codec_keyword[idx]);
7240 result = GST_AUTOPLUG_SELECT_SKIP;
7245 /* exclude webm format */
7246 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7247 * because webm format is not supportable.
7248 * If webm is disabled in "autoplug-continue", there is no state change
7249 * failure or error because the decodebin will expose the pad directly.
7250 * It make MSL invoke _prepare_async_callback.
7251 * So, we need to disable webm format in "autoplug-select" */
7252 if (caps_str && strstr(caps_str, "webm")) {
7253 LOGW("webm is not supported");
7254 result = GST_AUTOPLUG_SELECT_SKIP;
7258 /* check factory class for filtering */
7259 /* NOTE : msl don't need to use image plugins.
7260 * So, those plugins should be skipped for error handling.
7262 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7263 LOGD("skipping [%s] by not required", factory_name);
7264 result = GST_AUTOPLUG_SELECT_SKIP;
7268 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7269 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7270 // TO CHECK : subtitle if needed, add subparse exception.
7271 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7272 result = GST_AUTOPLUG_SELECT_SKIP;
7276 if (g_strrstr(factory_name, "mpegpsdemux")) {
7277 LOGD("skipping PS container - not support");
7278 result = GST_AUTOPLUG_SELECT_SKIP;
7282 if (g_strrstr(factory_name, "mssdemux"))
7283 player->smooth_streaming = TRUE;
7285 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7286 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7289 GstStructure *str = NULL;
7290 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7292 /* don't make video because of not required */
7293 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7294 (!player->set_mode.video_export)) {
7295 LOGD("no need video decoding, expose pad");
7296 result = GST_AUTOPLUG_SELECT_EXPOSE;
7300 /* get w/h for omx state-tune */
7301 /* FIXME: deprecated? */
7302 str = gst_caps_get_structure(caps, 0);
7303 gst_structure_get_int(str, "width", &width);
7306 if (player->v_stream_caps) {
7307 gst_caps_unref(player->v_stream_caps);
7308 player->v_stream_caps = NULL;
7311 player->v_stream_caps = gst_caps_copy(caps);
7312 LOGD("take caps for video state tune");
7313 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7317 if (g_strrstr(klass, "Codec/Decoder")) {
7318 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7319 if (result != GST_AUTOPLUG_SELECT_TRY) {
7320 LOGW("skip add decoder");
7326 MMPLAYER_FREEIF(caps_str);
7332 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7335 //mmplayer_t *player = (mmplayer_t *)data;
7336 GstCaps *caps = NULL;
7338 LOGD("[Decodebin2] pad-removed signal");
7340 caps = gst_pad_query_caps(new_pad, NULL);
7342 LOGW("query caps is NULL");
7346 gchar *caps_str = NULL;
7347 caps_str = gst_caps_to_string(caps);
7349 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7351 MMPLAYER_FREEIF(caps_str);
7352 gst_caps_unref(caps);
7356 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7358 mmplayer_t *player = (mmplayer_t *)data;
7359 GstIterator *iter = NULL;
7360 GValue item = { 0, };
7362 gboolean done = FALSE;
7363 gboolean is_all_drained = TRUE;
7366 MMPLAYER_RETURN_IF_FAIL(player);
7368 LOGD("got drained signal");
7370 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7371 LOGW("Fail to get cmd lock");
7375 if (!__mmplayer_verify_gapless_play_path(player)) {
7376 LOGD("decoding is finished.");
7377 MMPLAYER_CMD_UNLOCK(player);
7381 _mmplayer_set_reconfigure_state(player, TRUE);
7382 MMPLAYER_CMD_UNLOCK(player);
7384 /* check decodebin src pads whether they received EOS or not */
7385 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7388 switch (gst_iterator_next(iter, &item)) {
7389 case GST_ITERATOR_OK:
7390 pad = g_value_get_object(&item);
7391 if (pad && !GST_PAD_IS_EOS(pad)) {
7392 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7393 is_all_drained = FALSE;
7396 g_value_reset(&item);
7398 case GST_ITERATOR_RESYNC:
7399 gst_iterator_resync(iter);
7401 case GST_ITERATOR_ERROR:
7402 case GST_ITERATOR_DONE:
7407 g_value_unset(&item);
7408 gst_iterator_free(iter);
7410 if (!is_all_drained) {
7411 LOGD("Wait util the all pads get EOS.");
7416 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7417 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7419 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7420 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7421 __mmplayer_deactivate_old_path(player);
7427 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7429 mmplayer_t *player = (mmplayer_t *)data;
7430 const gchar *klass = NULL;
7431 gchar *factory_name = NULL;
7433 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7434 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7436 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7438 if (__mmplayer_add_dump_buffer_probe(player, element))
7439 LOGD("add buffer probe");
7441 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7442 gchar *selected = NULL;
7443 selected = g_strdup(GST_ELEMENT_NAME(element));
7444 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7446 /* update codec info */
7447 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7448 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7449 player->audiodec_linked = 1;
7450 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7451 /* update codec info */
7452 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7453 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7454 player->videodec_linked = 1;
7457 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7458 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7459 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7461 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7462 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7464 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7465 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7466 "max-video-width", player->adaptive_info.limit.width,
7467 "max-video-height", player->adaptive_info.limit.height, NULL);
7469 } else if (g_strrstr(klass, "Demuxer")) {
7471 LOGD("plugged element is demuxer. take it");
7473 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7474 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7477 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7478 int surface_type = 0;
7480 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7483 // to support trust-zone only
7484 if (g_strrstr(factory_name, "asfdemux")) {
7485 LOGD("set file-location %s", player->profile.uri);
7486 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7487 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7488 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7489 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7490 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7491 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7492 (__mmplayer_is_only_mp3_type(player->type))) {
7493 LOGD("[mpegaudioparse] set streaming pull mode.");
7494 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7496 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7497 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7500 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7501 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7502 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7504 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7505 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7507 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7508 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7509 (MMPLAYER_IS_DASH_STREAMING(player))) {
7510 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7511 _mm_player_streaming_set_multiqueue(player->streamer, element);
7512 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7521 __mmplayer_release_misc(mmplayer_t *player)
7524 bool cur_mode = player->set_mode.rich_audio;
7527 MMPLAYER_RETURN_IF_FAIL(player);
7529 player->sent_bos = FALSE;
7530 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7532 player->seek_state = MMPLAYER_SEEK_NONE;
7534 player->total_bitrate = 0;
7535 player->total_maximum_bitrate = 0;
7537 player->not_found_demuxer = 0;
7539 player->last_position = 0;
7540 player->duration = 0;
7541 player->http_content_size = 0;
7542 player->not_supported_codec = MISSING_PLUGIN_NONE;
7543 player->can_support_codec = FOUND_PLUGIN_NONE;
7544 player->pending_seek.is_pending = false;
7545 player->pending_seek.pos = 0;
7546 player->msg_posted = FALSE;
7547 player->has_many_types = FALSE;
7548 player->is_subtitle_force_drop = FALSE;
7549 player->play_subtitle = FALSE;
7550 player->adjust_subtitle_pos = 0;
7551 player->has_closed_caption = FALSE;
7552 player->set_mode.video_export = false;
7553 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7554 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7556 player->set_mode.rich_audio = cur_mode;
7558 if (player->audio_device_cb_id > 0 &&
7559 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7560 LOGW("failed to remove audio device_connected_callback");
7561 player->audio_device_cb_id = 0;
7563 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7564 player->bitrate[i] = 0;
7565 player->maximum_bitrate[i] = 0;
7568 /* free memory related to audio effect */
7569 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7571 if (player->adaptive_info.var_list) {
7572 g_list_free_full(player->adaptive_info.var_list, g_free);
7573 player->adaptive_info.var_list = NULL;
7576 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7577 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7578 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7580 /* Reset video360 settings to their defaults in case if the pipeline is to be
7583 player->video360_metadata.is_spherical = -1;
7584 player->is_openal_plugin_used = FALSE;
7586 player->is_content_spherical = FALSE;
7587 player->is_video360_enabled = TRUE;
7588 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7589 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7590 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7591 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7592 player->video360_zoom = 1.0f;
7593 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7594 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7596 player->sound.rg_enable = false;
7598 __mmplayer_initialize_video_roi(player);
7603 __mmplayer_release_misc_post(mmplayer_t *player)
7605 char *original_uri = NULL;
7608 /* player->pipeline is already released before. */
7609 MMPLAYER_RETURN_IF_FAIL(player);
7611 player->video_decoded_cb = NULL;
7612 player->video_decoded_cb_user_param = NULL;
7613 player->video_stream_prerolled = false;
7615 player->audio_decoded_cb = NULL;
7616 player->audio_decoded_cb_user_param = NULL;
7617 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7619 player->audio_stream_changed_cb = NULL;
7620 player->audio_stream_changed_cb_user_param = NULL;
7622 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7624 /* clean found audio decoders */
7625 if (player->audio_decoders) {
7626 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7627 player->audio_decoders = NULL;
7630 /* clean the uri list except original uri */
7631 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7633 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7634 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7635 g_list_free_full(tmp, (GDestroyNotify)g_free);
7638 LOGW("failed to get original uri info");
7640 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7641 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7645 /* clear the audio stream buffer list */
7646 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7648 /* clear the video stream bo list */
7649 __mmplayer_video_stream_destroy_bo_list(player);
7650 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7652 if (player->profile.input_mem.buf) {
7653 free(player->profile.input_mem.buf);
7654 player->profile.input_mem.buf = NULL;
7656 player->profile.input_mem.len = 0;
7657 player->profile.input_mem.offset = 0;
7659 player->uri_info.uri_idx = 0;
7664 __mmplayer_check_subtitle(mmplayer_t *player)
7666 MMHandleType attrs = 0;
7667 char *subtitle_uri = NULL;
7671 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7673 /* get subtitle attribute */
7674 attrs = MMPLAYER_GET_ATTRS(player);
7678 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7679 if (!subtitle_uri || !strlen(subtitle_uri))
7682 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7683 player->is_external_subtitle_present = TRUE;
7691 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7693 MMPLAYER_RETURN_IF_FAIL(player);
7695 if (player->eos_timer) {
7696 LOGD("cancel eos timer");
7697 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7698 player->eos_timer = 0;
7705 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7709 MMPLAYER_RETURN_IF_FAIL(player);
7710 MMPLAYER_RETURN_IF_FAIL(sink);
7712 player->sink_elements = g_list_append(player->sink_elements, sink);
7718 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7722 MMPLAYER_RETURN_IF_FAIL(player);
7723 MMPLAYER_RETURN_IF_FAIL(sink);
7725 player->sink_elements = g_list_remove(player->sink_elements, sink);
7731 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7732 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7734 mmplayer_signal_item_t *item = NULL;
7737 MMPLAYER_RETURN_IF_FAIL(player);
7739 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7740 LOGE("invalid signal type [%d]", type);
7744 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7746 LOGE("cannot connect signal [%s]", signal);
7751 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7752 player->signals[type] = g_list_append(player->signals[type], item);
7758 /* NOTE : be careful with calling this api. please refer to below glib comment
7759 * glib comment : Note that there is a bug in GObject that makes this function much
7760 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7761 * will no longer be called, but, the signal handler is not currently disconnected.
7762 * If the instance is itself being freed at the same time than this doesn't matter,
7763 * since the signal will automatically be removed, but if instance persists,
7764 * then the signal handler will leak. You should not remove the signal yourself
7765 * because in a future versions of GObject, the handler will automatically be
7768 * It's possible to work around this problem in a way that will continue to work
7769 * with future versions of GObject by checking that the signal handler is still
7770 * connected before disconnected it:
7772 * if (g_signal_handler_is_connected(instance, id))
7773 * g_signal_handler_disconnect(instance, id);
7776 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7778 GList *sig_list = NULL;
7779 mmplayer_signal_item_t *item = NULL;
7783 MMPLAYER_RETURN_IF_FAIL(player);
7785 LOGD("release signals type : %d", type);
7787 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7788 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7789 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7790 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7791 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7792 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7796 sig_list = player->signals[type];
7798 for (; sig_list; sig_list = sig_list->next) {
7799 item = sig_list->data;
7801 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7802 if (g_signal_handler_is_connected(item->obj, item->sig))
7803 g_signal_handler_disconnect(item->obj, item->sig);
7806 MMPLAYER_FREEIF(item);
7809 g_list_free(player->signals[type]);
7810 player->signals[type] = NULL;
7818 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7820 mmplayer_t *player = 0;
7821 int prev_display_surface_type = 0;
7825 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7827 player = MM_PLAYER_CAST(handle);
7829 /* check video sinkbin is created */
7830 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7831 LOGW("Videosink is already created");
7832 return MM_ERROR_NONE;
7835 LOGD("videosink element is not yet ready");
7837 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7838 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7840 return MM_ERROR_INVALID_ARGUMENT;
7843 /* load previous attributes */
7844 if (player->attrs) {
7845 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7846 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7847 if (prev_display_surface_type == surface_type) {
7848 LOGD("incoming display surface type is same as previous one, do nothing..");
7850 return MM_ERROR_NONE;
7853 LOGE("failed to load attributes");
7855 return MM_ERROR_PLAYER_INTERNAL;
7858 /* videobin is not created yet, so we just set attributes related to display surface */
7859 LOGD("store display attribute for given surface type(%d)", surface_type);
7860 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7861 "display_overlay", wl_surface_id, NULL);
7864 return MM_ERROR_NONE;
7867 /* Note : if silent is true, then subtitle would not be displayed. :*/
7869 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7871 mmplayer_t *player = (mmplayer_t *)hplayer;
7875 /* check player handle */
7876 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7878 player->set_mode.subtitle_off = silent;
7880 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7884 return MM_ERROR_NONE;
7888 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7890 mmplayer_gst_element_t *mainbin = NULL;
7891 mmplayer_gst_element_t *textbin = NULL;
7892 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7893 GstState current_state = GST_STATE_VOID_PENDING;
7894 GstState element_state = GST_STATE_VOID_PENDING;
7895 GstState element_pending_state = GST_STATE_VOID_PENDING;
7897 GstEvent *event = NULL;
7898 int result = MM_ERROR_NONE;
7900 GstClock *curr_clock = NULL;
7901 GstClockTime base_time, start_time, curr_time;
7906 /* check player handle */
7907 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7909 player->pipeline->mainbin &&
7910 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7912 mainbin = player->pipeline->mainbin;
7913 textbin = player->pipeline->textbin;
7915 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7917 // sync clock with current pipeline
7918 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7919 curr_time = gst_clock_get_time(curr_clock);
7921 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7922 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7924 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7925 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7927 if (current_state > GST_STATE_READY) {
7928 // sync state with current pipeline
7929 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7930 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7931 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7933 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7934 if (GST_STATE_CHANGE_FAILURE == ret) {
7935 LOGE("fail to state change.");
7936 result = MM_ERROR_PLAYER_INTERNAL;
7940 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7941 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7944 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7945 gst_object_unref(curr_clock);
7948 // seek to current position
7949 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7950 result = MM_ERROR_PLAYER_INVALID_STATE;
7951 LOGE("gst_element_query_position failed, invalid state");
7955 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7956 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);
7958 _mmplayer_gst_send_event_to_sink(player, event);
7960 result = MM_ERROR_PLAYER_INTERNAL;
7961 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7965 /* sync state with current pipeline */
7966 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7967 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7968 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7970 return MM_ERROR_NONE;
7973 /* release text pipeline resource */
7974 player->textsink_linked = 0;
7976 /* release signal */
7977 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7979 /* release textbin with it's childs */
7980 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7981 MMPLAYER_FREEIF(player->pipeline->textbin);
7982 player->pipeline->textbin = NULL;
7984 /* release subtitle elem */
7985 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7986 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7992 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7994 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7995 GstState current_state = GST_STATE_VOID_PENDING;
7997 MMHandleType attrs = 0;
7998 mmplayer_gst_element_t *mainbin = NULL;
7999 mmplayer_gst_element_t *textbin = NULL;
8001 gchar *subtitle_uri = NULL;
8002 int result = MM_ERROR_NONE;
8003 const gchar *charset = NULL;
8007 /* check player handle */
8008 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8010 player->pipeline->mainbin &&
8011 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8012 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8014 mainbin = player->pipeline->mainbin;
8015 textbin = player->pipeline->textbin;
8017 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8018 if (current_state < GST_STATE_READY) {
8019 result = MM_ERROR_PLAYER_INVALID_STATE;
8020 LOGE("Pipeline is not in proper state");
8024 attrs = MMPLAYER_GET_ATTRS(player);
8026 LOGE("cannot get content attribute");
8027 result = MM_ERROR_PLAYER_INTERNAL;
8031 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8032 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8033 LOGE("subtitle uri is not proper filepath");
8034 result = MM_ERROR_PLAYER_INVALID_URI;
8038 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8039 LOGE("failed to get storage info of subtitle path");
8040 result = MM_ERROR_PLAYER_INVALID_URI;
8044 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8045 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8047 if (!strcmp(filepath, subtitle_uri)) {
8048 LOGD("subtitle path is not changed");
8051 if (mm_player_set_attribute((MMHandleType)player, NULL,
8052 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8053 LOGE("failed to set attribute");
8058 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8059 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8060 player->subtitle_language_list = NULL;
8061 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8063 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8064 if (ret != GST_STATE_CHANGE_SUCCESS) {
8065 LOGE("failed to change state of textbin to READY");
8066 result = MM_ERROR_PLAYER_INTERNAL;
8070 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8071 if (ret != GST_STATE_CHANGE_SUCCESS) {
8072 LOGE("failed to change state of subparse to READY");
8073 result = MM_ERROR_PLAYER_INTERNAL;
8077 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8078 if (ret != GST_STATE_CHANGE_SUCCESS) {
8079 LOGE("failed to change state of filesrc to READY");
8080 result = MM_ERROR_PLAYER_INTERNAL;
8084 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8086 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8088 charset = _mmplayer_get_charset(filepath);
8090 LOGD("detected charset is %s", charset);
8091 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8094 result = _mmplayer_sync_subtitle_pipeline(player);
8101 /* API to switch between external subtitles */
8103 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8105 int result = MM_ERROR_NONE;
8106 mmplayer_t *player = (mmplayer_t *)hplayer;
8111 /* check player handle */
8112 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8114 /* filepath can be null in idle state */
8116 /* check file path */
8117 if ((path = strstr(filepath, "file://")))
8118 result = _mmplayer_exist_file_path(path + 7);
8120 result = _mmplayer_exist_file_path(filepath);
8122 if (result != MM_ERROR_NONE) {
8123 LOGE("invalid subtitle path 0x%X", result);
8124 return result; /* file not found or permission denied */
8128 if (!player->pipeline) {
8130 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8131 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8132 LOGE("failed to set attribute");
8133 return MM_ERROR_PLAYER_INTERNAL;
8136 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8137 /* check filepath */
8138 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8140 if (!__mmplayer_check_subtitle(player)) {
8141 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8142 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8143 LOGE("failed to set attribute");
8144 return MM_ERROR_PLAYER_INTERNAL;
8147 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8148 LOGE("fail to create text pipeline");
8149 return MM_ERROR_PLAYER_INTERNAL;
8152 result = _mmplayer_sync_subtitle_pipeline(player);
8154 result = __mmplayer_change_external_subtitle_language(player, filepath);
8157 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8158 player->is_external_subtitle_added_now = TRUE;
8160 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8161 if (!player->subtitle_language_list) {
8162 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8163 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8164 LOGW("subtitle language list is not updated yet");
8166 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8174 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8176 guint active_idx = 0;
8177 GstStream *stream = NULL;
8178 GList *streams = NULL;
8179 GstEvent *ev = NULL;
8180 GstCaps *caps = NULL;
8182 LOGD("Switching Streams... type: %d, index: %d", type, index);
8184 player->track[type].active_track_index = index;
8186 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8187 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8188 if (player->track[i].total_track_num > 0) {
8189 active_idx = player->track[i].active_track_index;
8190 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8191 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8192 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8194 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8195 caps = gst_stream_get_caps(stream);
8197 _mmplayer_set_audio_attrs(player, caps);
8198 gst_caps_unref(caps);
8204 ev = gst_event_new_select_streams(streams);
8205 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8206 g_list_free(streams);
8208 return MM_ERROR_NONE;
8212 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8214 int result = MM_ERROR_NONE;
8215 gchar *change_pad_name = NULL;
8216 GstPad *sinkpad = NULL;
8217 mmplayer_gst_element_t *mainbin = NULL;
8218 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8219 GstCaps *caps = NULL;
8220 gint total_track_num = 0;
8224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8225 MM_ERROR_PLAYER_NOT_INITIALIZED);
8227 LOGD("Change Track(%d) to %d", type, index);
8229 mainbin = player->pipeline->mainbin;
8231 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8232 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8233 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8234 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8236 /* Changing Video Track is not supported. */
8237 LOGE("Track Type Error");
8241 if (mainbin[elem_idx].gst == NULL) {
8242 result = MM_ERROR_PLAYER_NO_OP;
8243 LOGD("Req track doesn't exist");
8247 total_track_num = player->track[type].total_track_num;
8248 if (total_track_num <= 0) {
8249 result = MM_ERROR_PLAYER_NO_OP;
8250 LOGD("Language list is not available");
8254 if ((index < 0) || (index >= total_track_num)) {
8255 result = MM_ERROR_INVALID_ARGUMENT;
8256 LOGD("Not a proper index : %d", index);
8260 /*To get the new pad from the selector*/
8261 change_pad_name = g_strdup_printf("sink_%u", index);
8262 if (change_pad_name == NULL) {
8263 result = MM_ERROR_PLAYER_INTERNAL;
8264 LOGD("Pad does not exists");
8268 LOGD("new active pad name: %s", change_pad_name);
8270 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8271 if (sinkpad == NULL) {
8272 LOGD("sinkpad is NULL");
8273 result = MM_ERROR_PLAYER_INTERNAL;
8277 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8278 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8280 caps = gst_pad_get_current_caps(sinkpad);
8281 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8284 gst_object_unref(sinkpad);
8286 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8287 _mmplayer_set_audio_attrs(player, caps);
8290 gst_caps_unref(caps);
8293 MMPLAYER_FREEIF(change_pad_name);
8298 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8300 int result = MM_ERROR_NONE;
8301 mmplayer_t *player = NULL;
8302 mmplayer_gst_element_t *mainbin = NULL;
8304 gint current_active_index = 0;
8306 GstState current_state = GST_STATE_VOID_PENDING;
8311 player = (mmplayer_t *)hplayer;
8312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8314 if (!player->pipeline) {
8315 LOGE("Track %d pre setting -> %d", type, index);
8317 player->track[type].active_track_index = index;
8321 mainbin = player->pipeline->mainbin;
8323 current_active_index = player->track[type].active_track_index;
8325 /*If index is same as running index no need to change the pad*/
8326 if (current_active_index == index)
8329 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8330 result = MM_ERROR_PLAYER_INVALID_STATE;
8334 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8335 if (current_state < GST_STATE_PAUSED) {
8336 result = MM_ERROR_PLAYER_INVALID_STATE;
8337 LOGW("Pipeline not in porper state");
8341 if (MMPLAYER_USE_DECODEBIN(player)) {
8342 result = __mmplayer_change_selector_pad(player, type, index);
8344 result = __mmplayer_switch_stream(player, type, index);
8346 if (result != MM_ERROR_NONE) {
8347 LOGE("failed to change track");
8351 player->track[type].active_track_index = index;
8353 if (MMPLAYER_USE_DECODEBIN(player)) {
8354 GstEvent *event = NULL;
8355 if (current_state == GST_STATE_PLAYING) {
8356 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8357 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8358 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8360 _mmplayer_gst_send_event_to_sink(player, event);
8362 result = MM_ERROR_PLAYER_INTERNAL;
8373 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8375 mmplayer_t *player = (mmplayer_t *)hplayer;
8379 /* check player handle */
8380 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8382 *silent = player->set_mode.subtitle_off;
8384 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8388 return MM_ERROR_NONE;
8392 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8394 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8395 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8397 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8398 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8402 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8403 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8404 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8405 mmplayer_dump_t *dump_s;
8406 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8407 if (dump_s == NULL) {
8408 LOGE("malloc fail");
8412 dump_s->dump_element_file = NULL;
8413 dump_s->dump_pad = NULL;
8414 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8416 if (dump_s->dump_pad) {
8417 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8418 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]);
8419 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8420 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);
8421 /* add list for removed buffer probe and close FILE */
8422 player->dump_list = g_list_append(player->dump_list, dump_s);
8423 LOGD("%s sink pad added buffer probe for dump", factory_name);
8426 MMPLAYER_FREEIF(dump_s);
8427 LOGE("failed to get %s sink pad added", factory_name);
8434 static GstPadProbeReturn
8435 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8437 FILE *dump_data = (FILE *)u_data;
8439 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8440 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8442 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8444 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8446 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8448 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8450 gst_buffer_unmap(buffer, &probe_info);
8452 return GST_PAD_PROBE_OK;
8456 __mmplayer_release_dump_list(GList *dump_list)
8458 GList *d_list = dump_list;
8463 for (; d_list; d_list = g_list_next(d_list)) {
8464 mmplayer_dump_t *dump_s = d_list->data;
8465 if (dump_s->dump_pad) {
8466 if (dump_s->probe_handle_id)
8467 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8468 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8470 if (dump_s->dump_element_file) {
8471 fclose(dump_s->dump_element_file);
8472 dump_s->dump_element_file = NULL;
8474 MMPLAYER_FREEIF(dump_s);
8476 g_list_free(dump_list);
8481 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8483 mmplayer_t *player = (mmplayer_t *)hplayer;
8487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8488 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8490 *exist = (bool)player->has_closed_caption;
8494 return MM_ERROR_NONE;
8498 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8503 LOGD("unref internal gst buffer %p", buffer);
8505 gst_buffer_unref((GstBuffer *)buffer);
8512 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8514 mmplayer_t *player = (mmplayer_t *)hplayer;
8518 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8519 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8521 if (MMPLAYER_IS_STREAMING(player))
8522 *timeout = (int)player->ini.live_state_change_timeout;
8524 *timeout = (int)player->ini.localplayback_state_change_timeout;
8526 LOGD("timeout = %d", *timeout);
8529 return MM_ERROR_NONE;
8533 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8537 MMPLAYER_RETURN_IF_FAIL(player);
8539 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8541 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8542 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8543 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8544 player->storage_info[i].id = -1;
8545 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8547 if (path_type != MMPLAYER_PATH_MAX)
8556 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8558 int ret = MM_ERROR_NONE;
8559 mmplayer_t *player = (mmplayer_t *)hplayer;
8560 MMMessageParamType msg_param = {0, };
8563 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8565 LOGW("state changed storage %d:%d", id, state);
8567 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8568 return MM_ERROR_NONE;
8570 /* FIXME: text path should be handled seperately. */
8571 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8572 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8573 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8574 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8575 LOGW("external storage is removed");
8577 if (player->msg_posted == FALSE) {
8578 memset(&msg_param, 0, sizeof(MMMessageParamType));
8579 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8580 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8581 player->msg_posted = TRUE;
8584 /* unrealize the player */
8585 ret = _mmplayer_unrealize(hplayer);
8586 if (ret != MM_ERROR_NONE)
8587 LOGE("failed to unrealize");
8595 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8597 int ret = MM_ERROR_NONE;
8598 mmplayer_t *player = (mmplayer_t *)hplayer;
8599 int idx = 0, total = 0;
8600 gchar *result = NULL, *tmp = NULL;
8603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8604 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8606 total = *num = g_list_length(player->adaptive_info.var_list);
8608 LOGW("There is no stream variant info.");
8612 result = g_strdup("");
8613 for (idx = 0 ; idx < total ; idx++) {
8614 stream_variant_t *v_data = NULL;
8615 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8618 gchar data[64] = {0};
8619 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8621 tmp = g_strconcat(result, data, NULL);
8625 LOGW("There is no variant data in %d", idx);
8630 *var_info = (char *)result;
8632 LOGD("variant info %d:%s", *num, *var_info);
8638 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8640 int ret = MM_ERROR_NONE;
8641 mmplayer_t *player = (mmplayer_t *)hplayer;
8644 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8646 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8648 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8649 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8650 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8652 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8653 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8654 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8655 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8657 /* FIXME: seek to current position for applying new variant limitation */
8666 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8668 int ret = MM_ERROR_NONE;
8669 mmplayer_t *player = (mmplayer_t *)hplayer;
8672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8673 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8675 *bandwidth = player->adaptive_info.limit.bandwidth;
8676 *width = player->adaptive_info.limit.width;
8677 *height = player->adaptive_info.limit.height;
8679 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8686 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8688 int ret = MM_ERROR_NONE;
8689 mmplayer_t *player = (mmplayer_t *)hplayer;
8692 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8693 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8694 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8696 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8698 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8699 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8700 else /* live case */
8701 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8703 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8710 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8712 #define IDX_FIRST_SW_CODEC 0
8713 mmplayer_t *player = (mmplayer_t *)hplayer;
8714 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8717 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8719 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8720 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8721 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8723 switch (stream_type) {
8724 case MM_PLAYER_STREAM_TYPE_AUDIO:
8725 /* to support audio codec selection, codec info have to be added in ini file as below.
8726 audio codec element hw = xxxx
8727 audio codec element sw = avdec
8728 and in case of audio hw codec is supported and selected,
8729 audio filter elements should be applied depending on the hw capabilities.
8731 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8732 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8733 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8734 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8735 LOGE("There is no audio codec info for codec_type %d", codec_type);
8736 return MM_ERROR_PLAYER_NO_OP;
8739 case MM_PLAYER_STREAM_TYPE_VIDEO:
8740 /* to support video codec selection, codec info have to be added in ini file as below.
8741 video codec element hw = omx
8742 video codec element sw = avdec */
8743 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8744 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8745 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8746 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8747 LOGE("There is no video codec info for codec_type %d", codec_type);
8748 return MM_ERROR_PLAYER_NO_OP;
8752 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8753 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8757 LOGD("update %s codec_type to %d", attr_name, codec_type);
8758 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8761 return MM_ERROR_NONE;
8765 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8767 mmplayer_t *player = (mmplayer_t *)hplayer;
8768 GstElement *rg_vol_element = NULL;
8772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8774 player->sound.rg_enable = enabled;
8776 /* just hold rgvolume enable value if pipeline is not ready */
8777 if (!player->pipeline || !player->pipeline->audiobin) {
8778 LOGD("pipeline is not ready. holding rgvolume enable value");
8779 return MM_ERROR_NONE;
8782 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8784 if (!rg_vol_element) {
8785 LOGD("rgvolume element is not created");
8786 return MM_ERROR_PLAYER_INTERNAL;
8790 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8792 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8796 return MM_ERROR_NONE;
8800 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8802 mmplayer_t *player = (mmplayer_t *)hplayer;
8803 GstElement *rg_vol_element = NULL;
8804 gboolean enable = FALSE;
8808 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8809 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8811 /* just hold enable_rg value if pipeline is not ready */
8812 if (!player->pipeline || !player->pipeline->audiobin) {
8813 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8814 *enabled = player->sound.rg_enable;
8815 return MM_ERROR_NONE;
8818 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8820 if (!rg_vol_element) {
8821 LOGD("rgvolume element is not created");
8822 return MM_ERROR_PLAYER_INTERNAL;
8825 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8826 *enabled = (bool)enable;
8830 return MM_ERROR_NONE;
8834 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8836 mmplayer_t *player = (mmplayer_t *)hplayer;
8837 MMHandleType attrs = 0;
8839 int ret = MM_ERROR_NONE;
8843 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8845 attrs = MMPLAYER_GET_ATTRS(player);
8846 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8848 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8850 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8851 return MM_ERROR_PLAYER_INTERNAL;
8854 player->video_roi.scale_x = scale_x;
8855 player->video_roi.scale_y = scale_y;
8856 player->video_roi.scale_width = scale_width;
8857 player->video_roi.scale_height = scale_height;
8859 /* check video sinkbin is created */
8860 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8861 return MM_ERROR_NONE;
8863 if (!gst_video_overlay_set_video_roi_area(
8864 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8865 scale_x, scale_y, scale_width, scale_height))
8866 ret = MM_ERROR_PLAYER_INTERNAL;
8868 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8869 scale_x, scale_y, scale_width, scale_height);
8877 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8879 mmplayer_t *player = (mmplayer_t *)hplayer;
8880 int ret = MM_ERROR_NONE;
8884 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8885 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8887 *scale_x = player->video_roi.scale_x;
8888 *scale_y = player->video_roi.scale_y;
8889 *scale_width = player->video_roi.scale_width;
8890 *scale_height = player->video_roi.scale_height;
8892 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8893 *scale_x, *scale_y, *scale_width, *scale_height);
8899 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8901 mmplayer_t *player = (mmplayer_t *)hplayer;
8905 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8907 player->client_pid = pid;
8909 LOGD("client pid[%d] %p", pid, player);
8913 return MM_ERROR_NONE;
8917 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8919 mmplayer_t *player = (mmplayer_t *)hplayer;
8920 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8921 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8926 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8929 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8931 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8933 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8934 return MM_ERROR_NONE;
8936 /* in case of audio codec default type is HW */
8938 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8939 if (player->ini.support_audio_effect)
8940 return MM_ERROR_NONE;
8941 elem_id = MMPLAYER_A_FILTER;
8943 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8944 if (player->ini.support_replaygain_control)
8945 return MM_ERROR_NONE;
8946 elem_id = MMPLAYER_A_RGVOL;
8948 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8949 if (player->ini.support_pitch_control)
8950 return MM_ERROR_NONE;
8951 elem_id = MMPLAYER_A_PITCH;
8953 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8954 if (player->ini.support_audio_effect)
8955 return MM_ERROR_NONE;
8957 /* default case handling is not required */
8960 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8961 LOGW("audio control option [%d] is not available", opt);
8964 /* setting pcm exporting option is allowed before READY state */
8965 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8966 return MM_ERROR_PLAYER_INVALID_STATE;
8968 /* check whether the audio filter exist or not after READY state,
8969 because the sw codec could be added during auto-plugging in some cases */
8970 if (!player->pipeline ||
8971 !player->pipeline->audiobin ||
8972 !player->pipeline->audiobin[elem_id].gst) {
8973 LOGW("there is no audio elem [%d]", elem_id);
8978 LOGD("audio control opt %d, available %d", opt, *available);
8982 return MM_ERROR_NONE;
8986 __mmplayer_update_duration_value(mmplayer_t *player)
8988 gboolean ret = FALSE;
8989 gint64 dur_nsec = 0;
8990 LOGD("try to update duration");
8992 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8993 player->duration = dur_nsec;
8994 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8998 if (player->duration < 0) {
8999 LOGW("duration is Non-Initialized !!!");
9000 player->duration = 0;
9003 /* update streaming service type */
9004 player->streaming_type = _mmplayer_get_stream_service_type(player);
9006 /* check duration is OK */
9007 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9008 /* FIXIT : find another way to get duration here. */
9009 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9015 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9017 /* update audio params
9018 NOTE : We need original audio params and it can be only obtained from src pad of audio
9019 decoder. Below code only valid when we are not using 'resampler' just before
9020 'audioconverter'. */
9021 GstCaps *caps_a = NULL;
9023 gint samplerate = 0, channels = 0;
9024 GstStructure *p = NULL;
9025 GstElement *aconv = NULL;
9027 LOGD("try to update audio attrs");
9029 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9031 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9032 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9033 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9034 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9036 LOGE("there is no audio converter");
9040 pad = gst_element_get_static_pad(aconv, "sink");
9043 LOGW("failed to get pad from audio converter");
9047 caps_a = gst_pad_get_current_caps(pad);
9049 LOGW("not ready to get audio caps");
9050 gst_object_unref(pad);
9054 p = gst_caps_get_structure(caps_a, 0);
9056 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9058 gst_structure_get_int(p, "rate", &samplerate);
9059 gst_structure_get_int(p, "channels", &channels);
9061 mm_player_set_attribute((MMHandleType)player, NULL,
9062 "content_audio_samplerate", samplerate,
9063 "content_audio_channels", channels, NULL);
9065 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9067 gst_caps_unref(caps_a);
9068 gst_object_unref(pad);
9074 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9076 LOGD("try to update video attrs");
9078 GstCaps *caps_v = NULL;
9082 GstStructure *p = NULL;
9084 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9085 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9087 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9089 LOGD("no videosink sink pad");
9093 caps_v = gst_pad_get_current_caps(pad);
9094 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9095 if (!caps_v && player->v_stream_caps) {
9096 caps_v = player->v_stream_caps;
9097 gst_caps_ref(caps_v);
9101 LOGD("no negitiated caps from videosink");
9102 gst_object_unref(pad);
9106 p = gst_caps_get_structure(caps_v, 0);
9107 gst_structure_get_int(p, "width", &width);
9108 gst_structure_get_int(p, "height", &height);
9110 mm_player_set_attribute((MMHandleType)player, NULL,
9111 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9113 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9115 SECURE_LOGD("width : %d height : %d", width, height);
9117 gst_caps_unref(caps_v);
9118 gst_object_unref(pad);
9121 mm_player_set_attribute((MMHandleType)player, NULL,
9122 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9123 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9130 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9132 gboolean ret = FALSE;
9133 guint64 data_size = 0;
9137 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9138 if (!player->duration)
9141 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9142 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9143 if (stat(path, &sb) == 0)
9144 data_size = (guint64)sb.st_size;
9146 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9147 data_size = player->http_content_size;
9150 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9153 guint64 bitrate = 0;
9154 guint64 msec_dur = 0;
9156 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9158 bitrate = data_size * 8 * 1000 / msec_dur;
9159 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9160 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9161 mm_player_set_attribute((MMHandleType)player, NULL,
9162 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9165 LOGD("player duration is less than 0");
9169 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9170 if (player->total_bitrate) {
9171 mm_player_set_attribute((MMHandleType)player, NULL,
9172 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9181 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9183 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9184 data->uri_type = uri_type;
9188 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9190 int ret = MM_ERROR_PLAYER_INVALID_URI;
9192 char *buffer = NULL;
9193 char *seperator = strchr(path, ',');
9194 char ext[100] = {0,}, size[100] = {0,};
9197 if ((buffer = strstr(path, "ext="))) {
9198 buffer += strlen("ext=");
9200 if (strlen(buffer)) {
9201 strncpy(ext, buffer, 99);
9203 if ((seperator = strchr(ext, ','))
9204 || (seperator = strchr(ext, ' '))
9205 || (seperator = strchr(ext, '\0'))) {
9206 seperator[0] = '\0';
9211 if ((buffer = strstr(path, "size="))) {
9212 buffer += strlen("size=");
9214 if (strlen(buffer) > 0) {
9215 strncpy(size, buffer, 99);
9217 if ((seperator = strchr(size, ','))
9218 || (seperator = strchr(size, ' '))
9219 || (seperator = strchr(size, '\0'))) {
9220 seperator[0] = '\0';
9223 mem_size = atoi(size);
9228 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9230 if (mem_size && param) {
9231 if (data->input_mem.buf)
9232 free(data->input_mem.buf);
9233 data->input_mem.buf = malloc(mem_size);
9235 if (data->input_mem.buf) {
9236 memcpy(data->input_mem.buf, param, mem_size);
9237 data->input_mem.len = mem_size;
9238 ret = MM_ERROR_NONE;
9240 LOGE("failed to alloc mem %d", mem_size);
9241 ret = MM_ERROR_PLAYER_INTERNAL;
9244 data->input_mem.offset = 0;
9245 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9252 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9254 gchar *location = NULL;
9257 int ret = MM_ERROR_NONE;
9259 if ((path = strstr(uri, "file://"))) {
9260 location = g_filename_from_uri(uri, NULL, &err);
9261 if (!location || (err != NULL)) {
9262 LOGE("Invalid URI '%s' for filesrc: %s", path,
9263 (err != NULL) ? err->message : "unknown error");
9267 MMPLAYER_FREEIF(location);
9269 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9270 return MM_ERROR_PLAYER_INVALID_URI;
9272 LOGD("path from uri: %s", location);
9275 path = (location != NULL) ? (location) : ((char *)uri);
9278 ret = _mmplayer_exist_file_path(path);
9280 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9281 if (ret == MM_ERROR_NONE) {
9282 if (_mmplayer_is_sdp_file(path)) {
9283 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9284 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9285 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9287 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9288 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9290 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9291 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9293 LOGE("invalid uri, could not play..");
9294 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9297 MMPLAYER_FREEIF(location);
9302 static mmplayer_video_decoded_data_info_t *
9303 __mmplayer_create_stream_from_pad(GstPad *pad)
9305 GstCaps *caps = NULL;
9306 GstStructure *structure = NULL;
9307 unsigned int fourcc = 0;
9308 const gchar *string_format = NULL;
9309 mmplayer_video_decoded_data_info_t *stream = NULL;
9311 MMPixelFormatType format;
9314 caps = gst_pad_get_current_caps(pad);
9316 LOGE("Caps is NULL.");
9321 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9323 structure = gst_caps_get_structure(caps, 0);
9324 gst_structure_get_int(structure, "width", &width);
9325 gst_structure_get_int(structure, "height", &height);
9326 string_format = gst_structure_get_string(structure, "format");
9329 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9330 format = _mmplayer_get_pixtype(fourcc);
9331 gst_video_info_from_caps(&info, caps);
9332 gst_caps_unref(caps);
9335 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9336 LOGE("Wrong condition!!");
9340 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9342 LOGE("failed to alloc mem for video data");
9346 stream->width = width;
9347 stream->height = height;
9348 stream->format = format;
9349 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9355 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9357 unsigned int pitch = 0;
9358 unsigned int size = 0;
9360 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9363 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9364 bo = gst_tizen_memory_get_bos(mem, index);
9366 stream->bo[index] = tbm_bo_ref(bo);
9368 LOGE("failed to get bo for index %d", index);
9371 for (index = 0; index < stream->plane_num; index++) {
9372 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9373 stream->stride[index] = pitch;
9375 stream->elevation[index] = size / pitch;
9377 stream->elevation[index] = stream->height;
9382 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9384 if (stream->format == MM_PIXEL_FORMAT_I420) {
9385 int ret = TBM_SURFACE_ERROR_NONE;
9386 tbm_surface_h surface;
9387 tbm_surface_info_s info;
9389 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9391 ret = tbm_surface_get_info(surface, &info);
9392 if (ret != TBM_SURFACE_ERROR_NONE) {
9393 tbm_surface_destroy(surface);
9397 tbm_surface_destroy(surface);
9398 stream->stride[0] = info.planes[0].stride;
9399 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9400 stream->stride[1] = info.planes[1].stride;
9401 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9402 stream->stride[2] = info.planes[2].stride;
9403 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9404 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9405 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9406 stream->stride[0] = stream->width * 4;
9407 stream->elevation[0] = stream->height;
9408 stream->bo_size = stream->stride[0] * stream->height;
9410 LOGE("Not support format %d", stream->format);
9418 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9420 tbm_bo_handle thandle;
9422 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9423 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9424 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9428 unsigned char *src = NULL;
9429 unsigned char *dest = NULL;
9430 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9432 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9434 LOGE("fail to gst_memory_map");
9438 if (!mapinfo.data) {
9439 LOGE("data pointer is wrong");
9443 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9444 if (!stream->bo[0]) {
9445 LOGE("Fail to tbm_bo_alloc!!");
9449 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9451 LOGE("thandle pointer is wrong");
9455 if (stream->format == MM_PIXEL_FORMAT_I420) {
9456 src_stride[0] = GST_ROUND_UP_4(stream->width);
9457 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9458 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9459 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9462 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9463 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9465 for (i = 0; i < 3; i++) {
9466 src = mapinfo.data + src_offset[i];
9467 dest = thandle.ptr + dest_offset[i];
9472 for (j = 0; j < stream->height >> k; j++) {
9473 memcpy(dest, src, stream->width>>k);
9474 src += src_stride[i];
9475 dest += stream->stride[i];
9478 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9479 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9481 LOGE("Not support format %d", stream->format);
9485 tbm_bo_unmap(stream->bo[0]);
9486 gst_memory_unmap(mem, &mapinfo);
9492 tbm_bo_unmap(stream->bo[0]);
9495 gst_memory_unmap(mem, &mapinfo);
9501 __mmplayer_set_pause_state(mmplayer_t *player)
9503 if (player->sent_bos)
9506 /* rtsp case, get content attrs by GstMessage */
9507 if (MMPLAYER_IS_RTSP_STREAMING(player))
9510 /* it's first time to update all content attrs. */
9511 _mmplayer_update_content_attrs(player, ATTR_ALL);
9515 __mmplayer_set_playing_state(mmplayer_t *player)
9517 gchar *audio_codec = NULL;
9519 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9520 /* initialize because auto resume is done well. */
9521 player->resumed_by_rewind = FALSE;
9522 player->playback_rate = 1.0;
9525 if (player->sent_bos)
9528 /* try to get content metadata */
9530 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9531 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9532 * legacy mmfw-player api
9534 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9536 if ((player->cmd == MMPLAYER_COMMAND_START)
9537 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9538 __mmplayer_handle_missed_plugin(player);
9541 /* check audio codec field is set or not
9542 * we can get it from typefinder or codec's caps.
9544 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9546 /* The codec format can't be sent for audio only case like amr, mid etc.
9547 * Because, parser don't make related TAG.
9548 * So, if it's not set yet, fill it with found data.
9551 if (g_strrstr(player->type, "audio/midi"))
9552 audio_codec = "MIDI";
9553 else if (g_strrstr(player->type, "audio/x-amr"))
9554 audio_codec = "AMR";
9555 else if (g_strrstr(player->type, "audio/mpeg")
9556 && !g_strrstr(player->type, "mpegversion=(int)1"))
9557 audio_codec = "AAC";
9559 audio_codec = "unknown";
9561 if (mm_player_set_attribute((MMHandleType)player, NULL,
9562 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9563 LOGE("failed to set attribute");
9565 LOGD("set audio codec type with caps");