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_decode_no_more_pads(GstElement *elem, gpointer data);
145 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
146 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
147 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
151 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
152 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
153 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
155 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_release_misc(mmplayer_t *player);
157 static void __mmplayer_release_misc_post(mmplayer_t *player);
158 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
159 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
160 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
162 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
164 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
165 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
166 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
167 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
168 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
170 static gpointer __mmplayer_gapless_play_thread(gpointer data);
171 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
172 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
173 static void __mmplayer_release_dump_list(GList *dump_list);
174 static int __mmplayer_gst_realize(mmplayer_t *player);
175 static int __mmplayer_gst_unrealize(mmplayer_t *player);
176 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
177 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
180 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
181 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
182 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
183 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
184 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
185 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
186 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
187 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
188 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
189 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
190 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
194 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
195 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
196 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
198 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
199 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
200 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
201 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
203 static void __mmplayer_set_pause_state(mmplayer_t *player);
204 static void __mmplayer_set_playing_state(mmplayer_t *player);
205 /*===========================================================================================
207 | FUNCTION DEFINITIONS |
209 ========================================================================================== */
211 /* This function should be called after the pipeline goes PAUSED or higher
214 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
216 static gboolean has_duration = FALSE;
217 static gboolean has_video_attrs = FALSE;
218 static gboolean has_audio_attrs = FALSE;
219 static gboolean has_bitrate = FALSE;
220 gboolean missing_only = FALSE;
221 gboolean all = FALSE;
222 MMHandleType attrs = 0;
226 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
228 /* check player state here */
229 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
230 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
231 /* give warning now only */
232 LOGW("be careful. content attributes may not available in this state ");
235 /* get content attribute first */
236 attrs = MMPLAYER_GET_ATTRS(player);
238 LOGE("cannot get content attribute");
242 /* get update flag */
244 if (flag & ATTR_MISSING_ONLY) {
246 LOGD("updating missed attr only");
249 if (flag & ATTR_ALL) {
251 has_duration = FALSE;
252 has_video_attrs = FALSE;
253 has_audio_attrs = FALSE;
256 LOGD("updating all attrs");
259 if (missing_only && all) {
260 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
261 missing_only = FALSE;
264 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
265 has_duration = __mmplayer_update_duration_value(player);
267 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
268 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
270 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
271 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
273 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
274 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
282 _mmplayer_get_stream_service_type(mmplayer_t *player)
284 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
288 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
290 player->pipeline->mainbin &&
291 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
292 STREAMING_SERVICE_NONE);
294 /* streaming service type if streaming */
295 if (!MMPLAYER_IS_STREAMING(player))
296 return STREAMING_SERVICE_NONE;
298 streaming_type = (player->duration == 0) ?
299 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
301 switch (streaming_type) {
302 case STREAMING_SERVICE_LIVE:
303 LOGD("it's live streaming");
305 case STREAMING_SERVICE_VOD:
306 LOGD("it's vod streaming");
309 LOGE("should not get here");
315 return streaming_type;
318 /* this function sets the player state and also report
319 * it to applicaton by calling callback function
322 _mmplayer_set_state(mmplayer_t *player, int state)
324 MMMessageParamType msg = {0, };
326 MMPLAYER_RETURN_IF_FAIL(player);
328 if (MMPLAYER_CURRENT_STATE(player) == state) {
329 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
330 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
334 /* update player states */
335 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
336 MMPLAYER_CURRENT_STATE(player) = state;
338 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
339 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
342 MMPLAYER_PRINT_STATE(player);
344 switch (MMPLAYER_CURRENT_STATE(player)) {
345 case MM_PLAYER_STATE_NULL:
346 case MM_PLAYER_STATE_READY:
348 case MM_PLAYER_STATE_PAUSED:
349 __mmplayer_set_pause_state(player);
351 case MM_PLAYER_STATE_PLAYING:
352 __mmplayer_set_playing_state(player);
354 case MM_PLAYER_STATE_NONE:
356 LOGW("invalid target state, there is nothing to do.");
361 /* post message to application */
362 if (MMPLAYER_TARGET_STATE(player) == state) {
363 /* fill the message with state of player */
364 msg.union_type = MM_MSG_UNION_STATE;
365 msg.state.previous = MMPLAYER_PREV_STATE(player);
366 msg.state.current = MMPLAYER_CURRENT_STATE(player);
368 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
370 /* state changed by resource callback */
371 if (player->interrupted_by_resource)
372 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
373 else /* state changed by usecase */
374 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
377 LOGD("intermediate state, do nothing.");
378 MMPLAYER_PRINT_STATE(player);
382 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
383 && !player->sent_bos) {
384 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
385 player->sent_bos = TRUE;
392 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
394 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
395 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
399 LOGD("incomming command : %d ", command);
401 current_state = MMPLAYER_CURRENT_STATE(player);
402 pending_state = MMPLAYER_PENDING_STATE(player);
404 MMPLAYER_PRINT_STATE(player);
407 case MMPLAYER_COMMAND_CREATE:
409 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
411 if (current_state == MM_PLAYER_STATE_NULL ||
412 current_state == MM_PLAYER_STATE_READY ||
413 current_state == MM_PLAYER_STATE_PAUSED ||
414 current_state == MM_PLAYER_STATE_PLAYING)
419 case MMPLAYER_COMMAND_DESTROY:
421 /* destroy can called anytime */
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
427 case MMPLAYER_COMMAND_REALIZE:
429 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
431 if (pending_state != MM_PLAYER_STATE_NONE) {
434 /* need ready state to realize */
435 if (current_state == MM_PLAYER_STATE_READY)
438 if (current_state != MM_PLAYER_STATE_NULL)
444 case MMPLAYER_COMMAND_UNREALIZE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL)
453 case MMPLAYER_COMMAND_START:
455 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
457 if (pending_state == MM_PLAYER_STATE_NONE) {
458 if (current_state == MM_PLAYER_STATE_PLAYING)
460 else if (current_state != MM_PLAYER_STATE_READY &&
461 current_state != MM_PLAYER_STATE_PAUSED)
463 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
465 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
466 LOGD("player is going to paused state, just change the pending state as playing");
473 case MMPLAYER_COMMAND_STOP:
475 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
477 if (current_state == MM_PLAYER_STATE_READY)
480 /* need playing/paused state to stop */
481 if (current_state != MM_PLAYER_STATE_PLAYING &&
482 current_state != MM_PLAYER_STATE_PAUSED)
487 case MMPLAYER_COMMAND_PAUSE:
489 if (MMPLAYER_IS_LIVE_STREAMING(player))
492 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
493 goto NOT_COMPLETED_SEEK;
495 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
497 if (pending_state == MM_PLAYER_STATE_NONE) {
498 if (current_state == MM_PLAYER_STATE_PAUSED)
500 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
504 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
505 if (current_state == MM_PLAYER_STATE_PAUSED)
506 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
513 case MMPLAYER_COMMAND_RESUME:
515 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
516 goto NOT_COMPLETED_SEEK;
518 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
520 if (pending_state == MM_PLAYER_STATE_NONE) {
521 if (current_state == MM_PLAYER_STATE_PLAYING)
523 else if (current_state != MM_PLAYER_STATE_PAUSED)
525 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
527 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
528 LOGD("player is going to paused state, just change the pending state as playing");
538 player->cmd = command;
540 return MM_ERROR_NONE;
543 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
544 MMPLAYER_STATE_GET_NAME(current_state), command);
545 return MM_ERROR_PLAYER_INVALID_STATE;
548 LOGW("not completed seek");
549 return MM_ERROR_PLAYER_DOING_SEEK;
552 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
553 return MM_ERROR_PLAYER_NO_OP;
556 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
557 return MM_ERROR_PLAYER_NO_OP;
560 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
562 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
563 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
566 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
569 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
570 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
572 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
573 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
576 LOGE("invalid mmplayer resource type %d", type);
577 return MM_ERROR_PLAYER_INTERNAL;
580 if (player->hw_resource[type] != NULL) {
581 LOGD("[%d type] resource was already acquired", type);
582 return MM_ERROR_NONE;
585 LOGD("mark for acquire [%d type] resource", type);
586 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
587 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
593 rm_ret = mm_resource_manager_commit(player->resource_manager);
594 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
595 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
596 return MM_ERROR_PLAYER_INTERNAL;
600 return MM_ERROR_NONE;
603 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
605 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
609 if (player->hw_resource[type] == NULL) {
610 LOGD("there is no acquired [%d type] resource", type);
611 return MM_ERROR_NONE;
614 LOGD("mark for release [%d type] resource", type);
615 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
616 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
617 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
618 return MM_ERROR_PLAYER_INTERNAL;
621 player->hw_resource[type] = NULL;
623 rm_ret = mm_resource_manager_commit(player->resource_manager);
624 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
625 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
626 return MM_ERROR_PLAYER_INTERNAL;
630 return MM_ERROR_NONE;
634 __mmplayer_initialize_gapless_play(mmplayer_t *player)
640 player->smooth_streaming = FALSE;
641 player->videodec_linked = 0;
642 player->audiodec_linked = 0;
643 player->textsink_linked = 0;
644 player->is_external_subtitle_present = FALSE;
645 player->is_external_subtitle_added_now = FALSE;
646 player->not_supported_codec = MISSING_PLUGIN_NONE;
647 player->can_support_codec = FOUND_PLUGIN_NONE;
648 player->pending_seek.is_pending = false;
649 player->pending_seek.pos = 0;
650 player->msg_posted = FALSE;
651 player->has_many_types = FALSE;
652 player->no_more_pad = FALSE;
653 player->not_found_demuxer = 0;
654 player->seek_state = MMPLAYER_SEEK_NONE;
655 player->is_subtitle_force_drop = FALSE;
656 player->play_subtitle = FALSE;
657 player->adjust_subtitle_pos = 0;
659 player->total_bitrate = 0;
660 player->total_maximum_bitrate = 0;
662 _mmplayer_track_initialize(player);
663 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
665 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
666 player->bitrate[i] = 0;
667 player->maximum_bitrate[i] = 0;
670 if (player->v_stream_caps) {
671 gst_caps_unref(player->v_stream_caps);
672 player->v_stream_caps = NULL;
675 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
677 /* clean found audio decoders */
678 if (player->audio_decoders) {
679 GList *a_dec = player->audio_decoders;
680 for (; a_dec; a_dec = g_list_next(a_dec)) {
681 gchar *name = a_dec->data;
682 MMPLAYER_FREEIF(name);
684 g_list_free(player->audio_decoders);
685 player->audio_decoders = NULL;
688 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
693 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
695 LOGI("set pipeline reconfigure state %d", state);
696 MMPLAYER_RECONFIGURE_LOCK(player);
697 player->gapless.reconfigure = state;
698 if (!state) /* wake up the waiting job */
699 MMPLAYER_RECONFIGURE_SIGNAL(player);
700 MMPLAYER_RECONFIGURE_UNLOCK(player);
704 __mmplayer_gapless_play_thread(gpointer data)
706 mmplayer_t *player = (mmplayer_t *)data;
707 mmplayer_gst_element_t *mainbin = NULL;
709 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
711 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
712 while (!player->gapless_play_thread_exit) {
713 LOGD("gapless play thread started. waiting for signal.");
714 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
716 LOGD("reconfigure pipeline for gapless play.");
718 if (player->gapless_play_thread_exit) {
719 _mmplayer_set_reconfigure_state(player, FALSE);
720 LOGD("exiting gapless play thread");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 /* Initialize Player values */
733 __mmplayer_initialize_gapless_play(player);
735 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
745 GSource *source = NULL;
749 source = g_main_context_find_source_by_id(context, source_id);
750 if (source != NULL) {
751 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
752 g_source_destroy(source);
759 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
762 GstMessage *msg = NULL;
763 GQueue *queue = NULL;
766 MMPLAYER_RETURN_IF_FAIL(player);
768 /* disconnecting bus watch */
769 if (player->bus_watcher)
770 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
771 player->bus_watcher = 0;
773 /* destroy the gst bus msg thread */
774 if (player->bus_msg_thread) {
775 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
776 player->bus_msg_thread_exit = TRUE;
777 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
778 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
780 LOGD("gst bus msg thread exit.");
781 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
782 player->bus_msg_thread = NULL;
784 g_mutex_clear(&player->bus_msg_thread_mutex);
785 g_cond_clear(&player->bus_msg_thread_cond);
788 g_mutex_lock(&player->bus_msg_q_lock);
789 queue = player->bus_msg_q;
790 while (!g_queue_is_empty(queue)) {
791 msg = (GstMessage *)g_queue_pop_head(queue);
796 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
797 gst_message_unref(msg);
799 g_mutex_unlock(&player->bus_msg_q_lock);
805 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
807 GstElement *parent = NULL;
809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
810 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
813 MMPLAYER_FSINK_LOCK(player);
815 /* get parent of fakesink */
816 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
818 LOGD("fakesink already removed");
822 gst_element_set_locked_state(fakesink->gst, TRUE);
824 /* setting the state to NULL never returns async
825 * so no need to wait for completion of state transiton
827 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
828 LOGE("fakesink state change failure!");
829 /* FIXIT : should I return here? or try to proceed to next? */
832 /* remove fakesink from it's parent */
833 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
834 LOGE("failed to remove fakesink");
836 gst_object_unref(parent);
841 gst_object_unref(parent);
843 LOGD("state-holder removed");
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
852 gst_element_set_locked_state(fakesink->gst, FALSE);
854 MMPLAYER_FSINK_UNLOCK(player);
858 static GstPadProbeReturn
859 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
861 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
862 return GST_PAD_PROBE_OK;
866 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
868 gint64 stop_running_time = 0;
869 gint64 position_running_time = 0;
873 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
874 if ((player->gapless.update_segment[idx] == TRUE) ||
875 !(player->selector[idx].event_probe_id)) {
877 LOGW("[%d] skip", idx);
882 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
884 gst_segment_to_running_time(&player->gapless.segment[idx],
885 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
886 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
888 gst_segment_to_running_time(&player->gapless.segment[idx],
889 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
891 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
893 gst_segment_to_running_time(&player->gapless.segment[idx],
894 GST_FORMAT_TIME, player->duration);
897 position_running_time =
898 gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].position);
901 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
902 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
904 GST_TIME_ARGS(stop_running_time),
905 GST_TIME_ARGS(position_running_time),
906 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
907 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
909 position_running_time = MAX(position_running_time, stop_running_time);
910 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].start);
912 position_running_time = MAX(0, position_running_time);
913 position = MAX(position, position_running_time);
917 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
918 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
919 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
921 player->gapless.start_time[stream_type] += position;
927 static GstPadProbeReturn
928 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
930 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
931 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
932 mmplayer_t *player = (mmplayer_t *)data;
933 GstCaps *caps = NULL;
934 GstStructure *str = NULL;
935 const gchar *name = NULL;
936 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
937 gboolean caps_ret = TRUE;
939 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
940 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
941 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
942 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
943 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
946 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
950 if (strstr(name, "audio")) {
951 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
952 } else if (strstr(name, "video")) {
953 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
955 /* text track is not supportable */
956 LOGE("invalid name %s", name);
960 switch (GST_EVENT_TYPE(event)) {
963 /* in case of gapless, drop eos event not to send it to sink */
964 if (player->gapless.reconfigure && !player->msg_posted) {
965 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
966 ret = GST_PAD_PROBE_DROP;
970 case GST_EVENT_STREAM_START:
972 __mmplayer_gst_selector_update_start_time(player, stream_type);
975 case GST_EVENT_FLUSH_STOP:
977 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
978 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
979 player->gapless.start_time[stream_type] = 0;
982 case GST_EVENT_SEGMENT:
987 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
988 gst_event_copy_segment(event, &segment);
990 if (segment.format != GST_FORMAT_TIME)
993 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
994 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
995 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
996 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
997 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
998 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1000 /* keep the all the segment ev to cover the seeking */
1001 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1002 player->gapless.update_segment[stream_type] = TRUE;
1004 if (!player->gapless.running)
1007 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1009 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1011 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1012 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1013 gst_event_unref(event);
1014 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1020 gdouble proportion = 0.0;
1021 GstClockTimeDiff diff = 0;
1022 GstClockTime timestamp = 0;
1023 gint64 running_time_diff = -1;
1024 GstQOSType type = 0;
1025 GstEvent *tmpev = NULL;
1027 running_time_diff = player->gapless.segment[stream_type].base;
1029 if (running_time_diff <= 0) /* don't need to adjust */
1032 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1033 gst_event_unref(event);
1035 if (timestamp < running_time_diff) {
1036 LOGW("QOS event from previous group");
1037 ret = GST_PAD_PROBE_DROP;
1042 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1043 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1044 stream_type, GST_TIME_ARGS(timestamp),
1045 GST_TIME_ARGS(running_time_diff),
1046 GST_TIME_ARGS(timestamp - running_time_diff));
1049 timestamp -= running_time_diff;
1051 /* That case is invalid for QoS events */
1052 if (diff < 0 && -diff > timestamp) {
1053 LOGW("QOS event from previous group");
1054 ret = GST_PAD_PROBE_DROP;
1058 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1059 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1069 gst_caps_unref(caps);
1073 /* create fakesink for audio or video path witout audiobin or videobin */
1075 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1077 GstElement *pipeline = NULL;
1078 GstElement *fakesink = NULL;
1079 GstPad *sinkpad = NULL;
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1087 fakesink = gst_element_factory_make("fakesink", NULL);
1088 if (fakesink == NULL) {
1089 LOGE("failed to create fakesink");
1093 /* store it as it's sink element */
1094 __mmplayer_add_sink(player, fakesink);
1096 gst_bin_add(GST_BIN(pipeline), fakesink);
1099 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1101 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1103 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1104 LOGE("failed to link fakesink");
1105 gst_object_unref(GST_OBJECT(fakesink));
1109 if (strstr(name, "video")) {
1110 if (player->v_stream_caps) {
1111 gst_caps_unref(player->v_stream_caps);
1112 player->v_stream_caps = NULL;
1114 if (player->ini.set_dump_element_flag)
1115 __mmplayer_add_dump_buffer_probe(player, fakesink);
1118 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1119 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1123 gst_object_unref(GST_OBJECT(sinkpad));
1130 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1132 GstElement *pipeline = NULL;
1133 GstElement *selector = NULL;
1134 GstPad *srcpad = NULL;
1137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1139 selector = gst_element_factory_make("input-selector", NULL);
1141 LOGE("failed to create input-selector");
1144 g_object_set(selector, "sync-streams", TRUE, NULL);
1146 player->pipeline->mainbin[elem_idx].id = elem_idx;
1147 player->pipeline->mainbin[elem_idx].gst = selector;
1149 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1151 srcpad = gst_element_get_static_pad(selector, "src");
1153 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1154 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1155 __mmplayer_gst_selector_blocked, NULL, NULL);
1156 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1157 __mmplayer_gst_selector_event_probe, player, NULL);
1159 gst_element_set_state(selector, GST_STATE_PAUSED);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1162 gst_bin_add(GST_BIN(pipeline), selector);
1164 gst_object_unref(GST_OBJECT(srcpad));
1171 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1173 mmplayer_t *player = (mmplayer_t *)data;
1174 GstElement *selector = NULL;
1175 GstCaps *caps = NULL;
1176 GstStructure *str = NULL;
1177 const gchar *name = NULL;
1178 GstPad *sinkpad = NULL;
1179 gboolean first_track = FALSE;
1181 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1182 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1185 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1186 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1188 LOGD("pad-added signal handling");
1190 /* get mimetype from caps */
1191 caps = gst_pad_get_current_caps(pad);
1193 str = gst_caps_get_structure(caps, 0);
1195 name = gst_structure_get_name(str);
1200 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1202 LOGD("detected mimetype : %s", name);
1205 if (strstr(name, "video")) {
1207 gchar *caps_str = NULL;
1209 caps_str = gst_caps_to_string(caps);
1210 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1211 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1212 player->set_mode.video_zc = true;
1214 MMPLAYER_FREEIF(caps_str);
1216 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1217 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1219 LOGD("surface type : %d", stype);
1221 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1222 __mmplayer_gst_create_sinkbin(elem, pad, player);
1226 /* in case of exporting video frame, it requires the 360 video filter.
1227 * it will be handled in _no_more_pads(). */
1228 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1229 __mmplayer_gst_make_fakesink(player, pad, name);
1233 LOGD("video selector is required");
1234 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1235 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1236 } else if (strstr(name, "audio")) {
1237 gint samplerate = 0;
1240 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1241 if (player->build_audio_offload)
1242 player->no_more_pad = TRUE; /* remove state holder */
1243 __mmplayer_gst_create_sinkbin(elem, pad, player);
1247 gst_structure_get_int(str, "rate", &samplerate);
1248 gst_structure_get_int(str, "channels", &channels);
1250 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1251 __mmplayer_gst_make_fakesink(player, pad, name);
1255 LOGD("audio selector is required");
1256 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1257 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1259 } else if (strstr(name, "text")) {
1260 LOGD("text selector is required");
1261 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1262 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1264 LOGE("invalid caps info");
1268 /* check selector and create it */
1269 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1270 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1275 LOGD("input-selector is already created.");
1279 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1281 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1283 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1284 LOGE("failed to link selector");
1285 gst_object_unref(GST_OBJECT(selector));
1290 LOGD("this track will be activated");
1291 g_object_set(selector, "active-pad", sinkpad, NULL);
1294 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1300 gst_caps_unref(caps);
1303 gst_object_unref(GST_OBJECT(sinkpad));
1311 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1313 GstPad *srcpad = NULL;
1316 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1318 LOGD("type %d", type);
1321 LOGD("there is no %d track", type);
1325 srcpad = gst_element_get_static_pad(selector, "src");
1327 LOGE("failed to get srcpad from selector");
1331 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1333 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1335 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1336 if (player->selector[type].block_id) {
1337 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1338 player->selector[type].block_id = 0;
1342 gst_object_unref(GST_OBJECT(srcpad));
1351 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1353 gint active_index = 0;
1356 MMPLAYER_RETURN_IF_FAIL(player);
1358 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1360 /* change track to active pad */
1361 active_index = player->selector[type].active_pad_index;
1362 if ((active_index != DEFAULT_TRACK) &&
1363 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1364 LOGW("failed to change %d type track to %d", type, active_index);
1365 player->selector[type].active_pad_index = DEFAULT_TRACK;
1369 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1370 mm_player_set_attribute((MMHandleType)player, NULL,
1371 "content_text_track_num", player->selector[type].total_track_num,
1372 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1379 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1382 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1384 if (!audio_selector) {
1385 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1387 /* in case the source is changed, output can be changed. */
1388 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1389 LOGD("remove previous audiobin if it exist");
1391 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1392 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1394 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1395 MMPLAYER_FREEIF(player->pipeline->audiobin);
1398 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1399 __mmplayer_pipeline_complete(NULL, player);
1404 /* apply the audio track information */
1405 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1407 /* create audio sink path */
1408 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1409 LOGE("failed to create audio sink path");
1418 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1421 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1423 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1424 LOGD("text path is not supproted");
1428 /* apply the text track information */
1429 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1431 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1432 player->has_closed_caption = TRUE;
1434 /* create text decode path */
1435 player->no_more_pad = TRUE;
1437 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1438 LOGE("failed to create text sink path");
1447 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1449 gint64 dur_bytes = 0L;
1452 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1453 player->pipeline->mainbin && player->streamer, FALSE);
1455 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1456 LOGE("fail to get duration.");
1458 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1459 * use file information was already set on Q2 when it was created. */
1460 _mm_player_streaming_set_queue2(player->streamer,
1461 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1462 TRUE, /* use_buffering */
1463 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1464 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1471 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1473 mmplayer_t *player = NULL;
1474 GstElement *video_selector = NULL;
1475 GstElement *audio_selector = NULL;
1476 GstElement *text_selector = NULL;
1479 player = (mmplayer_t *)data;
1481 LOGD("no-more-pad signal handling");
1483 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1484 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1485 LOGW("player is shutting down");
1489 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1490 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1491 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1492 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1493 LOGE("failed to set queue2 buffering");
1498 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1499 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1500 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1502 if (!video_selector && !audio_selector && !text_selector) {
1503 LOGW("there is no selector");
1504 player->no_more_pad = TRUE;
1508 /* create video path followed by video-select */
1509 if (video_selector && !audio_selector && !text_selector)
1510 player->no_more_pad = TRUE;
1512 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1515 /* create audio path followed by audio-select */
1516 if (audio_selector && !text_selector)
1517 player->no_more_pad = TRUE;
1519 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1522 /* create text path followed by text-select */
1523 __mmplayer_create_text_sink_path(player, text_selector);
1526 _mmplayer_set_reconfigure_state(player, FALSE);
1531 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1533 gboolean ret = FALSE;
1534 GstElement *pipeline = NULL;
1535 GstPad *sinkpad = NULL;
1538 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1539 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1541 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1543 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1545 LOGE("failed to get pad from sinkbin");
1551 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1552 LOGE("failed to link sinkbin for reusing");
1553 goto EXIT; /* exit either pass or fail */
1557 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1558 LOGE("failed to set state(READY) to sinkbin");
1563 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1564 LOGE("failed to add sinkbin to pipeline");
1569 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1570 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1575 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1576 LOGE("failed to set state(PAUSED) to sinkbin");
1585 gst_object_unref(GST_OBJECT(sinkpad));
1593 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1595 mmplayer_t *player = NULL;
1596 GstCaps *caps = NULL;
1597 gchar *caps_str = NULL;
1598 GstStructure *str = NULL;
1599 const gchar *name = NULL;
1600 GstElement *sinkbin = NULL;
1601 gboolean reusing = FALSE;
1602 gboolean caps_ret = TRUE;
1603 gchar *sink_pad_name = "sink";
1606 player = (mmplayer_t *)data;
1609 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1610 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1612 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1616 caps_str = gst_caps_to_string(caps);
1618 LOGD("detected mimetype : %s", name);
1620 if (strstr(name, "audio")) {
1621 if (player->pipeline->audiobin == NULL) {
1622 const gchar *audio_format = gst_structure_get_string(str, "format");
1624 LOGD("original audio format %s", audio_format);
1625 mm_player_set_attribute((MMHandleType)player, NULL,
1626 "content_audio_format", audio_format, strlen(audio_format), NULL);
1629 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1630 LOGE("failed to create audiobin. continuing without audio");
1634 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1635 LOGD("creating audiobin success");
1638 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1639 LOGD("reusing audiobin");
1640 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1642 } else if (strstr(name, "video")) {
1643 /* 1. zero copy is updated at _decode_pad_added()
1644 * 2. NULL surface type is handled in _decode_pad_added() */
1645 LOGD("zero copy %d", player->set_mode.video_zc);
1646 if (player->pipeline->videobin == NULL) {
1647 int surface_type = 0;
1648 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1649 LOGD("display_surface_type (%d)", surface_type);
1651 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1652 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1653 LOGE("failed to acquire video overlay resource");
1657 player->interrupted_by_resource = FALSE;
1659 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1660 LOGE("failed to create videobin. continuing without video");
1664 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1665 LOGD("creating videosink bin success");
1668 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1669 LOGD("re-using videobin");
1670 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1672 } else if (strstr(name, "text")) {
1673 if (player->pipeline->textbin == NULL) {
1674 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1675 LOGE("failed to create text sink bin. continuing without text");
1679 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1680 player->textsink_linked = 1;
1681 LOGD("creating textsink bin success");
1683 if (!player->textsink_linked) {
1684 LOGD("re-using textbin");
1686 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1687 player->textsink_linked = 1;
1689 /* linked textbin exist which means that the external subtitle path exist already */
1690 LOGW("ignoring internal subtutle since external subtitle is available");
1693 sink_pad_name = "text_sink";
1695 LOGW("unknown mime type %s, ignoring it", name);
1699 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1702 LOGD("[handle: %p] success to create and link sink bin", player);
1704 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1705 * streaming task. if the task blocked, then buffer will not flow to the next element
1706 *(autoplugging element). so this is special hack for streaming. please try to remove it
1708 /* dec stream count. we can remove fakesink if it's zero */
1709 if (player->num_dynamic_pad)
1710 player->num_dynamic_pad--;
1712 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1714 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1715 __mmplayer_pipeline_complete(NULL, player);
1719 MMPLAYER_FREEIF(caps_str);
1722 gst_caps_unref(caps);
1728 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1730 int required_angle = 0; /* Angle required for straight view */
1731 int rotation_angle = 0;
1733 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1734 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1736 /* Counter clockwise */
1737 switch (orientation) {
1742 required_angle = 270;
1745 required_angle = 180;
1748 required_angle = 90;
1752 rotation_angle = display_angle + required_angle;
1753 if (rotation_angle >= 360)
1754 rotation_angle -= 360;
1756 /* chech if supported or not */
1757 if (rotation_angle % 90) {
1758 LOGD("not supported rotation angle = %d", rotation_angle);
1762 switch (rotation_angle) {
1764 *value = MM_DISPLAY_ROTATION_NONE;
1767 *value = MM_DISPLAY_ROTATION_90;
1770 *value = MM_DISPLAY_ROTATION_180;
1773 *value = MM_DISPLAY_ROTATION_270;
1777 LOGD("setting rotation property value : %d", *value);
1783 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1785 int display_rotation = 0;
1786 gchar *org_orient = NULL;
1787 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1790 LOGE("cannot get content attribute");
1791 return MM_ERROR_PLAYER_INTERNAL;
1794 if (display_angle) {
1795 /* update user roation */
1796 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1798 /* Counter clockwise */
1799 switch (display_rotation) {
1800 case MM_DISPLAY_ROTATION_NONE:
1803 case MM_DISPLAY_ROTATION_90:
1804 *display_angle = 90;
1806 case MM_DISPLAY_ROTATION_180:
1807 *display_angle = 180;
1809 case MM_DISPLAY_ROTATION_270:
1810 *display_angle = 270;
1813 LOGW("wrong angle type : %d", display_rotation);
1816 LOGD("check user angle: %d", *display_angle);
1820 /* Counter clockwise */
1821 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1824 if (!strcmp(org_orient, "rotate-90"))
1826 else if (!strcmp(org_orient, "rotate-180"))
1828 else if (!strcmp(org_orient, "rotate-270"))
1831 LOGD("original rotation is %s", org_orient);
1833 LOGD("content_video_orientation get fail");
1836 LOGD("check orientation: %d", *orientation);
1839 return MM_ERROR_NONE;
1842 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1844 int rotation_value = 0;
1845 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1846 int display_angle = 0;
1849 /* check video sinkbin is created */
1850 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1853 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1855 /* get rotation value to set */
1856 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1857 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1858 LOGD("set video param : rotate %d", rotation_value);
1861 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1863 MMHandleType attrs = 0;
1867 /* check video sinkbin is created */
1868 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1871 attrs = MMPLAYER_GET_ATTRS(player);
1872 MMPLAYER_RETURN_IF_FAIL(attrs);
1874 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1875 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1876 LOGD("set video param : visible %d", visible);
1879 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1881 MMHandleType attrs = 0;
1882 int display_method = 0;
1885 /* check video sinkbin is created */
1886 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1889 attrs = MMPLAYER_GET_ATTRS(player);
1890 MMPLAYER_RETURN_IF_FAIL(attrs);
1892 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1893 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1894 LOGD("set video param : method %d", display_method);
1897 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1899 MMHandleType attrs = 0;
1903 /* check video sinkbin is created */
1904 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1907 attrs = MMPLAYER_GET_ATTRS(player);
1908 MMPLAYER_RETURN_IF_FAIL(attrs);
1910 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1911 MMPLAYER_RETURN_IF_FAIL(handle);
1913 gst_video_overlay_set_video_roi_area(
1914 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1915 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1916 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1917 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1920 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1922 MMHandleType attrs = 0;
1927 int win_roi_width = 0;
1928 int win_roi_height = 0;
1931 /* check video sinkbin is created */
1932 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1935 attrs = MMPLAYER_GET_ATTRS(player);
1936 MMPLAYER_RETURN_IF_FAIL(attrs);
1938 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1939 MMPLAYER_RETURN_IF_FAIL(handle);
1941 /* It should be set after setting window */
1942 mm_attrs_multiple_get(attrs, NULL,
1943 "display_win_roi_x", &win_roi_x,
1944 "display_win_roi_y", &win_roi_y,
1945 "display_win_roi_width", &win_roi_width,
1946 "display_win_roi_height", &win_roi_height, NULL);
1948 /* After setting window handle, set display roi area */
1949 gst_video_overlay_set_display_roi_area(
1950 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1951 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1952 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1953 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1956 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1958 MMHandleType attrs = 0;
1961 /* check video sinkbin is created */
1962 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1965 attrs = MMPLAYER_GET_ATTRS(player);
1966 MMPLAYER_RETURN_IF_FAIL(attrs);
1968 /* common case if using overlay surface */
1969 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1970 MMPLAYER_RETURN_IF_FAIL(handle);
1972 /* default is using wl_surface_id */
1973 LOGD("set video param : wl_surface_id %d", handle);
1974 gst_video_overlay_set_wl_window_wl_surface_id(
1975 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1980 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1982 gboolean update_all_param = FALSE;
1986 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1987 LOGW("videosink is not ready yet");
1988 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1991 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1992 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1993 return MM_ERROR_PLAYER_INTERNAL;
1996 LOGD("param_name : %s", param_name);
1997 if (!g_strcmp0(param_name, "update_all_param"))
1998 update_all_param = TRUE;
2000 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2001 __mmplayer_video_param_set_display_overlay(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2003 __mmplayer_video_param_set_display_method(player);
2004 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2005 __mmplayer_video_param_set_display_visible(player);
2006 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2007 __mmplayer_video_param_set_display_rotation(player);
2008 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2009 __mmplayer_video_param_set_roi_area(player);
2010 if (update_all_param)
2011 __mmplayer_video_param_set_video_roi_area(player);
2015 return MM_ERROR_NONE;
2019 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2021 gboolean disable_overlay = FALSE;
2022 mmplayer_t *player = (mmplayer_t *)hplayer;
2025 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2026 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2027 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2028 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2030 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2031 LOGW("Display control is not supported");
2032 return MM_ERROR_PLAYER_INTERNAL;
2035 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2037 if (audio_only == (bool)disable_overlay) {
2038 LOGE("It's the same with current setting: (%d)", audio_only);
2039 return MM_ERROR_NONE;
2043 LOGE("disable overlay");
2044 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2046 /* release overlay resource */
2047 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2048 LOGE("failed to release overlay resource");
2052 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2053 LOGE("failed to acquire video overlay resource");
2056 player->interrupted_by_resource = FALSE;
2058 LOGD("enable overlay");
2059 __mmplayer_video_param_set_display_overlay(player);
2060 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2065 return MM_ERROR_NONE;
2069 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2071 mmplayer_t *player = (mmplayer_t *)hplayer;
2072 gboolean disable_overlay = FALSE;
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2077 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2078 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2079 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2080 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2082 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2083 LOGW("Display control is not supported");
2084 return MM_ERROR_PLAYER_INTERNAL;
2087 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2089 *paudio_only = (bool)disable_overlay;
2091 LOGD("audio_only : %d", *paudio_only);
2095 return MM_ERROR_NONE;
2099 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2101 GList *bucket = element_bucket;
2102 mmplayer_gst_element_t *element = NULL;
2103 mmplayer_gst_element_t *prv_element = NULL;
2104 GstElement *tee_element = NULL;
2105 gint successful_link_count = 0;
2109 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2111 prv_element = (mmplayer_gst_element_t *)bucket->data;
2112 bucket = bucket->next;
2114 for (; bucket; bucket = bucket->next) {
2115 element = (mmplayer_gst_element_t *)bucket->data;
2117 if (element && element->gst) {
2118 if (prv_element && prv_element->gst) {
2119 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2121 prv_element->gst = tee_element;
2123 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2124 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2125 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2129 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2130 LOGD("linking [%s] to [%s] success",
2131 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2132 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2133 successful_link_count++;
2134 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2135 LOGD("keep audio-tee element for next audio pipeline branch");
2136 tee_element = prv_element->gst;
2139 LOGD("linking [%s] to [%s] failed",
2140 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2141 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2147 prv_element = element;
2152 return successful_link_count;
2156 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2158 GList *bucket = element_bucket;
2159 mmplayer_gst_element_t *element = NULL;
2160 int successful_add_count = 0;
2164 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2165 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2167 for (; bucket; bucket = bucket->next) {
2168 element = (mmplayer_gst_element_t *)bucket->data;
2170 if (element && element->gst) {
2171 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2172 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2173 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2174 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2177 successful_add_count++;
2183 return successful_add_count;
2187 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2189 mmplayer_t *player = (mmplayer_t *)data;
2190 GstCaps *caps = NULL;
2191 GstStructure *str = NULL;
2193 gboolean caps_ret = TRUE;
2197 MMPLAYER_RETURN_IF_FAIL(pad);
2198 MMPLAYER_RETURN_IF_FAIL(unused);
2199 MMPLAYER_RETURN_IF_FAIL(data);
2201 caps = gst_pad_get_current_caps(pad);
2205 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2209 LOGD("name = %s", name);
2211 if (strstr(name, "audio")) {
2212 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2214 if (player->audio_stream_changed_cb) {
2215 LOGE("call the audio stream changed cb");
2216 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2218 } else if (strstr(name, "video")) {
2219 if ((name = gst_structure_get_string(str, "format")))
2220 player->set_mode.video_zc = name[0] == 'S';
2222 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2223 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2225 LOGW("invalid caps info");
2230 gst_caps_unref(caps);
2238 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2243 MMPLAYER_RETURN_IF_FAIL(player);
2245 if (player->audio_stream_buff_list) {
2246 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2247 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2250 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2251 __mmplayer_audio_stream_send_data(player, tmp);
2253 MMPLAYER_FREEIF(tmp->pcm_data);
2254 MMPLAYER_FREEIF(tmp);
2257 g_list_free(player->audio_stream_buff_list);
2258 player->audio_stream_buff_list = NULL;
2265 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2267 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2270 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2272 audio_stream.bitrate = a_buffer->bitrate;
2273 audio_stream.channel = a_buffer->channel;
2274 audio_stream.channel_mask = a_buffer->channel_mask;
2275 audio_stream.data_size = a_buffer->data_size;
2276 audio_stream.data = a_buffer->pcm_data;
2277 audio_stream.pcm_format = a_buffer->pcm_format;
2279 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2281 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2287 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2289 mmplayer_t *player = (mmplayer_t *)data;
2290 const gchar *pcm_format = NULL;
2293 guint64 channel_mask = 0;
2294 void *a_data = NULL;
2296 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2297 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2301 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2303 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2304 a_data = mapinfo.data;
2305 a_size = mapinfo.size;
2307 GstCaps *caps = gst_pad_get_current_caps(pad);
2308 GstStructure *structure = gst_caps_get_structure(caps, 0);
2310 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2312 pcm_format = gst_structure_get_string(structure, "format");
2313 gst_structure_get_int(structure, "rate", &rate);
2314 gst_structure_get_int(structure, "channels", &channel);
2315 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2316 gst_caps_unref(GST_CAPS(caps));
2318 /* In case of the sync is false, use buffer list. *
2319 * The num of buffer list depends on the num of audio channels */
2320 if (player->audio_stream_buff_list) {
2321 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2322 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2324 if (channel_mask == tmp->channel_mask) {
2326 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2328 if (tmp->data_size + a_size < tmp->buff_size) {
2329 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2330 tmp->data_size += a_size;
2332 /* send data to client */
2333 __mmplayer_audio_stream_send_data(player, tmp);
2335 if (a_size > tmp->buff_size) {
2336 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2337 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2338 if (tmp->pcm_data == NULL) {
2339 LOGE("failed to realloc data.");
2342 tmp->buff_size = a_size;
2344 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2345 memcpy(tmp->pcm_data, a_data, a_size);
2346 tmp->data_size = a_size;
2351 LOGE("data is empty in list.");
2357 /* create new audio stream data for newly found audio channel */
2358 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2359 if (a_buffer == NULL) {
2360 LOGE("failed to alloc data.");
2363 a_buffer->bitrate = rate;
2364 a_buffer->channel = channel;
2365 a_buffer->channel_mask = channel_mask;
2366 a_buffer->data_size = a_size;
2367 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2369 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2370 /* If sync is FALSE, use buffer list to reduce the IPC. */
2371 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2372 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2373 if (a_buffer->pcm_data == NULL) {
2374 LOGE("failed to alloc data.");
2375 MMPLAYER_FREEIF(a_buffer);
2378 memcpy(a_buffer->pcm_data, a_data, a_size);
2380 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2382 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2384 /* If sync is TRUE, send data directly. */
2385 a_buffer->pcm_data = a_data;
2386 __mmplayer_audio_stream_send_data(player, a_buffer);
2387 MMPLAYER_FREEIF(a_buffer);
2391 gst_buffer_unmap(buffer, &mapinfo);
2396 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2398 mmplayer_t *player = (mmplayer_t *)data;
2399 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2400 GstPad *sinkpad = NULL;
2401 GstElement *queue = NULL, *sink = NULL;
2404 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2406 queue = gst_element_factory_make("queue", NULL);
2407 if (queue == NULL) {
2408 LOGD("fail make queue");
2412 sink = gst_element_factory_make("fakesink", NULL);
2414 LOGD("fail make fakesink");
2418 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2420 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2421 LOGW("failed to link queue & sink");
2425 sinkpad = gst_element_get_static_pad(queue, "sink");
2427 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2428 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2432 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2434 gst_object_unref(sinkpad);
2435 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2436 g_object_set(sink, "sync", TRUE, NULL);
2437 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2439 /* keep the first sink reference only */
2440 if (!audiobin[MMPLAYER_A_SINK].gst) {
2441 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2442 audiobin[MMPLAYER_A_SINK].gst = sink;
2446 _mmplayer_add_signal_connection(player,
2448 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2450 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2453 __mmplayer_add_sink(player, sink);
2455 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2456 LOGE("failed to sync state");
2460 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2461 LOGE("failed to sync state");
2469 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2471 gst_object_unref(GST_OBJECT(queue));
2475 gst_object_unref(GST_OBJECT(sink));
2479 gst_object_unref(GST_OBJECT(sinkpad));
2487 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2489 mmplayer_t *player = (mmplayer_t *)data;
2492 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2494 player->no_more_pad = TRUE;
2495 __mmplayer_pipeline_complete(NULL, player);
2502 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2504 #define MAX_PROPS_LEN 128
2505 mmplayer_gst_element_t *audiobin = NULL;
2506 gint latency_mode = 0;
2507 gchar *stream_type = NULL;
2508 gchar *latency = NULL;
2510 gchar stream_props[MAX_PROPS_LEN] = {0,};
2511 GstStructure *props = NULL;
2514 * It should be set after player creation through attribute.
2515 * But, it can not be changed during playing.
2518 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2520 audiobin = player->pipeline->audiobin;
2522 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2523 if (player->sound.mute) {
2524 LOGD("mute enabled");
2525 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2528 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2529 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2532 snprintf(stream_props, sizeof(stream_props) - 1,
2533 "props,application.process.id.origin=%d", player->client_pid);
2535 snprintf(stream_props, sizeof(stream_props) - 1,
2536 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2537 stream_type, stream_id, player->client_pid);
2539 props = gst_structure_from_string(stream_props, NULL);
2540 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2541 LOGI("props result[%s].", stream_props);
2542 gst_structure_free(props);
2544 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2546 switch (latency_mode) {
2547 case AUDIO_LATENCY_MODE_LOW:
2548 latency = g_strdup("low");
2550 case AUDIO_LATENCY_MODE_MID:
2551 latency = g_strdup("mid");
2553 case AUDIO_LATENCY_MODE_HIGH:
2554 latency = g_strdup("high");
2557 latency = g_strdup("mid");
2561 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2563 LOGD("audiosink property - latency=%s", latency);
2565 MMPLAYER_FREEIF(latency);
2571 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2573 mmplayer_gst_element_t *audiobin = NULL;
2576 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2577 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2579 audiobin = player->pipeline->audiobin;
2581 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2582 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2583 LOGE("failed to create media stream info");
2584 return MM_ERROR_PLAYER_INTERNAL;
2587 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2589 if (player->video360_yaw_radians <= M_PI &&
2590 player->video360_yaw_radians >= -M_PI &&
2591 player->video360_pitch_radians <= M_PI_2 &&
2592 player->video360_pitch_radians >= -M_PI_2) {
2593 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2594 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2595 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2596 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2597 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2598 "source-orientation-y", player->video360_metadata.init_view_heading,
2599 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2603 return MM_ERROR_NONE;
2607 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2609 mmplayer_gst_element_t *audiobin = NULL;
2610 GstPad *sink_pad = NULL;
2611 GstCaps *acaps = NULL;
2613 int pitch_control = 0;
2614 double pitch_value = 1.0;
2617 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2618 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2620 audiobin = player->pipeline->audiobin;
2622 LOGD("make element for normal audio playback");
2624 /* audio bin structure for playback. {} means optional.
2625 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2627 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2628 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2631 /* for pitch control */
2632 mm_attrs_multiple_get(player->attrs, NULL,
2633 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2634 MM_PLAYER_PITCH_VALUE, &pitch_value,
2637 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2638 if (pitch_control && (player->videodec_linked == 0)) {
2639 GstElementFactory *factory;
2641 factory = gst_element_factory_find("pitch");
2643 gst_object_unref(factory);
2646 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2649 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2650 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2652 LOGW("there is no pitch element");
2657 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2659 /* replaygain volume */
2660 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2661 if (player->sound.rg_enable)
2662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2664 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2667 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2669 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2670 /* currently, only openalsink uses volume element */
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2672 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2674 if (player->sound.mute) {
2675 LOGD("mute enabled");
2676 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2680 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2682 /* audio effect element. if audio effect is enabled */
2683 if ((strcmp(player->ini.audioeffect_element, ""))
2685 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2686 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2688 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2690 if ((!player->bypass_audio_effect)
2691 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2692 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2693 if (!_mmplayer_audio_effect_custom_apply(player))
2694 LOGI("apply audio effect(custom) setting success");
2698 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2699 && (player->set_mode.rich_audio)) {
2700 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2704 /* create audio sink */
2705 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2706 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2707 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2709 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2710 if (player->is_360_feature_enabled &&
2711 player->is_content_spherical &&
2713 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2714 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2715 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2717 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2721 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2722 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2724 gst_caps_unref(acaps);
2726 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2728 player->is_openal_plugin_used = TRUE;
2730 if (player->is_360_feature_enabled && player->is_content_spherical)
2731 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2732 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2735 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2736 (player->videodec_linked && player->ini.use_system_clock)) {
2737 LOGD("system clock will be used.");
2738 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2741 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2742 __mmplayer_gst_set_pulsesink_property(player);
2743 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2744 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2749 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2750 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2752 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2753 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2754 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2755 gst_object_unref(GST_OBJECT(sink_pad));
2757 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2760 return MM_ERROR_NONE;
2762 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2764 return MM_ERROR_PLAYER_INTERNAL;
2768 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2770 mmplayer_gst_element_t *audiobin = NULL;
2771 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2773 gchar *dst_format = NULL;
2775 int dst_samplerate = 0;
2776 int dst_channels = 0;
2777 GstCaps *caps = NULL;
2778 char *caps_str = NULL;
2781 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2782 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2784 audiobin = player->pipeline->audiobin;
2786 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2788 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2790 [case 1] extract interleave audio pcm without playback
2791 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2792 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2794 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2796 [case 2] deinterleave for each channel without playback
2797 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2798 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2800 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2801 - fakesink (sync or not)
2804 [case 3] [case 1(sync only)] + playback
2805 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2807 * src - ... - tee - queue1 - playback path
2808 - queue2 - [case1 pipeline with sync]
2810 [case 4] [case 2(sync only)] + playback
2811 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2813 * src - ... - tee - queue1 - playback path
2814 - queue2 - [case2 pipeline with sync]
2818 /* 1. create tee and playback path
2819 'tee' should be added at first to copy the decoded stream
2821 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2823 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2825 /* tee - path 1 : for playback path */
2826 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2827 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2829 /* tee - path 2 : for extract path */
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2831 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2834 /* if there is tee, 'tee - path 2' is linked here */
2836 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2839 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2841 /* 2. decide the extract pcm format */
2842 mm_attrs_multiple_get(player->attrs, NULL,
2843 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2844 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2845 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2848 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2849 dst_format, dst_len, dst_samplerate, dst_channels);
2851 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2852 mm_attrs_multiple_get(player->attrs, NULL,
2853 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2854 "content_audio_samplerate", &dst_samplerate,
2855 "content_audio_channels", &dst_channels,
2858 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2859 dst_format, dst_len, dst_samplerate, dst_channels);
2861 /* If there is no enough information, set it to platform default value. */
2862 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2863 LOGD("set platform default format");
2864 dst_format = DEFAULT_PCM_OUT_FORMAT;
2866 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2867 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2870 /* 3. create capsfilter */
2871 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2872 caps = gst_caps_new_simple("audio/x-raw",
2873 "format", G_TYPE_STRING, dst_format,
2874 "rate", G_TYPE_INT, dst_samplerate,
2875 "channels", G_TYPE_INT, dst_channels,
2878 caps_str = gst_caps_to_string(caps);
2879 LOGD("new caps : %s", caps_str);
2881 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2884 gst_caps_unref(caps);
2885 MMPLAYER_FREEIF(caps_str);
2887 /* 4-1. create deinterleave to extract pcm for each channel */
2888 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2889 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2890 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2892 /* audiosink will be added after getting signal for each channel */
2893 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2894 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2895 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2896 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2897 player->no_more_pad = FALSE;
2899 /* 4-2. create fakesink to extract interlevaed pcm */
2900 LOGD("add audio fakesink for interleaved audio");
2901 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2902 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2903 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2904 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2906 _mmplayer_add_signal_connection(player,
2907 G_OBJECT(audiobin[extract_sink_id].gst),
2908 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2910 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2913 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2917 return MM_ERROR_NONE;
2919 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2921 return MM_ERROR_PLAYER_INTERNAL;
2925 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2927 int ret = MM_ERROR_NONE;
2928 mmplayer_gst_element_t *audiobin = NULL;
2929 GList *element_bucket = NULL;
2932 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2933 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2935 audiobin = player->pipeline->audiobin;
2937 if (player->build_audio_offload) { /* skip all the audio filters */
2938 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2940 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2941 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2942 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2944 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2948 /* FIXME: need to mention the supportable condition at API reference */
2949 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2950 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2952 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2954 if (ret != MM_ERROR_NONE)
2957 LOGD("success to make audio bin element");
2958 *bucket = element_bucket;
2961 return MM_ERROR_NONE;
2964 LOGE("failed to make audio bin element");
2965 g_list_free(element_bucket);
2969 return MM_ERROR_PLAYER_INTERNAL;
2973 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2975 mmplayer_gst_element_t *first_element = NULL;
2976 mmplayer_gst_element_t *audiobin = NULL;
2978 GstPad *ghostpad = NULL;
2979 GList *element_bucket = NULL;
2983 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2986 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2988 LOGE("failed to allocate memory for audiobin");
2989 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2993 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2994 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2995 if (!audiobin[MMPLAYER_A_BIN].gst) {
2996 LOGE("failed to create audiobin");
3001 player->pipeline->audiobin = audiobin;
3003 /* create audio filters and audiosink */
3004 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3007 /* adding created elements to bin */
3008 LOGD("adding created elements to bin");
3009 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3012 /* linking elements in the bucket by added order. */
3013 LOGD("Linking elements in the bucket by added order.");
3014 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3017 /* get first element's sinkpad for creating ghostpad */
3018 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3019 if (!first_element) {
3020 LOGE("failed to get first elem");
3024 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3026 LOGE("failed to get pad from first element of audiobin");
3030 ghostpad = gst_ghost_pad_new("sink", pad);
3032 LOGE("failed to create ghostpad");
3036 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3037 LOGE("failed to add ghostpad to audiobin");
3041 gst_object_unref(pad);
3043 g_list_free(element_bucket);
3046 return MM_ERROR_NONE;
3049 LOGD("ERROR : releasing audiobin");
3052 gst_object_unref(GST_OBJECT(pad));
3055 gst_object_unref(GST_OBJECT(ghostpad));
3058 g_list_free(element_bucket);
3060 /* release element which are not added to bin */
3061 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3062 /* NOTE : skip bin */
3063 if (audiobin[i].gst) {
3064 GstObject *parent = NULL;
3065 parent = gst_element_get_parent(audiobin[i].gst);
3068 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3069 audiobin[i].gst = NULL;
3071 gst_object_unref(GST_OBJECT(parent));
3075 /* release audiobin with it's childs */
3076 if (audiobin[MMPLAYER_A_BIN].gst)
3077 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3079 MMPLAYER_FREEIF(audiobin);
3081 player->pipeline->audiobin = NULL;
3083 return MM_ERROR_PLAYER_INTERNAL;
3087 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3089 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3093 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3095 int ret = MM_ERROR_NONE;
3097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3098 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3100 MMPLAYER_VIDEO_BO_LOCK(player);
3102 if (player->video_bo_list) {
3103 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3104 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3105 if (tmp && tmp->bo == bo) {
3107 LOGD("release bo %p", bo);
3108 tbm_bo_unref(tmp->bo);
3109 MMPLAYER_VIDEO_BO_UNLOCK(player);
3110 MMPLAYER_VIDEO_BO_SIGNAL(player);
3115 /* hw codec is running or the list was reset for DRC. */
3116 LOGW("there is no bo list.");
3118 MMPLAYER_VIDEO_BO_UNLOCK(player);
3120 LOGW("failed to find bo %p", bo);
3125 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3130 MMPLAYER_RETURN_IF_FAIL(player);
3132 MMPLAYER_VIDEO_BO_LOCK(player);
3133 if (player->video_bo_list) {
3134 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3135 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3136 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3139 tbm_bo_unref(tmp->bo);
3143 g_list_free(player->video_bo_list);
3144 player->video_bo_list = NULL;
3146 player->video_bo_size = 0;
3147 MMPLAYER_VIDEO_BO_UNLOCK(player);
3154 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3157 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3158 gboolean ret = TRUE;
3160 /* check DRC, if it is, destroy the prev bo list to create again */
3161 if (player->video_bo_size != size) {
3162 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3163 __mmplayer_video_stream_destroy_bo_list(player);
3164 player->video_bo_size = size;
3167 MMPLAYER_VIDEO_BO_LOCK(player);
3169 if ((!player->video_bo_list) ||
3170 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3172 /* create bo list */
3174 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3176 if (player->video_bo_list) {
3177 /* if bo list did not created all, try it again. */
3178 idx = g_list_length(player->video_bo_list);
3179 LOGD("bo list exist(len: %d)", idx);
3182 for (; idx < player->ini.num_of_video_bo; idx++) {
3183 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3185 LOGE("Fail to alloc bo_info.");
3188 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3190 LOGE("Fail to tbm_bo_alloc.");
3191 MMPLAYER_FREEIF(bo_info);
3194 bo_info->used = FALSE;
3195 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3198 /* update video num buffers */
3199 LOGD("video_num_buffers : %d", idx);
3200 mm_player_set_attribute((MMHandleType)player, NULL,
3201 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3202 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3206 MMPLAYER_VIDEO_BO_UNLOCK(player);
3212 /* get bo from list*/
3213 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3214 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3215 if (tmp && (tmp->used == FALSE)) {
3216 LOGD("found bo %p to use", tmp->bo);
3218 MMPLAYER_VIDEO_BO_UNLOCK(player);
3219 return tbm_bo_ref(tmp->bo);
3223 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3224 MMPLAYER_VIDEO_BO_UNLOCK(player);
3228 if (player->ini.video_bo_timeout <= 0) {
3229 MMPLAYER_VIDEO_BO_WAIT(player);
3231 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3232 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3239 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3241 mmplayer_t *player = (mmplayer_t *)data;
3243 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3245 /* send prerolled pkt */
3246 player->video_stream_prerolled = false;
3248 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3250 /* not to send prerolled pkt again */
3251 player->video_stream_prerolled = true;
3255 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3257 mmplayer_t *player = (mmplayer_t *)data;
3258 mmplayer_video_decoded_data_info_t *stream = NULL;
3259 GstMemory *mem = NULL;
3262 MMPLAYER_RETURN_IF_FAIL(player);
3263 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3265 if (player->video_stream_prerolled) {
3266 player->video_stream_prerolled = false;
3267 LOGD("skip the prerolled pkt not to send it again");
3271 /* clear stream data structure */
3272 stream = __mmplayer_create_stream_from_pad(pad);
3274 LOGE("failed to alloc stream");
3278 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3280 /* set size and timestamp */
3281 mem = gst_buffer_peek_memory(buffer, 0);
3282 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3283 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3285 /* check zero-copy */
3286 if (player->set_mode.video_zc &&
3287 player->set_mode.video_export &&
3288 gst_is_tizen_memory(mem)) {
3289 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3290 stream->internal_buffer = gst_buffer_ref(buffer);
3291 } else { /* sw codec */
3292 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3295 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3299 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3300 LOGE("failed to send video decoded data.");
3307 LOGE("release video stream resource.");
3308 if (gst_is_tizen_memory(mem)) {
3310 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3312 tbm_bo_unref(stream->bo[i]);
3315 /* unref gst buffer */
3316 if (stream->internal_buffer)
3317 gst_buffer_unref(stream->internal_buffer);
3320 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3322 MMPLAYER_FREEIF(stream);
3327 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3329 mmplayer_gst_element_t *videobin = NULL;
3332 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3334 videobin = player->pipeline->videobin;
3336 /* Set spatial media metadata and/or user settings to the element.
3338 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3339 "projection-type", player->video360_metadata.projection_type, NULL);
3341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3342 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3344 if (player->video360_metadata.full_pano_width_pixels &&
3345 player->video360_metadata.full_pano_height_pixels &&
3346 player->video360_metadata.cropped_area_image_width &&
3347 player->video360_metadata.cropped_area_image_height) {
3348 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3349 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3350 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3351 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3352 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3353 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3354 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3358 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3359 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3360 "horizontal-fov", player->video360_horizontal_fov,
3361 "vertical-fov", player->video360_vertical_fov, NULL);
3364 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "zoom", 1.0f / player->video360_zoom, NULL);
3369 if (player->video360_yaw_radians <= M_PI &&
3370 player->video360_yaw_radians >= -M_PI &&
3371 player->video360_pitch_radians <= M_PI_2 &&
3372 player->video360_pitch_radians >= -M_PI_2) {
3373 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3374 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3375 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3376 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3377 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3378 "pose-yaw", player->video360_metadata.init_view_heading,
3379 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3382 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3383 "passthrough", !player->is_video360_enabled, NULL);
3390 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3392 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3393 GList *element_bucket = NULL;
3396 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3398 /* create video360 filter */
3399 if (player->is_360_feature_enabled && player->is_content_spherical) {
3400 LOGD("create video360 element");
3401 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3402 __mmplayer_gst_set_video360_property(player);
3406 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3407 LOGD("skip creating the videoconv and rotator");
3408 return MM_ERROR_NONE;
3411 /* in case of sw codec & overlay surface type, except 360 playback.
3412 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3413 LOGD("create video converter: %s", video_csc);
3414 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3417 *bucket = element_bucket;
3419 return MM_ERROR_NONE;
3421 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3422 g_list_free(element_bucket);
3426 return MM_ERROR_PLAYER_INTERNAL;
3430 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3432 gchar *factory_name = NULL;
3434 switch (surface_type) {
3435 case MM_DISPLAY_SURFACE_OVERLAY:
3436 if (strlen(player->ini.videosink_element_overlay) > 0)
3437 factory_name = player->ini.videosink_element_overlay;
3439 case MM_DISPLAY_SURFACE_REMOTE:
3440 case MM_DISPLAY_SURFACE_NULL:
3441 if (strlen(player->ini.videosink_element_fake) > 0)
3442 factory_name = player->ini.videosink_element_fake;
3445 LOGE("unidentified surface type");
3449 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3450 return factory_name;
3454 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3456 gchar *factory_name = NULL;
3457 mmplayer_gst_element_t *videobin = NULL;
3462 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3464 videobin = player->pipeline->videobin;
3465 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3467 attrs = MMPLAYER_GET_ATTRS(player);
3469 LOGE("cannot get content attribute");
3470 return MM_ERROR_PLAYER_INTERNAL;
3473 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3474 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3475 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3476 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3477 "use-tbm", use_tbm, NULL);
3480 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3481 return MM_ERROR_PLAYER_INTERNAL;
3483 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3486 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3487 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3490 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3492 LOGD("disable last-sample");
3493 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3496 if (player->set_mode.video_export) {
3498 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3499 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3500 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3502 _mmplayer_add_signal_connection(player,
3503 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3504 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3506 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3509 _mmplayer_add_signal_connection(player,
3510 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3511 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3513 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3517 if (videobin[MMPLAYER_V_SINK].gst) {
3518 GstPad *sink_pad = NULL;
3519 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3521 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3522 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3523 gst_object_unref(GST_OBJECT(sink_pad));
3525 LOGE("failed to get sink pad from videosink");
3529 return MM_ERROR_NONE;
3534 * - video overlay surface(arm/x86) : tizenwlsink
3537 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3540 GList *element_bucket = NULL;
3541 mmplayer_gst_element_t *first_element = NULL;
3542 mmplayer_gst_element_t *videobin = NULL;
3543 gchar *videosink_factory_name = NULL;
3546 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3549 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3551 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3553 player->pipeline->videobin = videobin;
3556 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3557 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3558 if (!videobin[MMPLAYER_V_BIN].gst) {
3559 LOGE("failed to create videobin");
3563 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3566 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3567 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3569 /* additional setting for sink plug-in */
3570 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3571 LOGE("failed to set video property");
3575 /* store it as it's sink element */
3576 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3578 /* adding created elements to bin */
3579 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3580 LOGE("failed to add elements");
3584 /* Linking elements in the bucket by added order */
3585 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3586 LOGE("failed to link elements");
3590 /* get first element's sinkpad for creating ghostpad */
3591 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3592 if (!first_element) {
3593 LOGE("failed to get first element from bucket");
3597 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3599 LOGE("failed to get pad from first element");
3603 /* create ghostpad */
3604 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3605 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3606 LOGE("failed to add ghostpad to videobin");
3609 gst_object_unref(pad);
3611 /* done. free allocated variables */
3612 g_list_free(element_bucket);
3616 return MM_ERROR_NONE;
3619 LOGE("ERROR : releasing videobin");
3620 g_list_free(element_bucket);
3623 gst_object_unref(GST_OBJECT(pad));
3625 /* release videobin with it's childs */
3626 if (videobin[MMPLAYER_V_BIN].gst)
3627 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3629 MMPLAYER_FREEIF(videobin);
3630 player->pipeline->videobin = NULL;
3632 return MM_ERROR_PLAYER_INTERNAL;
3636 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3638 GList *element_bucket = NULL;
3639 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3641 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3642 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3643 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3644 "signal-handoffs", FALSE,
3647 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3648 _mmplayer_add_signal_connection(player,
3649 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3650 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3652 G_CALLBACK(__mmplayer_update_subtitle),
3655 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3656 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3658 if (!player->play_subtitle) {
3659 LOGD("add textbin sink as sink element of whole pipeline.");
3660 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3663 /* adding created elements to bin */
3664 LOGD("adding created elements to bin");
3665 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3666 LOGE("failed to add elements");
3670 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3671 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3672 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3674 /* linking elements in the bucket by added order. */
3675 LOGD("Linking elements in the bucket by added order.");
3676 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3677 LOGE("failed to link elements");
3681 /* done. free allocated variables */
3682 g_list_free(element_bucket);
3684 if (textbin[MMPLAYER_T_QUEUE].gst) {
3686 GstPad *ghostpad = NULL;
3688 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3690 LOGE("failed to get sink pad of text queue");
3694 ghostpad = gst_ghost_pad_new("text_sink", pad);
3695 gst_object_unref(pad);
3698 LOGE("failed to create ghostpad of textbin");
3702 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3703 LOGE("failed to add ghostpad to textbin");
3704 gst_object_unref(ghostpad);
3709 return MM_ERROR_NONE;
3712 g_list_free(element_bucket);
3714 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3715 LOGE("remove textbin sink from sink list");
3716 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3719 /* release element at __mmplayer_gst_create_text_sink_bin */
3720 return MM_ERROR_PLAYER_INTERNAL;
3724 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3726 mmplayer_gst_element_t *textbin = NULL;
3727 GList *element_bucket = NULL;
3728 int surface_type = 0;
3733 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3736 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3738 LOGE("failed to allocate memory for textbin");
3739 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3743 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3744 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3745 if (!textbin[MMPLAYER_T_BIN].gst) {
3746 LOGE("failed to create textbin");
3751 player->pipeline->textbin = textbin;
3754 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3755 LOGD("surface type for subtitle : %d", surface_type);
3756 switch (surface_type) {
3757 case MM_DISPLAY_SURFACE_OVERLAY:
3758 case MM_DISPLAY_SURFACE_NULL:
3759 case MM_DISPLAY_SURFACE_REMOTE:
3760 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3761 LOGE("failed to make plain text elements");
3772 return MM_ERROR_NONE;
3776 LOGD("ERROR : releasing textbin");
3778 g_list_free(element_bucket);
3780 /* release signal */
3781 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3783 /* release element which are not added to bin */
3784 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3785 /* NOTE : skip bin */
3786 if (textbin[i].gst) {
3787 GstObject *parent = NULL;
3788 parent = gst_element_get_parent(textbin[i].gst);
3791 gst_object_unref(GST_OBJECT(textbin[i].gst));
3792 textbin[i].gst = NULL;
3794 gst_object_unref(GST_OBJECT(parent));
3799 /* release textbin with it's childs */
3800 if (textbin[MMPLAYER_T_BIN].gst)
3801 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3803 MMPLAYER_FREEIF(textbin);
3804 player->pipeline->textbin = NULL;
3807 return MM_ERROR_PLAYER_INTERNAL;
3811 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3813 mmplayer_gst_element_t *mainbin = NULL;
3814 mmplayer_gst_element_t *textbin = NULL;
3815 MMHandleType attrs = 0;
3816 GstElement *subsrc = NULL;
3817 GstElement *subparse = NULL;
3818 gchar *subtitle_uri = NULL;
3819 const gchar *charset = NULL;
3825 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3827 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3829 mainbin = player->pipeline->mainbin;
3831 attrs = MMPLAYER_GET_ATTRS(player);
3833 LOGE("cannot get content attribute");
3834 return MM_ERROR_PLAYER_INTERNAL;
3837 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3838 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3839 LOGE("subtitle uri is not proper filepath.");
3840 return MM_ERROR_PLAYER_INVALID_URI;
3843 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3844 LOGE("failed to get storage info of subtitle path");
3845 return MM_ERROR_PLAYER_INVALID_URI;
3848 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3850 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3851 player->subtitle_language_list = NULL;
3852 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3854 /* create the subtitle source */
3855 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3857 LOGE("failed to create filesrc element");
3860 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3862 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3863 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3865 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3866 LOGW("failed to add queue");
3867 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3868 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3869 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3874 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3876 LOGE("failed to create subparse element");
3880 charset = _mmplayer_get_charset(subtitle_uri);
3882 LOGD("detected charset is %s", charset);
3883 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3886 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3887 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3889 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3890 LOGW("failed to add subparse");
3891 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3892 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3893 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3897 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3898 LOGW("failed to link subsrc and subparse");
3902 player->play_subtitle = TRUE;
3903 player->adjust_subtitle_pos = 0;
3905 LOGD("play subtitle using subtitle file");
3907 if (player->pipeline->textbin == NULL) {
3908 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3909 LOGE("failed to create text sink bin. continuing without text");
3913 textbin = player->pipeline->textbin;
3915 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3916 LOGW("failed to add textbin");
3918 /* release signal */
3919 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3921 /* release textbin with it's childs */
3922 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3923 MMPLAYER_FREEIF(player->pipeline->textbin);
3924 player->pipeline->textbin = textbin = NULL;
3928 LOGD("link text input selector and textbin ghost pad");
3930 player->textsink_linked = 1;
3931 player->external_text_idx = 0;
3932 LOGI("textsink is linked");
3934 textbin = player->pipeline->textbin;
3935 LOGD("text bin has been created. reuse it.");
3936 player->external_text_idx = 1;
3939 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3940 LOGW("failed to link subparse and textbin");
3944 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3946 LOGE("failed to get sink pad from textsink to probe data");
3950 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3951 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3953 gst_object_unref(pad);
3956 /* create dot. for debugging */
3957 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3960 return MM_ERROR_NONE;
3963 /* release text pipeline resource */
3964 player->textsink_linked = 0;
3966 /* release signal */
3967 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3969 if (player->pipeline->textbin) {
3970 LOGE("remove textbin");
3972 /* release textbin with it's childs */
3973 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3974 MMPLAYER_FREEIF(player->pipeline->textbin);
3975 player->pipeline->textbin = NULL;
3979 /* release subtitle elem */
3980 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3981 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3983 return MM_ERROR_PLAYER_INTERNAL;
3987 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3989 mmplayer_t *player = (mmplayer_t *)data;
3990 MMMessageParamType msg = {0, };
3991 GstClockTime duration = 0;
3992 gpointer text = NULL;
3993 guint text_size = 0;
3994 gboolean ret = TRUE;
3995 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3999 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4000 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4002 if (player->is_subtitle_force_drop) {
4003 LOGW("subtitle is dropped forcedly.");
4007 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4008 text = mapinfo.data;
4009 text_size = mapinfo.size;
4011 if (player->set_mode.subtitle_off) {
4012 LOGD("subtitle is OFF.");
4016 if (!text || (text_size == 0)) {
4017 LOGD("There is no subtitle to be displayed.");
4021 msg.data = (void *)text;
4023 duration = GST_BUFFER_DURATION(buffer);
4025 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4026 if (player->duration > GST_BUFFER_PTS(buffer))
4027 duration = player->duration - GST_BUFFER_PTS(buffer);
4030 LOGI("subtitle duration is invalid, subtitle duration change "
4031 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4033 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4035 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4037 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4038 gst_buffer_unmap(buffer, &mapinfo);
4045 static GstPadProbeReturn
4046 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4048 mmplayer_t *player = (mmplayer_t *)u_data;
4049 GstClockTime cur_timestamp = 0;
4050 gint64 adjusted_timestamp = 0;
4051 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4053 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4055 if (player->set_mode.subtitle_off) {
4056 LOGD("subtitle is OFF.");
4060 if (player->adjust_subtitle_pos == 0) {
4061 LOGD("nothing to do");
4065 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4066 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4068 if (adjusted_timestamp < 0) {
4069 LOGD("adjusted_timestamp under zero");
4074 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4075 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4076 GST_TIME_ARGS(cur_timestamp),
4077 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4079 return GST_PAD_PROBE_OK;
4083 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4087 /* check player and subtitlebin are created */
4088 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4089 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4091 if (position == 0) {
4092 LOGD("nothing to do");
4094 return MM_ERROR_NONE;
4097 /* check current postion */
4098 player->adjust_subtitle_pos = position;
4100 LOGD("save adjust_subtitle_pos in player");
4104 return MM_ERROR_NONE;
4108 * This function is to create audio or video pipeline for playing.
4110 * @param player [in] handle of player
4112 * @return This function returns zero on success.
4117 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4119 int ret = MM_ERROR_NONE;
4120 mmplayer_gst_element_t *mainbin = NULL;
4121 MMHandleType attrs = 0;
4124 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4126 /* get profile attribute */
4127 attrs = MMPLAYER_GET_ATTRS(player);
4129 LOGE("failed to get content attribute");
4133 /* create pipeline handles */
4134 if (player->pipeline) {
4135 LOGE("pipeline should be released before create new one");
4139 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4141 /* create mainbin */
4142 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4143 if (mainbin == NULL)
4146 /* create pipeline */
4147 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4148 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4149 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4150 LOGE("failed to create pipeline");
4155 player->pipeline->mainbin = mainbin;
4157 /* create the source and decoder elements */
4158 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4159 ret = _mmplayer_gst_build_es_pipeline(player);
4161 ret = _mmplayer_gst_build_pipeline(player);
4163 if (ret != MM_ERROR_NONE) {
4164 LOGE("failed to create some elements");
4168 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4169 if (__mmplayer_check_subtitle(player)
4170 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4171 LOGE("failed to create text pipeline");
4174 ret = _mmplayer_gst_add_bus_watch(player);
4175 if (ret != MM_ERROR_NONE) {
4176 LOGE("failed to add bus watch");
4181 return MM_ERROR_NONE;
4184 __mmplayer_gst_destroy_pipeline(player);
4185 return MM_ERROR_PLAYER_INTERNAL;
4189 __mmplayer_reset_gapless_state(mmplayer_t *player)
4192 MMPLAYER_RETURN_IF_FAIL(player
4194 && player->pipeline->audiobin
4195 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4197 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4204 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4207 int ret = MM_ERROR_NONE;
4211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4213 /* cleanup stuffs */
4214 MMPLAYER_FREEIF(player->type);
4215 player->no_more_pad = FALSE;
4216 player->num_dynamic_pad = 0;
4217 player->demux_pad_index = 0;
4219 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4220 player->subtitle_language_list = NULL;
4221 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4223 MMPLAYER_RECONFIGURE_LOCK(player);
4224 __mmplayer_reset_gapless_state(player);
4225 MMPLAYER_RECONFIGURE_UNLOCK(player);
4227 if (player->streamer) {
4228 _mm_player_streaming_initialize(player->streamer, FALSE);
4229 _mm_player_streaming_destroy(player->streamer);
4230 player->streamer = NULL;
4233 /* cleanup unlinked mime type */
4234 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4235 MMPLAYER_FREEIF(player->unlinked_video_mime);
4236 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4238 /* cleanup running stuffs */
4239 _mmplayer_cancel_eos_timer(player);
4241 /* cleanup gst stuffs */
4242 if (player->pipeline) {
4243 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4244 GstTagList *tag_list = player->pipeline->tag_list;
4246 /* first we need to disconnect all signal hander */
4247 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4250 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4251 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4252 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4253 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4254 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4255 gst_object_unref(bus);
4257 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4258 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4259 if (ret != MM_ERROR_NONE) {
4260 LOGE("fail to change state to NULL");
4261 return MM_ERROR_PLAYER_INTERNAL;
4264 LOGW("succeeded in changing state to NULL");
4266 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4269 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4270 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4272 /* free avsysaudiosink
4273 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4274 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4276 MMPLAYER_FREEIF(audiobin);
4277 MMPLAYER_FREEIF(videobin);
4278 MMPLAYER_FREEIF(textbin);
4279 MMPLAYER_FREEIF(mainbin);
4283 gst_tag_list_unref(tag_list);
4285 MMPLAYER_FREEIF(player->pipeline);
4287 MMPLAYER_FREEIF(player->album_art);
4289 if (player->v_stream_caps) {
4290 gst_caps_unref(player->v_stream_caps);
4291 player->v_stream_caps = NULL;
4294 if (player->a_stream_caps) {
4295 gst_caps_unref(player->a_stream_caps);
4296 player->a_stream_caps = NULL;
4299 if (player->s_stream_caps) {
4300 gst_caps_unref(player->s_stream_caps);
4301 player->s_stream_caps = NULL;
4303 _mmplayer_track_destroy(player);
4305 if (player->sink_elements)
4306 g_list_free(player->sink_elements);
4307 player->sink_elements = NULL;
4309 if (player->bufmgr) {
4310 tbm_bufmgr_deinit(player->bufmgr);
4311 player->bufmgr = NULL;
4314 LOGW("finished destroy pipeline");
4322 __mmplayer_gst_realize(mmplayer_t *player)
4325 int ret = MM_ERROR_NONE;
4329 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4331 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4333 ret = __mmplayer_gst_create_pipeline(player);
4335 LOGE("failed to create pipeline");
4339 /* set pipeline state to READY */
4340 /* NOTE : state change to READY must be performed sync. */
4341 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4342 ret = _mmplayer_gst_set_state(player,
4343 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4345 if (ret != MM_ERROR_NONE) {
4346 /* return error if failed to set state */
4347 LOGE("failed to set READY state");
4351 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4353 /* create dot before error-return. for debugging */
4354 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4362 __mmplayer_gst_unrealize(mmplayer_t *player)
4364 int ret = MM_ERROR_NONE;
4368 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4370 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4371 MMPLAYER_PRINT_STATE(player);
4373 /* release miscellaneous information */
4374 __mmplayer_release_misc(player);
4376 /* destroy pipeline */
4377 ret = __mmplayer_gst_destroy_pipeline(player);
4378 if (ret != MM_ERROR_NONE) {
4379 LOGE("failed to destory pipeline");
4383 /* release miscellaneous information.
4384 these info needs to be released after pipeline is destroyed. */
4385 __mmplayer_release_misc_post(player);
4387 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4395 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4400 LOGW("set_message_callback is called with invalid player handle");
4401 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4404 player->msg_cb = callback;
4405 player->msg_cb_param = user_param;
4407 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4411 return MM_ERROR_NONE;
4415 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4417 int ret = MM_ERROR_NONE;
4422 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4423 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4424 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4426 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4428 if (strstr(uri, "es_buff://")) {
4429 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4430 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4431 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4432 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4434 tmp = g_ascii_strdown(uri, strlen(uri));
4435 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4436 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4438 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4440 } else if (strstr(uri, "mms://")) {
4441 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4442 } else if ((path = strstr(uri, "mem://"))) {
4443 ret = __mmplayer_set_mem_uri(data, path, param);
4445 ret = __mmplayer_set_file_uri(data, uri);
4448 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4449 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4450 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4451 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4453 /* dump parse result */
4454 SECURE_LOGW("incoming uri : %s", uri);
4455 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4456 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4464 __mmplayer_can_do_interrupt(mmplayer_t *player)
4466 if (!player || !player->pipeline || !player->attrs) {
4467 LOGW("not initialized");
4471 if (player->audio_decoded_cb) {
4472 LOGW("not support in pcm extraction mode");
4476 /* check if seeking */
4477 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4478 MMMessageParamType msg_param;
4479 memset(&msg_param, 0, sizeof(MMMessageParamType));
4480 msg_param.code = MM_ERROR_PLAYER_SEEK;
4481 player->seek_state = MMPLAYER_SEEK_NONE;
4482 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4486 /* check other thread */
4487 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4488 LOGW("locked already, cmd state : %d", player->cmd);
4490 /* check application command */
4491 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4492 LOGW("playing.. should wait cmd lock then, will be interrupted");
4494 /* lock will be released at mrp_resource_release_cb() */
4495 MMPLAYER_CMD_LOCK(player);
4498 LOGW("nothing to do");
4501 LOGW("can interrupt immediately");
4505 FAILED: /* with CMD UNLOCKED */
4508 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4513 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4516 mmplayer_t *player = NULL;
4517 MMMessageParamType msg = {0, };
4519 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4524 LOGE("user_data is null");
4527 player = (mmplayer_t *)user_data;
4529 if (!__mmplayer_can_do_interrupt(player)) {
4530 LOGW("no need to interrupt, so leave");
4531 /* FIXME: there is no way to avoid releasing resource. */
4535 player->interrupted_by_resource = TRUE;
4537 /* get last play position */
4538 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4539 msg.union_type = MM_MSG_UNION_TIME;
4540 msg.time.elapsed = pos;
4541 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4543 LOGW("failed to get play position.");
4546 LOGD("video resource conflict so, resource will be freed by unrealizing");
4547 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4548 LOGE("failed to unrealize");
4550 /* lock is called in __mmplayer_can_do_interrupt() */
4551 MMPLAYER_CMD_UNLOCK(player);
4553 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4554 player->hw_resource[res_idx] = NULL;
4558 return TRUE; /* release all the resources */
4562 __mmplayer_initialize_video_roi(mmplayer_t *player)
4564 player->video_roi.scale_x = 0.0;
4565 player->video_roi.scale_y = 0.0;
4566 player->video_roi.scale_width = 1.0;
4567 player->video_roi.scale_height = 1.0;
4571 _mmplayer_create_player(MMHandleType handle)
4573 int ret = MM_ERROR_PLAYER_INTERNAL;
4574 bool enabled = false;
4576 mmplayer_t *player = MM_PLAYER_CAST(handle);
4580 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4582 /* initialize player state */
4583 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4584 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4585 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4586 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4588 /* check current state */
4589 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4591 /* construct attributes */
4592 player->attrs = _mmplayer_construct_attribute(handle);
4594 if (!player->attrs) {
4595 LOGE("Failed to construct attributes");
4599 /* initialize gstreamer with configured parameter */
4600 if (!__mmplayer_init_gstreamer(player)) {
4601 LOGE("Initializing gstreamer failed");
4602 _mmplayer_deconstruct_attribute(handle);
4606 /* create lock. note that g_tread_init() has already called in gst_init() */
4607 g_mutex_init(&player->fsink_lock);
4609 /* create update tag lock */
4610 g_mutex_init(&player->update_tag_lock);
4612 /* create gapless play mutex */
4613 g_mutex_init(&player->gapless_play_thread_mutex);
4615 /* create gapless play cond */
4616 g_cond_init(&player->gapless_play_thread_cond);
4618 /* create gapless play thread */
4619 player->gapless_play_thread =
4620 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4621 if (!player->gapless_play_thread) {
4622 LOGE("failed to create gapless play thread");
4623 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4624 g_mutex_clear(&player->gapless_play_thread_mutex);
4625 g_cond_clear(&player->gapless_play_thread_cond);
4629 player->bus_msg_q = g_queue_new();
4630 if (!player->bus_msg_q) {
4631 LOGE("failed to create queue for bus_msg");
4632 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4636 ret = _mmplayer_initialize_video_capture(player);
4637 if (ret != MM_ERROR_NONE) {
4638 LOGE("failed to initialize video capture");
4642 /* initialize resource manager */
4643 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4644 __resource_release_cb, player, &player->resource_manager)
4645 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4646 LOGE("failed to initialize resource manager");
4647 ret = MM_ERROR_PLAYER_INTERNAL;
4651 /* create video bo lock and cond */
4652 g_mutex_init(&player->video_bo_mutex);
4653 g_cond_init(&player->video_bo_cond);
4655 /* create subtitle info lock and cond */
4656 g_mutex_init(&player->subtitle_info_mutex);
4657 g_cond_init(&player->subtitle_info_cond);
4659 player->streaming_type = STREAMING_SERVICE_NONE;
4661 /* give default value of audio effect setting */
4662 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4663 player->sound.rg_enable = false;
4664 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4666 player->play_subtitle = FALSE;
4667 player->has_closed_caption = FALSE;
4668 player->pending_resume = FALSE;
4669 if (player->ini.dump_element_keyword[0][0] == '\0')
4670 player->ini.set_dump_element_flag = FALSE;
4672 player->ini.set_dump_element_flag = TRUE;
4674 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4675 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4676 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4678 /* Set video360 settings to their defaults for just-created player.
4681 player->is_360_feature_enabled = FALSE;
4682 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4683 LOGI("spherical feature info: %d", enabled);
4685 player->is_360_feature_enabled = TRUE;
4687 LOGE("failed to get spherical feature info");
4690 player->is_content_spherical = FALSE;
4691 player->is_video360_enabled = TRUE;
4692 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4693 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4694 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4695 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4696 player->video360_zoom = 1.0f;
4697 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4698 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4700 __mmplayer_initialize_video_roi(player);
4702 /* set player state to null */
4703 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4704 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4708 return MM_ERROR_NONE;
4712 g_mutex_clear(&player->fsink_lock);
4713 /* free update tag lock */
4714 g_mutex_clear(&player->update_tag_lock);
4715 g_queue_free(player->bus_msg_q);
4716 player->bus_msg_q = NULL;
4717 /* free gapless play thread */
4718 if (player->gapless_play_thread) {
4719 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4720 player->gapless_play_thread_exit = TRUE;
4721 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4722 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4724 g_thread_join(player->gapless_play_thread);
4725 player->gapless_play_thread = NULL;
4727 g_mutex_clear(&player->gapless_play_thread_mutex);
4728 g_cond_clear(&player->gapless_play_thread_cond);
4731 /* release attributes */
4732 _mmplayer_deconstruct_attribute(handle);
4740 __mmplayer_init_gstreamer(mmplayer_t *player)
4742 static gboolean initialized = FALSE;
4743 static const int max_argc = 50;
4745 gchar **argv = NULL;
4746 gchar **argv2 = NULL;
4752 LOGD("gstreamer already initialized.");
4757 argc = malloc(sizeof(int));
4758 argv = malloc(sizeof(gchar *) * max_argc);
4759 argv2 = malloc(sizeof(gchar *) * max_argc);
4761 if (!argc || !argv || !argv2)
4764 memset(argv, 0, sizeof(gchar *) * max_argc);
4765 memset(argv2, 0, sizeof(gchar *) * max_argc);
4769 argv[0] = g_strdup("mmplayer");
4772 for (i = 0; i < 5; i++) {
4773 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4774 if (strlen(player->ini.gst_param[i]) > 0) {
4775 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4780 /* we would not do fork for scanning plugins */
4781 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4784 /* check disable registry scan */
4785 if (player->ini.skip_rescan) {
4786 argv[*argc] = g_strdup("--gst-disable-registry-update");
4790 /* check disable segtrap */
4791 if (player->ini.disable_segtrap) {
4792 argv[*argc] = g_strdup("--gst-disable-segtrap");
4796 LOGD("initializing gstreamer with following parameter");
4797 LOGD("argc : %d", *argc);
4800 for (i = 0; i < arg_count; i++) {
4802 LOGD("argv[%d] : %s", i, argv2[i]);
4805 /* initializing gstreamer */
4806 if (!gst_init_check(argc, &argv, &err)) {
4807 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4814 for (i = 0; i < arg_count; i++) {
4816 LOGD("release - argv[%d] : %s", i, argv2[i]);
4818 MMPLAYER_FREEIF(argv2[i]);
4821 MMPLAYER_FREEIF(argv);
4822 MMPLAYER_FREEIF(argv2);
4823 MMPLAYER_FREEIF(argc);
4833 for (i = 0; i < arg_count; i++) {
4834 LOGD("free[%d] : %s", i, argv2[i]);
4835 MMPLAYER_FREEIF(argv2[i]);
4838 MMPLAYER_FREEIF(argv);
4839 MMPLAYER_FREEIF(argv2);
4840 MMPLAYER_FREEIF(argc);
4846 __mmplayer_check_async_state_transition(mmplayer_t *player)
4848 GstState element_state = GST_STATE_VOID_PENDING;
4849 GstState element_pending_state = GST_STATE_VOID_PENDING;
4850 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4851 GstElement *element = NULL;
4852 gboolean async = FALSE;
4854 /* check player handle */
4855 MMPLAYER_RETURN_IF_FAIL(player &&
4857 player->pipeline->mainbin &&
4858 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4861 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4863 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4864 LOGD("don't need to check the pipeline state");
4868 MMPLAYER_PRINT_STATE(player);
4870 /* wait for state transition */
4871 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4872 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4874 if (ret == GST_STATE_CHANGE_FAILURE) {
4875 LOGE(" [%s] state : %s pending : %s",
4876 GST_ELEMENT_NAME(element),
4877 gst_element_state_get_name(element_state),
4878 gst_element_state_get_name(element_pending_state));
4880 /* dump state of all element */
4881 _mmplayer_dump_pipeline_state(player);
4886 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4891 _mmplayer_destroy(MMHandleType handle)
4893 mmplayer_t *player = MM_PLAYER_CAST(handle);
4897 /* check player handle */
4898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4900 /* destroy can called at anytime */
4901 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4903 /* check async state transition */
4904 __mmplayer_check_async_state_transition(player);
4906 /* release gapless play thread */
4907 if (player->gapless_play_thread) {
4908 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4909 player->gapless_play_thread_exit = TRUE;
4910 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4911 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4913 LOGD("waitting for gapless play thread exit");
4914 g_thread_join(player->gapless_play_thread);
4915 g_mutex_clear(&player->gapless_play_thread_mutex);
4916 g_cond_clear(&player->gapless_play_thread_cond);
4917 LOGD("gapless play thread released");
4920 _mmplayer_release_video_capture(player);
4922 /* de-initialize resource manager */
4923 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4924 player->resource_manager))
4925 LOGE("failed to deinitialize resource manager");
4927 /* release miscellaneous information */
4928 __mmplayer_release_misc(player);
4930 /* release pipeline */
4931 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4932 LOGE("failed to destory pipeline");
4933 return MM_ERROR_PLAYER_INTERNAL;
4936 g_queue_free(player->bus_msg_q);
4938 /* release subtitle info lock and cond */
4939 g_mutex_clear(&player->subtitle_info_mutex);
4940 g_cond_clear(&player->subtitle_info_cond);
4942 __mmplayer_release_dump_list(player->dump_list);
4944 /* release miscellaneous information.
4945 these info needs to be released after pipeline is destroyed. */
4946 __mmplayer_release_misc_post(player);
4948 /* release attributes */
4949 _mmplayer_deconstruct_attribute(handle);
4951 if (player->uri_info.uri_list) {
4952 GList *uri_list = player->uri_info.uri_list;
4953 for (; uri_list; uri_list = g_list_next(uri_list)) {
4954 gchar *uri = uri_list->data;
4955 MMPLAYER_FREEIF(uri);
4957 g_list_free(player->uri_info.uri_list);
4958 player->uri_info.uri_list = NULL;
4962 g_mutex_clear(&player->fsink_lock);
4965 g_mutex_clear(&player->update_tag_lock);
4967 /* release video bo lock and cond */
4968 g_mutex_clear(&player->video_bo_mutex);
4969 g_cond_clear(&player->video_bo_cond);
4973 return MM_ERROR_NONE;
4977 _mmplayer_realize(MMHandleType hplayer)
4979 mmplayer_t *player = (mmplayer_t *)hplayer;
4980 int ret = MM_ERROR_NONE;
4983 MMHandleType attrs = 0;
4984 int video_codec_type = 0;
4985 int audio_codec_type = 0;
4986 int default_codec_type = 0;
4989 /* check player handle */
4990 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4992 /* check current state */
4993 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4995 attrs = MMPLAYER_GET_ATTRS(player);
4997 LOGE("fail to get attributes.");
4998 return MM_ERROR_PLAYER_INTERNAL;
5000 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5001 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5003 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5004 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5006 if (ret != MM_ERROR_NONE) {
5007 LOGE("failed to parse profile");
5012 if (uri && (strstr(uri, "es_buff://"))) {
5013 if (strstr(uri, "es_buff://push_mode"))
5014 player->es_player_push_mode = TRUE;
5016 player->es_player_push_mode = FALSE;
5019 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5020 LOGW("mms protocol is not supported format.");
5021 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5024 if (MMPLAYER_IS_STREAMING(player))
5025 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5027 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5029 player->smooth_streaming = FALSE;
5030 player->videodec_linked = 0;
5031 player->audiodec_linked = 0;
5032 player->textsink_linked = 0;
5033 player->is_external_subtitle_present = FALSE;
5034 player->is_external_subtitle_added_now = FALSE;
5035 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5036 player->video360_metadata.is_spherical = -1;
5037 player->is_openal_plugin_used = FALSE;
5038 player->demux_pad_index = 0;
5039 player->subtitle_language_list = NULL;
5040 player->is_subtitle_force_drop = FALSE;
5042 _mmplayer_track_initialize(player);
5043 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5045 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5046 gint prebuffer_ms = 0, rebuffer_ms = 0;
5048 player->streamer = _mm_player_streaming_create();
5049 _mm_player_streaming_initialize(player->streamer, TRUE);
5051 mm_attrs_multiple_get(player->attrs, NULL,
5052 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5053 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5055 if (prebuffer_ms > 0) {
5056 prebuffer_ms = MAX(prebuffer_ms, 1000);
5057 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5060 if (rebuffer_ms > 0) {
5061 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5062 rebuffer_ms = MAX(rebuffer_ms, 1000);
5063 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5066 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5067 player->streamer->buffering_req.rebuffer_time);
5070 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5071 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5072 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5074 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5076 if (audio_codec_type != default_codec_type) {
5077 LOGD("audio dec sorting is required");
5078 player->need_audio_dec_sorting = TRUE;
5081 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5082 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5083 LOGD("video dec sorting is required");
5084 player->need_video_dec_sorting = TRUE;
5087 /* realize pipeline */
5088 ret = __mmplayer_gst_realize(player);
5089 if (ret != MM_ERROR_NONE)
5090 LOGE("fail to realize the player.");
5092 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5100 _mmplayer_unrealize(MMHandleType hplayer)
5102 mmplayer_t *player = (mmplayer_t *)hplayer;
5103 int ret = MM_ERROR_NONE;
5107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5109 MMPLAYER_CMD_UNLOCK(player);
5110 /* destroy the gst bus msg thread which is created during realize.
5111 this funct have to be called before getting cmd lock. */
5112 _mmplayer_bus_msg_thread_destroy(player);
5113 MMPLAYER_CMD_LOCK(player);
5115 /* check current state */
5116 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5118 /* check async state transition */
5119 __mmplayer_check_async_state_transition(player);
5121 /* unrealize pipeline */
5122 ret = __mmplayer_gst_unrealize(player);
5124 if (!player->interrupted_by_resource) {
5125 int rm_ret = MM_ERROR_NONE;
5126 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5128 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5129 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5130 if (rm_ret != MM_ERROR_NONE)
5131 LOGE("failed to release [%d] resources", res_idx);
5140 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5142 mmplayer_t *player = (mmplayer_t *)hplayer;
5144 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5146 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5150 _mmplayer_get_state(MMHandleType hplayer, int *state)
5152 mmplayer_t *player = (mmplayer_t *)hplayer;
5154 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5156 *state = MMPLAYER_CURRENT_STATE(player);
5158 return MM_ERROR_NONE;
5162 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5164 GstElement *vol_element = NULL;
5165 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5168 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5171 /* check pipeline handle */
5172 if (!player->pipeline || !player->pipeline->audiobin) {
5173 LOGD("'%s' will be applied when audiobin is created", prop_name);
5175 /* NOTE : stored value will be used in create_audiobin
5176 * returning MM_ERROR_NONE here makes application to able to
5177 * set audio volume or mute at anytime.
5179 return MM_ERROR_NONE;
5182 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5183 volume_elem_id = MMPLAYER_A_SINK;
5185 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5187 LOGE("failed to get vol element %d", volume_elem_id);
5188 return MM_ERROR_PLAYER_INTERNAL;
5191 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5193 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5194 LOGE("there is no '%s' property", prop_name);
5195 return MM_ERROR_PLAYER_INTERNAL;
5198 if (!strcmp(prop_name, "volume")) {
5199 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5200 } else if (!strcmp(prop_name, "mute")) {
5201 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5203 LOGE("invalid property %s", prop_name);
5204 return MM_ERROR_PLAYER_INTERNAL;
5207 return MM_ERROR_NONE;
5211 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5213 int ret = MM_ERROR_NONE;
5214 mmplayer_t *player = (mmplayer_t *)hplayer;
5217 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5219 LOGD("volume = %f", volume);
5221 /* invalid factor range or not */
5222 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5223 LOGE("Invalid volume value");
5224 return MM_ERROR_INVALID_ARGUMENT;
5227 player->sound.volume = volume;
5229 ret = __mmplayer_gst_set_volume_property(player, "volume");
5236 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5238 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5243 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5245 *volume = player->sound.volume;
5247 LOGD("current vol = %f", *volume);
5250 return MM_ERROR_NONE;
5254 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5256 int ret = MM_ERROR_NONE;
5257 mmplayer_t *player = (mmplayer_t *)hplayer;
5260 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5262 LOGD("mute = %d", mute);
5264 player->sound.mute = mute;
5266 ret = __mmplayer_gst_set_volume_property(player, "mute");
5273 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5275 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5282 *mute = player->sound.mute;
5284 LOGD("current mute = %d", *mute);
5288 return MM_ERROR_NONE;
5292 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5294 mmplayer_t *player = (mmplayer_t *)hplayer;
5298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5300 player->audio_stream_changed_cb = callback;
5301 player->audio_stream_changed_cb_user_param = user_param;
5302 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5306 return MM_ERROR_NONE;
5310 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5312 mmplayer_t *player = (mmplayer_t *)hplayer;
5316 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5318 player->audio_decoded_cb = callback;
5319 player->audio_decoded_cb_user_param = user_param;
5320 player->audio_extract_opt = opt;
5321 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5325 return MM_ERROR_NONE;
5329 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5331 mmplayer_t *player = (mmplayer_t *)hplayer;
5335 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5337 if (callback && !player->bufmgr)
5338 player->bufmgr = tbm_bufmgr_init(-1);
5340 player->set_mode.video_export = (callback) ? true : false;
5341 player->video_decoded_cb = callback;
5342 player->video_decoded_cb_user_param = user_param;
5344 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5348 return MM_ERROR_NONE;
5352 _mmplayer_start(MMHandleType hplayer)
5354 mmplayer_t *player = (mmplayer_t *)hplayer;
5355 gint ret = MM_ERROR_NONE;
5359 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5361 /* check current state */
5362 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5364 /* start pipeline */
5365 ret = _mmplayer_gst_start(player);
5366 if (ret != MM_ERROR_NONE)
5367 LOGE("failed to start player.");
5369 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5370 LOGD("force playing start even during buffering");
5371 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5379 /* NOTE: post "not supported codec message" to application
5380 * when one codec is not found during AUTOPLUGGING in MSL.
5381 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5382 * And, if any codec is not found, don't send message here.
5383 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5386 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5388 MMMessageParamType msg_param;
5389 memset(&msg_param, 0, sizeof(MMMessageParamType));
5390 gboolean post_msg_direct = FALSE;
5394 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5396 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5397 player->not_supported_codec, player->can_support_codec);
5399 if (player->not_found_demuxer) {
5400 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5401 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5403 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5404 MMPLAYER_FREEIF(msg_param.data);
5406 return MM_ERROR_NONE;
5409 if (player->not_supported_codec) {
5410 if (player->can_support_codec) {
5411 // There is one codec to play
5412 post_msg_direct = TRUE;
5414 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5415 post_msg_direct = TRUE;
5418 if (post_msg_direct) {
5419 MMMessageParamType msg_param;
5420 memset(&msg_param, 0, sizeof(MMMessageParamType));
5422 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5423 LOGW("not found AUDIO codec, posting error code to application.");
5425 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5426 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5427 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5428 LOGW("not found VIDEO codec, posting error code to application.");
5430 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5431 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5434 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5436 MMPLAYER_FREEIF(msg_param.data);
5438 return MM_ERROR_NONE;
5440 // no any supported codec case
5441 LOGW("not found any codec, posting error code to application.");
5443 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5444 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5445 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5447 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5448 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5451 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5453 MMPLAYER_FREEIF(msg_param.data);
5459 return MM_ERROR_NONE;
5462 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5464 GstState element_state = GST_STATE_VOID_PENDING;
5465 GstState element_pending_state = GST_STATE_VOID_PENDING;
5466 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5467 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5469 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5471 MMPLAYER_RECONFIGURE_LOCK(player);
5472 if (!player->gapless.reconfigure) {
5473 MMPLAYER_RECONFIGURE_UNLOCK(player);
5477 LOGI("reconfigure is under process");
5478 MMPLAYER_RECONFIGURE_WAIT(player);
5479 MMPLAYER_RECONFIGURE_UNLOCK(player);
5480 LOGI("reconfigure is completed.");
5482 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5483 &element_state, &element_pending_state, timeout * GST_SECOND);
5484 if (result == GST_STATE_CHANGE_FAILURE)
5485 LOGW("failed to get pipeline state in %d sec", timeout);
5490 /* NOTE : it should be able to call 'stop' anytime*/
5492 _mmplayer_stop(MMHandleType hplayer)
5494 mmplayer_t *player = (mmplayer_t *)hplayer;
5495 int ret = MM_ERROR_NONE;
5499 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5501 /* check current state */
5502 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5504 /* need to wait till the rebuilding pipeline is completed */
5505 __mmplayer_check_pipeline_reconfigure_state(player);
5506 MMPLAYER_RECONFIGURE_LOCK(player);
5507 __mmplayer_reset_gapless_state(player);
5508 MMPLAYER_RECONFIGURE_UNLOCK(player);
5510 /* NOTE : application should not wait for EOS after calling STOP */
5511 _mmplayer_cancel_eos_timer(player);
5514 player->seek_state = MMPLAYER_SEEK_NONE;
5517 ret = _mmplayer_gst_stop(player);
5519 if (ret != MM_ERROR_NONE)
5520 LOGE("failed to stop player.");
5528 _mmplayer_pause(MMHandleType hplayer)
5530 mmplayer_t *player = (mmplayer_t *)hplayer;
5531 gint64 pos_nsec = 0;
5532 gboolean async = FALSE;
5533 gint ret = MM_ERROR_NONE;
5537 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5539 /* check current state */
5540 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5542 /* check pipline reconfigure state */
5543 __mmplayer_check_pipeline_reconfigure_state(player);
5545 switch (MMPLAYER_CURRENT_STATE(player)) {
5546 case MM_PLAYER_STATE_READY:
5548 /* check prepare async or not.
5549 * In the case of streaming playback, it's recommned to avoid blocking wait.
5551 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5552 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5554 /* Changing back sync of rtspsrc to async */
5555 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5556 LOGD("async prepare working mode for rtsp");
5562 case MM_PLAYER_STATE_PLAYING:
5564 /* NOTE : store current point to overcome some bad operation
5565 *(returning zero when getting current position in paused state) of some
5568 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5569 LOGW("getting current position failed in paused");
5571 player->last_position = pos_nsec;
5573 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5574 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5575 This causes problem is position calculation during normal pause resume scenarios also.
5576 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5577 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5578 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5579 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5585 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5586 LOGD("doing async pause in case of ms buff src");
5590 /* pause pipeline */
5591 ret = _mmplayer_gst_pause(player, async);
5593 if (ret != MM_ERROR_NONE)
5594 LOGE("failed to pause player. ret : 0x%x", ret);
5596 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5597 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5598 LOGE("failed to update display_rotation");
5606 /* in case of streaming, pause could take long time.*/
5608 _mmplayer_abort_pause(MMHandleType hplayer)
5610 mmplayer_t *player = (mmplayer_t *)hplayer;
5611 int ret = MM_ERROR_NONE;
5615 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5617 player->pipeline->mainbin,
5618 MM_ERROR_PLAYER_NOT_INITIALIZED);
5620 LOGD("set the pipeline state to READY");
5622 /* set state to READY */
5623 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5624 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5625 if (ret != MM_ERROR_NONE) {
5626 LOGE("fail to change state to READY");
5627 return MM_ERROR_PLAYER_INTERNAL;
5630 LOGD("succeeded in changing state to READY");
5635 _mmplayer_resume(MMHandleType hplayer)
5637 mmplayer_t *player = (mmplayer_t *)hplayer;
5638 int ret = MM_ERROR_NONE;
5639 gboolean async = FALSE;
5643 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5645 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5646 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5647 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5651 /* Changing back sync mode rtspsrc to async */
5652 LOGD("async resume for rtsp case");
5656 /* check current state */
5657 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5659 ret = _mmplayer_gst_resume(player, async);
5660 if (ret != MM_ERROR_NONE)
5661 LOGE("failed to resume player.");
5663 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5664 LOGD("force resume even during buffering");
5665 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5674 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5676 mmplayer_t *player = (mmplayer_t *)hplayer;
5677 gint64 pos_nsec = 0;
5678 int ret = MM_ERROR_NONE;
5680 signed long long start = 0, stop = 0;
5681 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5684 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5685 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5687 /* The sound of video is not supported under 0.0 and over 2.0. */
5688 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5689 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5692 _mmplayer_set_mute(hplayer, mute);
5694 if (player->playback_rate == rate)
5695 return MM_ERROR_NONE;
5697 /* If the position is reached at start potion during fast backward, EOS is posted.
5698 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5700 player->playback_rate = rate;
5702 current_state = MMPLAYER_CURRENT_STATE(player);
5704 if (current_state != MM_PLAYER_STATE_PAUSED)
5705 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5707 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5709 if ((current_state == MM_PLAYER_STATE_PAUSED)
5710 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5711 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5712 pos_nsec = player->last_position;
5717 stop = GST_CLOCK_TIME_NONE;
5719 start = GST_CLOCK_TIME_NONE;
5723 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5724 player->playback_rate,
5726 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5727 GST_SEEK_TYPE_SET, start,
5728 GST_SEEK_TYPE_SET, stop)) {
5729 LOGE("failed to set speed playback");
5730 return MM_ERROR_PLAYER_SEEK;
5733 LOGD("succeeded to set speed playback as %0.1f", rate);
5737 return MM_ERROR_NONE;;
5741 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5743 mmplayer_t *player = (mmplayer_t *)hplayer;
5744 int ret = MM_ERROR_NONE;
5748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5750 /* check pipline reconfigure state */
5751 __mmplayer_check_pipeline_reconfigure_state(player);
5753 ret = _mmplayer_gst_set_position(player, position, FALSE);
5761 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5763 mmplayer_t *player = (mmplayer_t *)hplayer;
5764 int ret = MM_ERROR_NONE;
5766 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5767 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5769 if (g_strrstr(player->type, "video/mpegts"))
5770 __mmplayer_update_duration_value(player);
5772 *duration = player->duration;
5777 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
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);
5784 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5790 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5792 mmplayer_t *player = (mmplayer_t *)hplayer;
5793 int ret = MM_ERROR_NONE;
5797 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5799 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5807 __mmplayer_is_midi_type(gchar *str_caps)
5809 if ((g_strrstr(str_caps, "audio/midi")) ||
5810 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5811 (g_strrstr(str_caps, "application/x-smaf")) ||
5812 (g_strrstr(str_caps, "audio/x-imelody")) ||
5813 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5814 (g_strrstr(str_caps, "audio/xmf")) ||
5815 (g_strrstr(str_caps, "audio/mxmf"))) {
5824 __mmplayer_is_only_mp3_type(gchar *str_caps)
5826 if (g_strrstr(str_caps, "application/x-id3") ||
5827 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5833 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5835 GstStructure *caps_structure = NULL;
5836 gint samplerate = 0;
5840 MMPLAYER_RETURN_IF_FAIL(player && caps);
5842 caps_structure = gst_caps_get_structure(caps, 0);
5844 /* set stream information */
5845 gst_structure_get_int(caps_structure, "rate", &samplerate);
5846 gst_structure_get_int(caps_structure, "channels", &channels);
5848 mm_player_set_attribute((MMHandleType)player, NULL,
5849 "content_audio_samplerate", samplerate,
5850 "content_audio_channels", channels, NULL);
5852 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5856 __mmplayer_update_content_type_info(mmplayer_t *player)
5859 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5861 if (__mmplayer_is_midi_type(player->type)) {
5862 player->bypass_audio_effect = TRUE;
5866 if (!player->streamer) {
5867 LOGD("no need to check streaming type");
5871 if (g_strrstr(player->type, "application/x-hls")) {
5872 /* If it can't know exact type when it parses uri because of redirection case,
5873 * it will be fixed by typefinder or when doing autoplugging.
5875 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5876 player->streamer->is_adaptive_streaming = TRUE;
5877 } else if (g_strrstr(player->type, "application/dash+xml")) {
5878 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5879 player->streamer->is_adaptive_streaming = TRUE;
5882 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5883 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5884 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5886 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5887 if (player->streamer->is_adaptive_streaming)
5888 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5890 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5894 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5899 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5900 GstCaps *caps, gpointer data)
5902 mmplayer_t *player = (mmplayer_t *)data;
5907 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5909 /* store type string */
5910 MMPLAYER_FREEIF(player->type);
5911 player->type = gst_caps_to_string(caps);
5913 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5914 player, player->type, probability, gst_caps_get_size(caps));
5916 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5917 (g_strrstr(player->type, "audio/x-raw-int"))) {
5918 LOGE("not support media format");
5920 if (player->msg_posted == FALSE) {
5921 MMMessageParamType msg_param;
5922 memset(&msg_param, 0, sizeof(MMMessageParamType));
5924 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5925 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5927 /* don't post more if one was sent already */
5928 player->msg_posted = TRUE;
5933 __mmplayer_update_content_type_info(player);
5935 pad = gst_element_get_static_pad(tf, "src");
5937 LOGE("fail to get typefind src pad.");
5941 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5942 gboolean async = FALSE;
5943 LOGE("failed to autoplug %s", player->type);
5945 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5947 if (async && player->msg_posted == FALSE)
5948 __mmplayer_handle_missed_plugin(player);
5952 gst_object_unref(GST_OBJECT(pad));
5960 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5962 GstElement *decodebin = NULL;
5966 /* create decodebin */
5967 decodebin = gst_element_factory_make("decodebin", NULL);
5970 LOGE("fail to create decodebin");
5974 /* raw pad handling signal */
5975 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5976 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5978 /* no-more-pad pad handling signal */
5979 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5980 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5982 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5983 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5985 /* This signal is emitted when a pad for which there is no further possible
5986 decoding is added to the decodebin.*/
5987 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5988 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5990 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5991 before looking for any elements that can handle that stream.*/
5992 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5993 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5995 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5996 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5997 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5999 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6000 before looking for any elements that can handle that stream.*/
6001 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6002 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6004 /* This signal is emitted once decodebin has finished decoding all the data.*/
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6006 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6008 /* This signal is emitted when a element is added to the bin.*/
6009 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6010 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6017 __mmplayer_gst_make_queue2(mmplayer_t *player)
6019 GstElement *queue2 = NULL;
6020 gint64 dur_bytes = 0L;
6021 mmplayer_gst_element_t *mainbin = NULL;
6022 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6025 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6027 mainbin = player->pipeline->mainbin;
6029 queue2 = gst_element_factory_make("queue2", "queue2");
6031 LOGE("failed to create buffering queue element");
6035 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6036 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6038 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6040 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6041 * skip the pull mode(file or ring buffering) setting. */
6042 if (dur_bytes > 0) {
6043 if (!g_strrstr(player->type, "video/mpegts")) {
6044 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6045 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6051 _mm_player_streaming_set_queue2(player->streamer,
6055 (guint64)dur_bytes); /* no meaning at the moment */
6061 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6063 mmplayer_gst_element_t *mainbin = NULL;
6064 GstElement *decodebin = NULL;
6065 GstElement *queue2 = NULL;
6066 GstPad *sinkpad = NULL;
6067 GstPad *qsrcpad = NULL;
6070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6072 mainbin = player->pipeline->mainbin;
6074 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6076 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6077 LOGW("need to check: muxed buffer is not null");
6080 queue2 = __mmplayer_gst_make_queue2(player);
6082 LOGE("failed to make queue2");
6086 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6087 LOGE("failed to add buffering queue");
6091 sinkpad = gst_element_get_static_pad(queue2, "sink");
6092 qsrcpad = gst_element_get_static_pad(queue2, "src");
6094 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6095 LOGE("failed to link [%s:%s]-[%s:%s]",
6096 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6100 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6101 LOGE("failed to sync queue2 state with parent");
6105 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6106 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6110 gst_object_unref(GST_OBJECT(sinkpad));
6114 /* create decodebin */
6115 decodebin = _mmplayer_gst_make_decodebin(player);
6117 LOGE("failed to make decodebin");
6121 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6122 LOGE("failed to add decodebin");
6126 /* to force caps on the decodebin element and avoid reparsing stuff by
6127 * typefind. It also avoids a deadlock in the way typefind activates pads in
6128 * the state change */
6129 g_object_set(decodebin, "sink-caps", caps, NULL);
6131 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6133 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6134 LOGE("failed to link [%s:%s]-[%s:%s]",
6135 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6139 gst_object_unref(GST_OBJECT(sinkpad));
6141 gst_object_unref(GST_OBJECT(qsrcpad));
6144 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6145 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6147 /* set decodebin property about buffer in streaming playback. *
6148 * in case of HLS/DASH, it does not need to have big buffer *
6149 * because it is kind of adaptive streaming. */
6150 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6151 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6152 gint high_percent = 0;
6154 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6155 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6157 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6159 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6161 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6162 "high-percent", high_percent,
6163 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6164 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6165 "max-size-buffers", 0, NULL); // disable or automatic
6168 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6169 LOGE("failed to sync decodebin state with parent");
6180 gst_object_unref(GST_OBJECT(sinkpad));
6183 gst_object_unref(GST_OBJECT(qsrcpad));
6186 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6187 * You need to explicitly set elements to the NULL state before
6188 * dropping the final reference, to allow them to clean up.
6190 gst_element_set_state(queue2, GST_STATE_NULL);
6192 /* And, it still has a parent "player".
6193 * You need to let the parent manage the object instead of unreffing the object directly.
6195 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6196 gst_object_unref(queue2);
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(decodebin, 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.
6211 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6212 gst_object_unref(decodebin);
6220 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6225 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6227 LOGD("class : %s, mime : %s", factory_class, mime);
6229 /* add missing plugin */
6230 /* NOTE : msl should check missing plugin for image mime type.
6231 * Some motion jpeg clips can have playable audio track.
6232 * So, msl have to play audio after displaying popup written video format not supported.
6234 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6235 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6236 LOGD("not found demuxer");
6237 player->not_found_demuxer = TRUE;
6238 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6244 if (!g_strrstr(factory_class, "Demuxer")) {
6245 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6246 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6247 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6249 /* check that clip have multi tracks or not */
6250 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6251 LOGD("video plugin is already linked");
6253 LOGW("add VIDEO to missing plugin");
6254 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6255 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6257 } else if (g_str_has_prefix(mime, "audio")) {
6258 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6259 LOGD("audio plugin is already linked");
6261 LOGW("add AUDIO to missing plugin");
6262 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6263 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6271 return MM_ERROR_NONE;
6275 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6277 mmplayer_t *player = (mmplayer_t *)data;
6281 MMPLAYER_RETURN_IF_FAIL(player);
6283 /* remove fakesink. */
6284 if (!_mmplayer_gst_remove_fakesink(player,
6285 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6286 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6287 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6288 * source element are not same. To overcome this situation, this function will called
6289 * several places and several times. Therefore, this is not an error case.
6294 LOGD("[handle: %p] pipeline has completely constructed", player);
6296 if ((player->msg_posted == FALSE) &&
6297 (player->cmd >= MMPLAYER_COMMAND_START))
6298 __mmplayer_handle_missed_plugin(player);
6300 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6304 __mmplayer_check_profile(void)
6307 static int profile_tv = -1;
6309 if (__builtin_expect(profile_tv != -1, 1))
6312 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6313 switch (*profileName) {
6328 __mmplayer_get_next_uri(mmplayer_t *player)
6330 mmplayer_parse_profile_t profile;
6332 guint num_of_list = 0;
6335 num_of_list = g_list_length(player->uri_info.uri_list);
6336 uri_idx = player->uri_info.uri_idx;
6338 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6339 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6340 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6342 LOGW("next uri does not exist");
6346 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6347 LOGE("failed to parse profile");
6351 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6352 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6353 LOGW("uri type is not supported(%d)", profile.uri_type);
6357 LOGD("success to find next uri %d", uri_idx);
6361 if (!uri || uri_idx == num_of_list) {
6362 LOGE("failed to find next uri");
6366 player->uri_info.uri_idx = uri_idx;
6367 if (mm_player_set_attribute((MMHandleType)player, NULL,
6368 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6369 LOGE("failed to set attribute");
6373 SECURE_LOGD("next playback uri: %s", uri);
6378 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6380 #define REPEAT_COUNT_INFINITE -1
6381 #define REPEAT_COUNT_MIN 2
6382 #define ORIGINAL_URI_ONLY 1
6384 MMHandleType attrs = 0;
6388 guint num_of_uri = 0;
6389 int profile_tv = -1;
6393 LOGD("checking for gapless play option");
6395 if (player->build_audio_offload) {
6396 LOGE("offload path is not supportable.");
6400 if (player->pipeline->textbin) {
6401 LOGE("subtitle path is enabled. gapless play is not supported.");
6405 attrs = MMPLAYER_GET_ATTRS(player);
6407 LOGE("fail to get attributes.");
6411 mm_attrs_multiple_get(player->attrs, NULL,
6412 "content_video_found", &video,
6413 "profile_play_count", &count,
6414 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6416 /* gapless playback is not supported in case of video at TV profile. */
6417 profile_tv = __mmplayer_check_profile();
6418 if (profile_tv && video) {
6419 LOGW("not support video gapless playback");
6423 /* check repeat count in case of audio */
6425 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6426 LOGW("gapless is disabled");
6430 num_of_uri = g_list_length(player->uri_info.uri_list);
6432 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6434 if (num_of_uri == ORIGINAL_URI_ONLY) {
6435 /* audio looping path */
6436 if (count >= REPEAT_COUNT_MIN) {
6437 /* decrease play count */
6438 /* we succeeded to rewind. update play count and then wait for next EOS */
6440 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6441 } else if (count != REPEAT_COUNT_INFINITE) {
6442 LOGD("there is no next uri and no repeat");
6445 LOGD("looping cnt %d", count);
6447 /* gapless playback path */
6448 if (!__mmplayer_get_next_uri(player)) {
6449 LOGE("failed to get next uri");
6456 LOGE("unable to play gapless path. EOS will be posted soon");
6461 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6463 mmplayer_selector_t *selector = &player->selector[type];
6464 mmplayer_gst_element_t *sinkbin = NULL;
6465 main_element_id_e selectorId = MMPLAYER_M_NUM;
6466 main_element_id_e sinkId = MMPLAYER_M_NUM;
6467 GstPad *srcpad = NULL;
6468 GstPad *sinkpad = NULL;
6469 gboolean send_notice = FALSE;
6472 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6474 LOGD("type %d", type);
6477 case MM_PLAYER_TRACK_TYPE_AUDIO:
6478 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6479 sinkId = MMPLAYER_A_BIN;
6480 sinkbin = player->pipeline->audiobin;
6482 case MM_PLAYER_TRACK_TYPE_VIDEO:
6483 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6484 sinkId = MMPLAYER_V_BIN;
6485 sinkbin = player->pipeline->videobin;
6488 case MM_PLAYER_TRACK_TYPE_TEXT:
6489 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6490 sinkId = MMPLAYER_T_BIN;
6491 sinkbin = player->pipeline->textbin;
6494 LOGE("requested type is not supportable");
6499 if (player->pipeline->mainbin[selectorId].gst) {
6502 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6504 if (selector->event_probe_id != 0)
6505 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6506 selector->event_probe_id = 0;
6508 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6509 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6511 if (srcpad && sinkpad) {
6512 /* after getting drained signal there is no data flows, so no need to do pad_block */
6513 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6514 gst_pad_unlink(srcpad, sinkpad);
6516 /* send custom event to sink pad to handle it at video sink */
6518 LOGD("send custom event to sinkpad");
6519 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6520 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6521 gst_pad_send_event(sinkpad, event);
6525 gst_object_unref(sinkpad);
6528 gst_object_unref(srcpad);
6531 LOGD("selector release");
6533 /* release and unref requests pad from the selector */
6534 for (n = 0; n < selector->channels->len; n++) {
6535 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6536 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6538 g_ptr_array_set_size(selector->channels, 0);
6540 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6541 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6543 player->pipeline->mainbin[selectorId].gst = NULL;
6551 __mmplayer_deactivate_old_path(mmplayer_t *player)
6554 MMPLAYER_RETURN_IF_FAIL(player);
6556 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6557 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6558 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6559 LOGE("deactivate selector error");
6563 _mmplayer_track_destroy(player);
6564 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6566 if (player->streamer) {
6567 _mm_player_streaming_initialize(player->streamer, FALSE);
6568 _mm_player_streaming_destroy(player->streamer);
6569 player->streamer = NULL;
6572 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6578 if (!player->msg_posted) {
6579 MMMessageParamType msg = {0,};
6582 msg.code = MM_ERROR_PLAYER_INTERNAL;
6583 LOGE("gapless_uri_play> deactivate error");
6585 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6586 player->msg_posted = TRUE;
6592 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6594 int result = MM_ERROR_NONE;
6595 mmplayer_t *player = (mmplayer_t *)hplayer;
6598 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6599 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6601 if (mm_player_set_attribute(hplayer, NULL,
6602 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6603 LOGE("failed to set attribute");
6604 result = MM_ERROR_PLAYER_INTERNAL;
6606 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6607 LOGE("failed to add the original uri in the uri list.");
6615 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6617 mmplayer_t *player = (mmplayer_t *)hplayer;
6618 guint num_of_list = 0;
6622 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6623 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6625 if (player->pipeline && player->pipeline->textbin) {
6626 LOGE("subtitle path is enabled.");
6627 return MM_ERROR_PLAYER_INVALID_STATE;
6630 num_of_list = g_list_length(player->uri_info.uri_list);
6632 if (is_first_path) {
6633 if (num_of_list == 0) {
6634 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6635 SECURE_LOGD("add original path : %s", uri);
6637 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6638 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6640 SECURE_LOGD("change original path : %s", uri);
6643 MMHandleType attrs = 0;
6644 attrs = MMPLAYER_GET_ATTRS(player);
6646 if (num_of_list == 0) {
6647 char *original_uri = NULL;
6650 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6652 if (!original_uri) {
6653 LOGE("there is no original uri.");
6654 return MM_ERROR_PLAYER_INVALID_STATE;
6657 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6658 player->uri_info.uri_idx = 0;
6660 SECURE_LOGD("add original path at first : %s", original_uri);
6664 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6665 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6669 return MM_ERROR_NONE;
6673 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6675 mmplayer_t *player = (mmplayer_t *)hplayer;
6676 char *next_uri = NULL;
6677 guint num_of_list = 0;
6680 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6682 num_of_list = g_list_length(player->uri_info.uri_list);
6684 if (num_of_list > 0) {
6685 gint uri_idx = player->uri_info.uri_idx;
6687 if (uri_idx < num_of_list-1)
6692 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6693 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6695 *uri = g_strdup(next_uri);
6699 return MM_ERROR_NONE;
6703 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6704 GstCaps *caps, gpointer data)
6706 mmplayer_t *player = (mmplayer_t *)data;
6707 const gchar *klass = NULL;
6708 const gchar *mime = NULL;
6709 gchar *caps_str = NULL;
6711 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6712 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6713 caps_str = gst_caps_to_string(caps);
6715 LOGW("unknown type of caps : %s from %s",
6716 caps_str, GST_ELEMENT_NAME(elem));
6718 MMPLAYER_FREEIF(caps_str);
6720 /* There is no available codec. */
6721 __mmplayer_check_not_supported_codec(player, klass, mime);
6725 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6726 GstCaps *caps, gpointer data)
6728 mmplayer_t *player = (mmplayer_t *)data;
6729 const char *mime = NULL;
6730 gboolean ret = TRUE;
6732 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6733 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6735 if (g_str_has_prefix(mime, "audio")) {
6736 GstStructure *caps_structure = NULL;
6737 gint samplerate = 0;
6739 gchar *caps_str = NULL;
6741 caps_structure = gst_caps_get_structure(caps, 0);
6742 gst_structure_get_int(caps_structure, "rate", &samplerate);
6743 gst_structure_get_int(caps_structure, "channels", &channels);
6745 if ((channels > 0 && samplerate == 0)) {
6746 LOGD("exclude audio...");
6750 caps_str = gst_caps_to_string(caps);
6751 /* set it directly because not sent by TAG */
6752 if (g_strrstr(caps_str, "mobile-xmf"))
6753 mm_player_set_attribute((MMHandleType)player, NULL,
6754 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6756 MMPLAYER_FREEIF(caps_str);
6757 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6758 LOGD("already video linked");
6761 LOGD("found new stream");
6768 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6770 gboolean ret = FALSE;
6771 GDBusConnection *conn = NULL;
6773 GVariant *result = NULL;
6774 const gchar *dbus_device_type = NULL;
6775 const gchar *dbus_ret = NULL;
6778 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6780 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6785 result = g_dbus_connection_call_sync(conn,
6786 "org.pulseaudio.Server",
6787 "/org/pulseaudio/StreamManager",
6788 "org.pulseaudio.StreamManager",
6789 "GetCurrentMediaRoutingPath",
6790 g_variant_new("(s)", "out"),
6791 G_VARIANT_TYPE("(ss)"),
6792 G_DBUS_CALL_FLAGS_NONE,
6796 if (!result || err) {
6797 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6802 /* device type is listed in stream-map.json at mmfw-sysconf */
6803 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6805 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6806 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6809 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6810 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6811 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6812 LOGD("audio offload is supportable");
6818 LOGD("audio offload is not supportable");
6821 g_variant_unref(result);
6823 g_object_unref(conn);
6828 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6830 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6831 gint64 position = 0;
6833 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6834 player->pipeline && player->pipeline->mainbin);
6836 MMPLAYER_CMD_LOCK(player);
6837 current_state = MMPLAYER_CURRENT_STATE(player);
6839 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6840 LOGW("getting current position failed in paused");
6842 _mmplayer_unrealize((MMHandleType)player);
6843 _mmplayer_realize((MMHandleType)player);
6845 _mmplayer_set_position((MMHandleType)player, position);
6847 /* async not to be blocked in streaming case */
6848 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6850 _mmplayer_pause((MMHandleType)player);
6852 if (current_state == MM_PLAYER_STATE_PLAYING)
6853 _mmplayer_start((MMHandleType)player);
6854 MMPLAYER_CMD_UNLOCK(player);
6856 LOGD("rebuilding audio pipeline is completed.");
6859 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6861 mmplayer_t *player = (mmplayer_t *)user_data;
6862 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6863 gboolean is_supportable = FALSE;
6865 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6866 LOGW("failed to get device type");
6868 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6870 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6871 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6872 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6873 LOGD("ignore this dev connected info");
6877 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6878 if (player->build_audio_offload == is_supportable) {
6879 LOGD("keep current pipeline without re-building");
6883 /* rebuild pipeline */
6884 LOGD("re-build pipeline - offload: %d", is_supportable);
6885 player->build_audio_offload = FALSE;
6886 __mmplayer_rebuild_audio_pipeline(player);
6892 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6894 unsigned int id = 0;
6896 if (player->audio_device_cb_id != 0) {
6897 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6901 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6902 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6903 LOGD("added device connected cb (%u)", id);
6904 player->audio_device_cb_id = id;
6906 LOGW("failed to add device connected cb");
6913 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6915 mmplayer_t *player = (mmplayer_t *)hplayer;
6918 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6919 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6921 *activated = player->build_audio_offload;
6923 LOGD("offload activated : %d", (int)*activated);
6926 return MM_ERROR_NONE;
6930 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6933 this function need to be updated according to the supported media format
6934 @see player->ini.audio_offload_media_format */
6936 if (__mmplayer_is_only_mp3_type(player->type)) {
6937 LOGD("offload supportable media format type");
6945 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6947 gboolean ret = FALSE;
6948 GstElementFactory *factory = NULL;
6951 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6953 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6954 if (!__mmplayer_is_offload_supported_type(player))
6957 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6958 LOGD("there is no audio offload sink");
6962 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6963 LOGW("there is no audio device type to support offload");
6967 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6969 LOGW("there is no installed audio offload sink element");
6972 gst_object_unref(factory);
6974 if (__mmplayer_acquire_hw_resource(player,
6975 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6976 LOGE("failed to acquire audio offload decoder resource");
6980 if (!__mmplayer_add_audio_device_connected_cb(player))
6983 if (!__mmplayer_is_audio_offload_device_type(player))
6986 LOGD("audio offload can be built");
6991 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6997 static GstAutoplugSelectResult
6998 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7000 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7001 int audio_offload = 0;
7003 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7004 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7006 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7007 LOGD("expose audio path to build offload output path");
7008 player->build_audio_offload = TRUE;
7009 /* update codec info */
7010 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7011 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7012 player->audiodec_linked = 1;
7014 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7018 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7019 And need to consider the multi-track audio content.
7020 There is no HW audio decoder in public. */
7022 /* set stream information */
7023 if (!player->audiodec_linked)
7024 __mmplayer_set_audio_attrs(player, caps);
7026 /* update codec info */
7027 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7028 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7029 player->audiodec_linked = 1;
7031 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7033 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7034 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7036 /* mark video decoder for acquire */
7037 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7038 LOGW("video decoder resource is already acquired, skip it.");
7039 ret = GST_AUTOPLUG_SELECT_SKIP;
7043 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7044 LOGE("failed to acquire video decoder resource");
7045 ret = GST_AUTOPLUG_SELECT_SKIP;
7048 player->interrupted_by_resource = FALSE;
7051 /* update codec info */
7052 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7053 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7054 player->videodec_linked = 1;
7062 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7063 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7065 #define DEFAULT_IDX 0xFFFF
7066 #define MIN_FACTORY_NUM 2
7067 mmplayer_t *player = (mmplayer_t *)data;
7068 GValueArray *new_factories = NULL;
7069 GValue val = { 0, };
7070 GstElementFactory *factory = NULL;
7071 const gchar *klass = NULL;
7072 gchar *factory_name = NULL;
7073 guint hw_dec_idx = DEFAULT_IDX;
7074 guint first_sw_dec_idx = DEFAULT_IDX;
7075 guint last_sw_dec_idx = DEFAULT_IDX;
7076 guint new_pos = DEFAULT_IDX;
7077 guint rm_pos = DEFAULT_IDX;
7078 int audio_codec_type;
7079 int video_codec_type;
7080 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7082 if (factories->n_values < MIN_FACTORY_NUM)
7085 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7086 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7089 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7091 for (int i = 0 ; i < factories->n_values ; i++) {
7092 gchar *hw_dec_info = NULL;
7093 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7095 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7097 LOGW("failed to get factory object");
7100 klass = gst_element_factory_get_klass(factory);
7101 factory_name = GST_OBJECT_NAME(factory);
7104 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7106 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7107 if (!player->need_audio_dec_sorting) {
7108 LOGD("sorting is not required");
7111 codec_type = audio_codec_type;
7112 hw_dec_info = player->ini.audiocodec_element_hw;
7113 sw_dec_info = player->ini.audiocodec_element_sw;
7114 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7115 if (!player->need_video_dec_sorting) {
7116 LOGD("sorting is not required");
7119 codec_type = video_codec_type;
7120 hw_dec_info = player->ini.videocodec_element_hw;
7121 sw_dec_info = player->ini.videocodec_element_sw;
7126 if (g_strrstr(factory_name, hw_dec_info)) {
7129 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7130 if (strstr(factory_name, sw_dec_info[j])) {
7131 last_sw_dec_idx = i;
7132 if (first_sw_dec_idx == DEFAULT_IDX) {
7133 first_sw_dec_idx = i;
7138 if (first_sw_dec_idx == DEFAULT_IDX)
7139 LOGW("unknown codec %s", factory_name);
7143 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7146 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7147 if (hw_dec_idx < first_sw_dec_idx)
7149 new_pos = first_sw_dec_idx;
7150 rm_pos = hw_dec_idx + 1;
7151 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7152 if (last_sw_dec_idx < hw_dec_idx)
7154 new_pos = last_sw_dec_idx + 1;
7155 rm_pos = hw_dec_idx;
7160 /* change position - insert H/W decoder according to the new position */
7161 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7163 LOGW("failed to get factory object");
7166 new_factories = g_value_array_copy(factories);
7167 g_value_init (&val, G_TYPE_OBJECT);
7168 g_value_set_object (&val, factory);
7169 g_value_array_insert(new_factories, new_pos, &val);
7170 g_value_unset (&val);
7171 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7173 for (int i = 0 ; i < new_factories->n_values ; i++) {
7174 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7176 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7177 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7179 LOGE("[Re-arranged] failed to get factory object");
7182 return new_factories;
7186 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7187 GstCaps *caps, GstElementFactory *factory, gpointer data)
7189 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7190 mmplayer_t *player = (mmplayer_t *)data;
7192 gchar *factory_name = NULL;
7193 gchar *caps_str = NULL;
7194 const gchar *klass = NULL;
7197 factory_name = GST_OBJECT_NAME(factory);
7198 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7199 caps_str = gst_caps_to_string(caps);
7201 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7203 /* store type string */
7204 if (player->type == NULL) {
7205 player->type = gst_caps_to_string(caps);
7206 __mmplayer_update_content_type_info(player);
7209 /* filtering exclude keyword */
7210 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7211 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7212 LOGW("skipping [%s] by exculde keyword [%s]",
7213 factory_name, player->ini.exclude_element_keyword[idx]);
7215 result = GST_AUTOPLUG_SELECT_SKIP;
7220 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7221 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7222 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7223 factory_name, player->ini.unsupported_codec_keyword[idx]);
7224 result = GST_AUTOPLUG_SELECT_SKIP;
7229 /* exclude webm format */
7230 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7231 * because webm format is not supportable.
7232 * If webm is disabled in "autoplug-continue", there is no state change
7233 * failure or error because the decodebin will expose the pad directly.
7234 * It make MSL invoke _prepare_async_callback.
7235 * So, we need to disable webm format in "autoplug-select" */
7236 if (caps_str && strstr(caps_str, "webm")) {
7237 LOGW("webm is not supported");
7238 result = GST_AUTOPLUG_SELECT_SKIP;
7242 /* check factory class for filtering */
7243 /* NOTE : msl don't need to use image plugins.
7244 * So, those plugins should be skipped for error handling.
7246 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7247 LOGD("skipping [%s] by not required", factory_name);
7248 result = GST_AUTOPLUG_SELECT_SKIP;
7252 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7253 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7254 // TO CHECK : subtitle if needed, add subparse exception.
7255 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7256 result = GST_AUTOPLUG_SELECT_SKIP;
7260 if (g_strrstr(factory_name, "mpegpsdemux")) {
7261 LOGD("skipping PS container - not support");
7262 result = GST_AUTOPLUG_SELECT_SKIP;
7266 if (g_strrstr(factory_name, "mssdemux"))
7267 player->smooth_streaming = TRUE;
7269 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7270 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7273 GstStructure *str = NULL;
7274 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7276 /* don't make video because of not required */
7277 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7278 (!player->set_mode.video_export)) {
7279 LOGD("no need video decoding, expose pad");
7280 result = GST_AUTOPLUG_SELECT_EXPOSE;
7284 /* get w/h for omx state-tune */
7285 /* FIXME: deprecated? */
7286 str = gst_caps_get_structure(caps, 0);
7287 gst_structure_get_int(str, "width", &width);
7290 if (player->v_stream_caps) {
7291 gst_caps_unref(player->v_stream_caps);
7292 player->v_stream_caps = NULL;
7295 player->v_stream_caps = gst_caps_copy(caps);
7296 LOGD("take caps for video state tune");
7297 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7301 if (g_strrstr(klass, "Codec/Decoder")) {
7302 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7303 if (result != GST_AUTOPLUG_SELECT_TRY) {
7304 LOGW("skip add decoder");
7310 MMPLAYER_FREEIF(caps_str);
7316 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7319 //mmplayer_t *player = (mmplayer_t *)data;
7320 GstCaps *caps = NULL;
7322 LOGD("[Decodebin2] pad-removed signal");
7324 caps = gst_pad_query_caps(new_pad, NULL);
7326 LOGW("query caps is NULL");
7330 gchar *caps_str = NULL;
7331 caps_str = gst_caps_to_string(caps);
7333 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7335 MMPLAYER_FREEIF(caps_str);
7336 gst_caps_unref(caps);
7340 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7342 mmplayer_t *player = (mmplayer_t *)data;
7343 GstIterator *iter = NULL;
7344 GValue item = { 0, };
7346 gboolean done = FALSE;
7347 gboolean is_all_drained = TRUE;
7350 MMPLAYER_RETURN_IF_FAIL(player);
7352 LOGD("__mmplayer_gst_decode_drained");
7354 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7355 LOGW("Fail to get cmd lock");
7359 if (!__mmplayer_verify_gapless_play_path(player)) {
7360 LOGD("decoding is finished.");
7361 MMPLAYER_CMD_UNLOCK(player);
7365 _mmplayer_set_reconfigure_state(player, TRUE);
7366 MMPLAYER_CMD_UNLOCK(player);
7368 /* check decodebin src pads whether they received EOS or not */
7369 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7372 switch (gst_iterator_next(iter, &item)) {
7373 case GST_ITERATOR_OK:
7374 pad = g_value_get_object(&item);
7375 if (pad && !GST_PAD_IS_EOS(pad)) {
7376 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7377 is_all_drained = FALSE;
7380 g_value_reset(&item);
7382 case GST_ITERATOR_RESYNC:
7383 gst_iterator_resync(iter);
7385 case GST_ITERATOR_ERROR:
7386 case GST_ITERATOR_DONE:
7391 g_value_unset(&item);
7392 gst_iterator_free(iter);
7394 if (!is_all_drained) {
7395 LOGD("Wait util the all pads get EOS.");
7400 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7401 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7403 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7404 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7405 __mmplayer_deactivate_old_path(player);
7411 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7413 mmplayer_t *player = (mmplayer_t *)data;
7414 const gchar *klass = NULL;
7415 gchar *factory_name = NULL;
7417 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7418 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7420 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7422 if (__mmplayer_add_dump_buffer_probe(player, element))
7423 LOGD("add buffer probe");
7425 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7426 gchar *selected = NULL;
7427 selected = g_strdup(GST_ELEMENT_NAME(element));
7428 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7431 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7432 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7433 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7435 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7436 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7438 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7439 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7440 "max-video-width", player->adaptive_info.limit.width,
7441 "max-video-height", player->adaptive_info.limit.height, NULL);
7443 } else if (g_strrstr(klass, "Demuxer")) {
7445 LOGD("plugged element is demuxer. take it");
7447 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7448 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7451 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7452 int surface_type = 0;
7454 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7457 // to support trust-zone only
7458 if (g_strrstr(factory_name, "asfdemux")) {
7459 LOGD("set file-location %s", player->profile.uri);
7460 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7461 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7462 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7463 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7464 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7465 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7466 (__mmplayer_is_only_mp3_type(player->type))) {
7467 LOGD("[mpegaudioparse] set streaming pull mode.");
7468 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7470 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7471 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7474 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7475 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7476 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7478 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7479 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7481 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7482 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7483 (MMPLAYER_IS_DASH_STREAMING(player))) {
7484 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7485 _mm_player_streaming_set_multiqueue(player->streamer, element);
7486 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7495 __mmplayer_release_misc(mmplayer_t *player)
7498 bool cur_mode = player->set_mode.rich_audio;
7501 MMPLAYER_RETURN_IF_FAIL(player);
7503 player->sent_bos = FALSE;
7504 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7506 player->seek_state = MMPLAYER_SEEK_NONE;
7508 player->total_bitrate = 0;
7509 player->total_maximum_bitrate = 0;
7511 player->not_found_demuxer = 0;
7513 player->last_position = 0;
7514 player->duration = 0;
7515 player->http_content_size = 0;
7516 player->not_supported_codec = MISSING_PLUGIN_NONE;
7517 player->can_support_codec = FOUND_PLUGIN_NONE;
7518 player->pending_seek.is_pending = false;
7519 player->pending_seek.pos = 0;
7520 player->msg_posted = FALSE;
7521 player->has_many_types = FALSE;
7522 player->is_subtitle_force_drop = FALSE;
7523 player->play_subtitle = FALSE;
7524 player->adjust_subtitle_pos = 0;
7525 player->has_closed_caption = FALSE;
7526 player->set_mode.video_export = false;
7527 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7528 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7530 player->set_mode.rich_audio = cur_mode;
7532 if (player->audio_device_cb_id > 0 &&
7533 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7534 LOGW("failed to remove audio device_connected_callback");
7535 player->audio_device_cb_id = 0;
7537 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7538 player->bitrate[i] = 0;
7539 player->maximum_bitrate[i] = 0;
7542 /* free memory related to audio effect */
7543 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7545 if (player->adaptive_info.var_list) {
7546 g_list_free_full(player->adaptive_info.var_list, g_free);
7547 player->adaptive_info.var_list = NULL;
7550 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7551 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7552 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7554 /* Reset video360 settings to their defaults in case if the pipeline is to be
7557 player->video360_metadata.is_spherical = -1;
7558 player->is_openal_plugin_used = FALSE;
7560 player->is_content_spherical = FALSE;
7561 player->is_video360_enabled = TRUE;
7562 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7563 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7564 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7565 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7566 player->video360_zoom = 1.0f;
7567 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7568 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7570 player->sound.rg_enable = false;
7572 __mmplayer_initialize_video_roi(player);
7577 __mmplayer_release_misc_post(mmplayer_t *player)
7579 char *original_uri = NULL;
7582 /* player->pipeline is already released before. */
7583 MMPLAYER_RETURN_IF_FAIL(player);
7585 player->video_decoded_cb = NULL;
7586 player->video_decoded_cb_user_param = NULL;
7587 player->video_stream_prerolled = false;
7589 player->audio_decoded_cb = NULL;
7590 player->audio_decoded_cb_user_param = NULL;
7591 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7593 player->audio_stream_changed_cb = NULL;
7594 player->audio_stream_changed_cb_user_param = NULL;
7596 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7598 /* clean found audio decoders */
7599 if (player->audio_decoders) {
7600 GList *a_dec = player->audio_decoders;
7601 for (; a_dec; a_dec = g_list_next(a_dec)) {
7602 gchar *name = a_dec->data;
7603 MMPLAYER_FREEIF(name);
7605 g_list_free(player->audio_decoders);
7606 player->audio_decoders = NULL;
7609 /* clean the uri list except original uri */
7610 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7611 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7613 LOGW("failed to get original uri info");
7615 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7616 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7618 GList *uri_list = player->uri_info.uri_list;
7619 for (; uri_list; uri_list = g_list_next(uri_list)) {
7620 gchar *uri = uri_list->data;
7621 if (original_uri != uri)
7622 MMPLAYER_FREEIF(uri);
7626 /* clear the audio stream buffer list */
7627 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7629 /* clear the video stream bo list */
7630 __mmplayer_video_stream_destroy_bo_list(player);
7631 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7633 if (player->profile.input_mem.buf) {
7634 free(player->profile.input_mem.buf);
7635 player->profile.input_mem.buf = NULL;
7637 player->profile.input_mem.len = 0;
7638 player->profile.input_mem.offset = 0;
7640 player->uri_info.uri_idx = 0;
7645 __mmplayer_check_subtitle(mmplayer_t *player)
7647 MMHandleType attrs = 0;
7648 char *subtitle_uri = NULL;
7652 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7654 /* get subtitle attribute */
7655 attrs = MMPLAYER_GET_ATTRS(player);
7659 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7660 if (!subtitle_uri || !strlen(subtitle_uri))
7663 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7664 player->is_external_subtitle_present = TRUE;
7672 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7674 MMPLAYER_RETURN_IF_FAIL(player);
7676 if (player->eos_timer) {
7677 LOGD("cancel eos timer");
7678 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7679 player->eos_timer = 0;
7686 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7690 MMPLAYER_RETURN_IF_FAIL(player);
7691 MMPLAYER_RETURN_IF_FAIL(sink);
7693 player->sink_elements = g_list_append(player->sink_elements, sink);
7699 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7703 MMPLAYER_RETURN_IF_FAIL(player);
7704 MMPLAYER_RETURN_IF_FAIL(sink);
7706 player->sink_elements = g_list_remove(player->sink_elements, sink);
7712 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7713 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7715 mmplayer_signal_item_t *item = NULL;
7718 MMPLAYER_RETURN_IF_FAIL(player);
7720 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7721 LOGE("invalid signal type [%d]", type);
7725 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7727 LOGE("cannot connect signal [%s]", signal);
7732 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7733 player->signals[type] = g_list_append(player->signals[type], item);
7739 /* NOTE : be careful with calling this api. please refer to below glib comment
7740 * glib comment : Note that there is a bug in GObject that makes this function much
7741 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7742 * will no longer be called, but, the signal handler is not currently disconnected.
7743 * If the instance is itself being freed at the same time than this doesn't matter,
7744 * since the signal will automatically be removed, but if instance persists,
7745 * then the signal handler will leak. You should not remove the signal yourself
7746 * because in a future versions of GObject, the handler will automatically be
7749 * It's possible to work around this problem in a way that will continue to work
7750 * with future versions of GObject by checking that the signal handler is still
7751 * connected before disconnected it:
7753 * if (g_signal_handler_is_connected(instance, id))
7754 * g_signal_handler_disconnect(instance, id);
7757 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7759 GList *sig_list = NULL;
7760 mmplayer_signal_item_t *item = NULL;
7764 MMPLAYER_RETURN_IF_FAIL(player);
7766 LOGD("release signals type : %d", type);
7768 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7769 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7770 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7771 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7772 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7773 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7777 sig_list = player->signals[type];
7779 for (; sig_list; sig_list = sig_list->next) {
7780 item = sig_list->data;
7782 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7783 if (g_signal_handler_is_connected(item->obj, item->sig))
7784 g_signal_handler_disconnect(item->obj, item->sig);
7787 MMPLAYER_FREEIF(item);
7790 g_list_free(player->signals[type]);
7791 player->signals[type] = NULL;
7799 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7801 mmplayer_t *player = 0;
7802 int prev_display_surface_type = 0;
7806 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7808 player = MM_PLAYER_CAST(handle);
7810 /* check video sinkbin is created */
7811 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7812 LOGW("Videosink is already created");
7813 return MM_ERROR_NONE;
7816 LOGD("videosink element is not yet ready");
7818 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7819 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7821 return MM_ERROR_INVALID_ARGUMENT;
7824 /* load previous attributes */
7825 if (player->attrs) {
7826 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7827 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7828 if (prev_display_surface_type == surface_type) {
7829 LOGD("incoming display surface type is same as previous one, do nothing..");
7831 return MM_ERROR_NONE;
7834 LOGE("failed to load attributes");
7836 return MM_ERROR_PLAYER_INTERNAL;
7839 /* videobin is not created yet, so we just set attributes related to display surface */
7840 LOGD("store display attribute for given surface type(%d)", surface_type);
7841 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7842 "display_overlay", wl_surface_id, NULL);
7845 return MM_ERROR_NONE;
7848 /* Note : if silent is true, then subtitle would not be displayed. :*/
7850 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7852 mmplayer_t *player = (mmplayer_t *)hplayer;
7856 /* check player handle */
7857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7859 player->set_mode.subtitle_off = silent;
7861 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7865 return MM_ERROR_NONE;
7869 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7871 mmplayer_gst_element_t *mainbin = NULL;
7872 mmplayer_gst_element_t *textbin = NULL;
7873 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7874 GstState current_state = GST_STATE_VOID_PENDING;
7875 GstState element_state = GST_STATE_VOID_PENDING;
7876 GstState element_pending_state = GST_STATE_VOID_PENDING;
7878 GstEvent *event = NULL;
7879 int result = MM_ERROR_NONE;
7881 GstClock *curr_clock = NULL;
7882 GstClockTime base_time, start_time, curr_time;
7887 /* check player handle */
7888 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7890 player->pipeline->mainbin &&
7891 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7893 mainbin = player->pipeline->mainbin;
7894 textbin = player->pipeline->textbin;
7896 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7898 // sync clock with current pipeline
7899 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7900 curr_time = gst_clock_get_time(curr_clock);
7902 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7903 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7905 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7906 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7908 if (current_state > GST_STATE_READY) {
7909 // sync state with current pipeline
7910 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7911 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7912 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7914 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7915 if (GST_STATE_CHANGE_FAILURE == ret) {
7916 LOGE("fail to state change.");
7917 result = MM_ERROR_PLAYER_INTERNAL;
7921 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7922 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7925 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7926 gst_object_unref(curr_clock);
7929 // seek to current position
7930 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7931 result = MM_ERROR_PLAYER_INVALID_STATE;
7932 LOGE("gst_element_query_position failed, invalid state");
7936 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7937 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);
7939 _mmplayer_gst_send_event_to_sink(player, event);
7941 result = MM_ERROR_PLAYER_INTERNAL;
7942 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7946 /* sync state with current pipeline */
7947 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7948 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7949 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7951 return MM_ERROR_NONE;
7954 /* release text pipeline resource */
7955 player->textsink_linked = 0;
7957 /* release signal */
7958 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7960 /* release textbin with it's childs */
7961 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7962 MMPLAYER_FREEIF(player->pipeline->textbin);
7963 player->pipeline->textbin = NULL;
7965 /* release subtitle elem */
7966 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7967 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7973 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7975 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7976 GstState current_state = GST_STATE_VOID_PENDING;
7978 MMHandleType attrs = 0;
7979 mmplayer_gst_element_t *mainbin = NULL;
7980 mmplayer_gst_element_t *textbin = NULL;
7982 gchar *subtitle_uri = NULL;
7983 int result = MM_ERROR_NONE;
7984 const gchar *charset = NULL;
7988 /* check player handle */
7989 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7991 player->pipeline->mainbin &&
7992 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7993 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7995 mainbin = player->pipeline->mainbin;
7996 textbin = player->pipeline->textbin;
7998 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7999 if (current_state < GST_STATE_READY) {
8000 result = MM_ERROR_PLAYER_INVALID_STATE;
8001 LOGE("Pipeline is not in proper state");
8005 attrs = MMPLAYER_GET_ATTRS(player);
8007 LOGE("cannot get content attribute");
8008 result = MM_ERROR_PLAYER_INTERNAL;
8012 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8013 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8014 LOGE("subtitle uri is not proper filepath");
8015 result = MM_ERROR_PLAYER_INVALID_URI;
8019 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8020 LOGE("failed to get storage info of subtitle path");
8021 result = MM_ERROR_PLAYER_INVALID_URI;
8025 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8026 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8028 if (!strcmp(filepath, subtitle_uri)) {
8029 LOGD("subtitle path is not changed");
8032 if (mm_player_set_attribute((MMHandleType)player, NULL,
8033 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8034 LOGE("failed to set attribute");
8039 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8040 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8041 player->subtitle_language_list = NULL;
8042 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8044 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8045 if (ret != GST_STATE_CHANGE_SUCCESS) {
8046 LOGE("failed to change state of textbin to READY");
8047 result = MM_ERROR_PLAYER_INTERNAL;
8051 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8052 if (ret != GST_STATE_CHANGE_SUCCESS) {
8053 LOGE("failed to change state of subparse to READY");
8054 result = MM_ERROR_PLAYER_INTERNAL;
8058 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8059 if (ret != GST_STATE_CHANGE_SUCCESS) {
8060 LOGE("failed to change state of filesrc to READY");
8061 result = MM_ERROR_PLAYER_INTERNAL;
8065 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8067 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8069 charset = _mmplayer_get_charset(filepath);
8071 LOGD("detected charset is %s", charset);
8072 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8075 result = _mmplayer_sync_subtitle_pipeline(player);
8082 /* API to switch between external subtitles */
8084 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8086 int result = MM_ERROR_NONE;
8087 mmplayer_t *player = (mmplayer_t *)hplayer;
8092 /* check player handle */
8093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8095 /* filepath can be null in idle state */
8097 /* check file path */
8098 if ((path = strstr(filepath, "file://")))
8099 result = _mmplayer_exist_file_path(path + 7);
8101 result = _mmplayer_exist_file_path(filepath);
8103 if (result != MM_ERROR_NONE) {
8104 LOGE("invalid subtitle path 0x%X", result);
8105 return result; /* file not found or permission denied */
8109 if (!player->pipeline) {
8111 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8112 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8113 LOGE("failed to set attribute");
8114 return MM_ERROR_PLAYER_INTERNAL;
8117 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8118 /* check filepath */
8119 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8121 if (!__mmplayer_check_subtitle(player)) {
8122 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8123 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8124 LOGE("failed to set attribute");
8125 return MM_ERROR_PLAYER_INTERNAL;
8128 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8129 LOGE("fail to create text pipeline");
8130 return MM_ERROR_PLAYER_INTERNAL;
8133 result = _mmplayer_sync_subtitle_pipeline(player);
8135 result = __mmplayer_change_external_subtitle_language(player, filepath);
8138 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8139 player->is_external_subtitle_added_now = TRUE;
8141 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8142 if (!player->subtitle_language_list) {
8143 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8144 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8145 LOGW("subtitle language list is not updated yet");
8147 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8155 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8157 int result = MM_ERROR_NONE;
8158 gchar *change_pad_name = NULL;
8159 GstPad *sinkpad = NULL;
8160 mmplayer_gst_element_t *mainbin = NULL;
8161 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8162 GstCaps *caps = NULL;
8163 gint total_track_num = 0;
8167 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8168 MM_ERROR_PLAYER_NOT_INITIALIZED);
8170 LOGD("Change Track(%d) to %d", type, index);
8172 mainbin = player->pipeline->mainbin;
8174 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8175 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8176 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8177 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8179 /* Changing Video Track is not supported. */
8180 LOGE("Track Type Error");
8184 if (mainbin[elem_idx].gst == NULL) {
8185 result = MM_ERROR_PLAYER_NO_OP;
8186 LOGD("Req track doesn't exist");
8190 total_track_num = player->selector[type].total_track_num;
8191 if (total_track_num <= 0) {
8192 result = MM_ERROR_PLAYER_NO_OP;
8193 LOGD("Language list is not available");
8197 if ((index < 0) || (index >= total_track_num)) {
8198 result = MM_ERROR_INVALID_ARGUMENT;
8199 LOGD("Not a proper index : %d", index);
8203 /*To get the new pad from the selector*/
8204 change_pad_name = g_strdup_printf("sink_%u", index);
8205 if (change_pad_name == NULL) {
8206 result = MM_ERROR_PLAYER_INTERNAL;
8207 LOGD("Pad does not exists");
8211 LOGD("new active pad name: %s", change_pad_name);
8213 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8214 if (sinkpad == NULL) {
8215 LOGD("sinkpad is NULL");
8216 result = MM_ERROR_PLAYER_INTERNAL;
8220 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8221 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8223 caps = gst_pad_get_current_caps(sinkpad);
8224 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8227 gst_object_unref(sinkpad);
8229 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8230 __mmplayer_set_audio_attrs(player, caps);
8233 MMPLAYER_FREEIF(change_pad_name);
8238 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8240 int result = MM_ERROR_NONE;
8241 mmplayer_t *player = NULL;
8242 mmplayer_gst_element_t *mainbin = NULL;
8244 gint current_active_index = 0;
8246 GstState current_state = GST_STATE_VOID_PENDING;
8247 GstEvent *event = NULL;
8252 player = (mmplayer_t *)hplayer;
8253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8255 if (!player->pipeline) {
8256 LOGE("Track %d pre setting -> %d", type, index);
8258 player->selector[type].active_pad_index = index;
8262 mainbin = player->pipeline->mainbin;
8264 current_active_index = player->selector[type].active_pad_index;
8266 /*If index is same as running index no need to change the pad*/
8267 if (current_active_index == index)
8270 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8271 result = MM_ERROR_PLAYER_INVALID_STATE;
8275 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8276 if (current_state < GST_STATE_PAUSED) {
8277 result = MM_ERROR_PLAYER_INVALID_STATE;
8278 LOGW("Pipeline not in porper state");
8282 result = __mmplayer_change_selector_pad(player, type, index);
8283 if (result != MM_ERROR_NONE) {
8284 LOGE("change selector pad error");
8288 player->selector[type].active_pad_index = index;
8290 if (current_state == GST_STATE_PLAYING) {
8291 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8292 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8293 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8295 _mmplayer_gst_send_event_to_sink(player, event);
8297 result = MM_ERROR_PLAYER_INTERNAL;
8307 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8309 mmplayer_t *player = (mmplayer_t *)hplayer;
8313 /* check player handle */
8314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8316 *silent = player->set_mode.subtitle_off;
8318 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8322 return MM_ERROR_NONE;
8326 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8328 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8329 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8331 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8332 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8336 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8337 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8338 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8339 mmplayer_dump_t *dump_s;
8340 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8341 if (dump_s == NULL) {
8342 LOGE("malloc fail");
8346 dump_s->dump_element_file = NULL;
8347 dump_s->dump_pad = NULL;
8348 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8350 if (dump_s->dump_pad) {
8351 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8352 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]);
8353 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8354 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);
8355 /* add list for removed buffer probe and close FILE */
8356 player->dump_list = g_list_append(player->dump_list, dump_s);
8357 LOGD("%s sink pad added buffer probe for dump", factory_name);
8360 MMPLAYER_FREEIF(dump_s);
8361 LOGE("failed to get %s sink pad added", factory_name);
8368 static GstPadProbeReturn
8369 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8371 FILE *dump_data = (FILE *)u_data;
8373 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8374 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8376 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8378 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8380 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8382 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8384 gst_buffer_unmap(buffer, &probe_info);
8386 return GST_PAD_PROBE_OK;
8390 __mmplayer_release_dump_list(GList *dump_list)
8392 GList *d_list = dump_list;
8397 for (; d_list; d_list = g_list_next(d_list)) {
8398 mmplayer_dump_t *dump_s = d_list->data;
8399 if (dump_s->dump_pad) {
8400 if (dump_s->probe_handle_id)
8401 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8402 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8404 if (dump_s->dump_element_file) {
8405 fclose(dump_s->dump_element_file);
8406 dump_s->dump_element_file = NULL;
8408 MMPLAYER_FREEIF(dump_s);
8410 g_list_free(dump_list);
8415 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8417 mmplayer_t *player = (mmplayer_t *)hplayer;
8421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8422 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8424 *exist = (bool)player->has_closed_caption;
8428 return MM_ERROR_NONE;
8432 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8437 LOGD("unref internal gst buffer %p", buffer);
8439 gst_buffer_unref((GstBuffer *)buffer);
8446 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8448 mmplayer_t *player = (mmplayer_t *)hplayer;
8452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8453 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8455 if (MMPLAYER_IS_STREAMING(player))
8456 *timeout = (int)player->ini.live_state_change_timeout;
8458 *timeout = (int)player->ini.localplayback_state_change_timeout;
8460 LOGD("timeout = %d", *timeout);
8463 return MM_ERROR_NONE;
8467 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8471 MMPLAYER_RETURN_IF_FAIL(player);
8473 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8475 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8476 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8477 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8478 player->storage_info[i].id = -1;
8479 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8481 if (path_type != MMPLAYER_PATH_MAX)
8490 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8492 int ret = MM_ERROR_NONE;
8493 mmplayer_t *player = (mmplayer_t *)hplayer;
8494 MMMessageParamType msg_param = {0, };
8497 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8499 LOGW("state changed storage %d:%d", id, state);
8501 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8502 return MM_ERROR_NONE;
8504 /* FIXME: text path should be handled seperately. */
8505 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8506 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8507 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8508 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8509 LOGW("external storage is removed");
8511 if (player->msg_posted == FALSE) {
8512 memset(&msg_param, 0, sizeof(MMMessageParamType));
8513 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8514 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8515 player->msg_posted = TRUE;
8518 /* unrealize the player */
8519 ret = _mmplayer_unrealize(hplayer);
8520 if (ret != MM_ERROR_NONE)
8521 LOGE("failed to unrealize");
8529 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8531 int ret = MM_ERROR_NONE;
8532 mmplayer_t *player = (mmplayer_t *)hplayer;
8533 int idx = 0, total = 0;
8534 gchar *result = NULL, *tmp = NULL;
8537 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8538 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8540 total = *num = g_list_length(player->adaptive_info.var_list);
8542 LOGW("There is no stream variant info.");
8546 result = g_strdup("");
8547 for (idx = 0 ; idx < total ; idx++) {
8548 stream_variant_t *v_data = NULL;
8549 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8552 gchar data[64] = {0};
8553 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8555 tmp = g_strconcat(result, data, NULL);
8559 LOGW("There is no variant data in %d", idx);
8564 *var_info = (char *)result;
8566 LOGD("variant info %d:%s", *num, *var_info);
8572 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8574 int ret = MM_ERROR_NONE;
8575 mmplayer_t *player = (mmplayer_t *)hplayer;
8578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8580 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8582 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8583 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8584 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8586 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8587 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8588 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8589 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8591 /* FIXME: seek to current position for applying new variant limitation */
8600 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8602 int ret = MM_ERROR_NONE;
8603 mmplayer_t *player = (mmplayer_t *)hplayer;
8606 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8607 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8609 *bandwidth = player->adaptive_info.limit.bandwidth;
8610 *width = player->adaptive_info.limit.width;
8611 *height = player->adaptive_info.limit.height;
8613 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8620 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8622 int ret = MM_ERROR_NONE;
8623 mmplayer_t *player = (mmplayer_t *)hplayer;
8626 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8627 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8628 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8630 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8632 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8633 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8634 else /* live case */
8635 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8637 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8644 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8646 #define IDX_FIRST_SW_CODEC 0
8647 mmplayer_t *player = (mmplayer_t *)hplayer;
8648 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8653 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8654 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8655 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8657 switch (stream_type) {
8658 case MM_PLAYER_STREAM_TYPE_AUDIO:
8659 /* to support audio codec selection, codec info have to be added in ini file as below.
8660 audio codec element hw = xxxx
8661 audio codec element sw = avdec
8662 and in case of audio hw codec is supported and selected,
8663 audio filter elements should be applied depending on the hw capabilities.
8665 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8666 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8667 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8668 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8669 LOGE("There is no audio codec info for codec_type %d", codec_type);
8670 return MM_ERROR_PLAYER_NO_OP;
8673 case MM_PLAYER_STREAM_TYPE_VIDEO:
8674 /* to support video codec selection, codec info have to be added in ini file as below.
8675 video codec element hw = omx
8676 video codec element sw = avdec */
8677 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8678 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8679 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8680 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8681 LOGE("There is no video codec info for codec_type %d", codec_type);
8682 return MM_ERROR_PLAYER_NO_OP;
8686 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8687 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8691 LOGD("update %s codec_type to %d", attr_name, codec_type);
8692 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8695 return MM_ERROR_NONE;
8699 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8701 mmplayer_t *player = (mmplayer_t *)hplayer;
8702 GstElement *rg_vol_element = NULL;
8706 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8708 player->sound.rg_enable = enabled;
8710 /* just hold rgvolume enable value if pipeline is not ready */
8711 if (!player->pipeline || !player->pipeline->audiobin) {
8712 LOGD("pipeline is not ready. holding rgvolume enable value");
8713 return MM_ERROR_NONE;
8716 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8718 if (!rg_vol_element) {
8719 LOGD("rgvolume element is not created");
8720 return MM_ERROR_PLAYER_INTERNAL;
8724 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8726 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8730 return MM_ERROR_NONE;
8734 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8736 mmplayer_t *player = (mmplayer_t *)hplayer;
8737 GstElement *rg_vol_element = NULL;
8738 gboolean enable = FALSE;
8742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8743 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8745 /* just hold enable_rg value if pipeline is not ready */
8746 if (!player->pipeline || !player->pipeline->audiobin) {
8747 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8748 *enabled = player->sound.rg_enable;
8749 return MM_ERROR_NONE;
8752 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8754 if (!rg_vol_element) {
8755 LOGD("rgvolume element is not created");
8756 return MM_ERROR_PLAYER_INTERNAL;
8759 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8760 *enabled = (bool)enable;
8764 return MM_ERROR_NONE;
8768 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8770 mmplayer_t *player = (mmplayer_t *)hplayer;
8771 MMHandleType attrs = 0;
8773 int ret = MM_ERROR_NONE;
8777 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8779 attrs = MMPLAYER_GET_ATTRS(player);
8780 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8782 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8784 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8785 return MM_ERROR_PLAYER_INTERNAL;
8788 player->video_roi.scale_x = scale_x;
8789 player->video_roi.scale_y = scale_y;
8790 player->video_roi.scale_width = scale_width;
8791 player->video_roi.scale_height = scale_height;
8793 /* check video sinkbin is created */
8794 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8795 return MM_ERROR_NONE;
8797 if (!gst_video_overlay_set_video_roi_area(
8798 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8799 scale_x, scale_y, scale_width, scale_height))
8800 ret = MM_ERROR_PLAYER_INTERNAL;
8802 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8803 scale_x, scale_y, scale_width, scale_height);
8811 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8813 mmplayer_t *player = (mmplayer_t *)hplayer;
8814 int ret = MM_ERROR_NONE;
8818 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8819 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8821 *scale_x = player->video_roi.scale_x;
8822 *scale_y = player->video_roi.scale_y;
8823 *scale_width = player->video_roi.scale_width;
8824 *scale_height = player->video_roi.scale_height;
8826 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8827 *scale_x, *scale_y, *scale_width, *scale_height);
8833 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8835 mmplayer_t *player = (mmplayer_t *)hplayer;
8839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8841 player->client_pid = pid;
8843 LOGD("client pid[%d] %p", pid, player);
8847 return MM_ERROR_NONE;
8851 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8853 mmplayer_t *player = (mmplayer_t *)hplayer;
8854 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8855 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8860 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8863 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8865 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8867 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8868 return MM_ERROR_NONE;
8870 /* in case of audio codec default type is HW */
8872 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8873 if (player->ini.support_audio_effect)
8874 return MM_ERROR_NONE;
8875 elem_id = MMPLAYER_A_FILTER;
8877 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8878 if (player->ini.support_replaygain_control)
8879 return MM_ERROR_NONE;
8880 elem_id = MMPLAYER_A_RGVOL;
8882 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8883 if (player->ini.support_pitch_control)
8884 return MM_ERROR_NONE;
8885 elem_id = MMPLAYER_A_PITCH;
8887 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8888 if (player->ini.support_audio_effect)
8889 return MM_ERROR_NONE;
8891 /* default case handling is not required */
8894 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8895 LOGW("audio control option [%d] is not available", opt);
8898 /* setting pcm exporting option is allowed before READY state */
8899 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8900 return MM_ERROR_PLAYER_INVALID_STATE;
8902 /* check whether the audio filter exist or not after READY state,
8903 because the sw codec could be added during auto-plugging in some cases */
8904 if (!player->pipeline ||
8905 !player->pipeline->audiobin ||
8906 !player->pipeline->audiobin[elem_id].gst) {
8907 LOGW("there is no audio elem [%d]", elem_id);
8912 LOGD("audio control opt %d, available %d", opt, *available);
8916 return MM_ERROR_NONE;
8920 __mmplayer_update_duration_value(mmplayer_t *player)
8922 gboolean ret = FALSE;
8923 gint64 dur_nsec = 0;
8924 LOGD("try to update duration");
8926 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8927 player->duration = dur_nsec;
8928 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8932 if (player->duration < 0) {
8933 LOGW("duration is Non-Initialized !!!");
8934 player->duration = 0;
8937 /* update streaming service type */
8938 player->streaming_type = _mmplayer_get_stream_service_type(player);
8940 /* check duration is OK */
8941 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8942 /* FIXIT : find another way to get duration here. */
8943 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8949 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8951 /* update audio params
8952 NOTE : We need original audio params and it can be only obtained from src pad of audio
8953 decoder. Below code only valid when we are not using 'resampler' just before
8954 'audioconverter'. */
8955 GstCaps *caps_a = NULL;
8957 gint samplerate = 0, channels = 0;
8958 GstStructure *p = NULL;
8959 GstElement *aconv = NULL;
8961 LOGD("try to update audio attrs");
8963 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8965 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8966 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8967 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8968 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8970 LOGE("there is no audio converter");
8974 pad = gst_element_get_static_pad(aconv, "sink");
8977 LOGW("failed to get pad from audio converter");
8981 caps_a = gst_pad_get_current_caps(pad);
8983 LOGW("not ready to get audio caps");
8984 gst_object_unref(pad);
8988 p = gst_caps_get_structure(caps_a, 0);
8990 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8992 gst_structure_get_int(p, "rate", &samplerate);
8993 gst_structure_get_int(p, "channels", &channels);
8995 mm_player_set_attribute((MMHandleType)player, NULL,
8996 "content_audio_samplerate", samplerate,
8997 "content_audio_channels", channels, NULL);
8999 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9001 gst_caps_unref(caps_a);
9002 gst_object_unref(pad);
9008 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9010 LOGD("try to update video attrs");
9012 GstCaps *caps_v = NULL;
9016 GstStructure *p = NULL;
9018 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9019 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9021 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9023 LOGD("no videosink sink pad");
9027 caps_v = gst_pad_get_current_caps(pad);
9028 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9029 if (!caps_v && player->v_stream_caps) {
9030 caps_v = player->v_stream_caps;
9031 gst_caps_ref(caps_v);
9035 LOGD("no negitiated caps from videosink");
9036 gst_object_unref(pad);
9040 p = gst_caps_get_structure(caps_v, 0);
9041 gst_structure_get_int(p, "width", &width);
9042 gst_structure_get_int(p, "height", &height);
9044 mm_player_set_attribute((MMHandleType)player, NULL,
9045 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9047 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9049 SECURE_LOGD("width : %d height : %d", width, height);
9051 gst_caps_unref(caps_v);
9052 gst_object_unref(pad);
9055 mm_player_set_attribute((MMHandleType)player, NULL,
9056 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9057 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9064 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9066 gboolean ret = FALSE;
9067 guint64 data_size = 0;
9071 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9072 if (!player->duration)
9075 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9076 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9077 if (stat(path, &sb) == 0)
9078 data_size = (guint64)sb.st_size;
9080 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9081 data_size = player->http_content_size;
9084 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9087 guint64 bitrate = 0;
9088 guint64 msec_dur = 0;
9090 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9092 bitrate = data_size * 8 * 1000 / msec_dur;
9093 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9094 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9095 mm_player_set_attribute((MMHandleType)player, NULL,
9096 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9099 LOGD("player duration is less than 0");
9103 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9104 if (player->total_bitrate) {
9105 mm_player_set_attribute((MMHandleType)player, NULL,
9106 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9115 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9117 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9118 data->uri_type = uri_type;
9122 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9124 int ret = MM_ERROR_PLAYER_INVALID_URI;
9126 char *buffer = NULL;
9127 char *seperator = strchr(path, ',');
9128 char ext[100] = {0,}, size[100] = {0,};
9131 if ((buffer = strstr(path, "ext="))) {
9132 buffer += strlen("ext=");
9134 if (strlen(buffer)) {
9135 strncpy(ext, buffer, 99);
9137 if ((seperator = strchr(ext, ','))
9138 || (seperator = strchr(ext, ' '))
9139 || (seperator = strchr(ext, '\0'))) {
9140 seperator[0] = '\0';
9145 if ((buffer = strstr(path, "size="))) {
9146 buffer += strlen("size=");
9148 if (strlen(buffer) > 0) {
9149 strncpy(size, buffer, 99);
9151 if ((seperator = strchr(size, ','))
9152 || (seperator = strchr(size, ' '))
9153 || (seperator = strchr(size, '\0'))) {
9154 seperator[0] = '\0';
9157 mem_size = atoi(size);
9162 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9164 if (mem_size && param) {
9165 if (data->input_mem.buf)
9166 free(data->input_mem.buf);
9167 data->input_mem.buf = malloc(mem_size);
9169 if (data->input_mem.buf) {
9170 memcpy(data->input_mem.buf, param, mem_size);
9171 data->input_mem.len = mem_size;
9172 ret = MM_ERROR_NONE;
9174 LOGE("failed to alloc mem %d", mem_size);
9175 ret = MM_ERROR_PLAYER_INTERNAL;
9178 data->input_mem.offset = 0;
9179 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9186 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9188 gchar *location = NULL;
9191 int ret = MM_ERROR_NONE;
9193 if ((path = strstr(uri, "file://"))) {
9194 location = g_filename_from_uri(uri, NULL, &err);
9195 if (!location || (err != NULL)) {
9196 LOGE("Invalid URI '%s' for filesrc: %s", path,
9197 (err != NULL) ? err->message : "unknown error");
9201 MMPLAYER_FREEIF(location);
9203 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9204 return MM_ERROR_PLAYER_INVALID_URI;
9206 LOGD("path from uri: %s", location);
9209 path = (location != NULL) ? (location) : ((char *)uri);
9212 ret = _mmplayer_exist_file_path(path);
9214 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9215 if (ret == MM_ERROR_NONE) {
9216 if (_mmplayer_is_sdp_file(path)) {
9217 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9218 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9219 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9221 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9222 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9224 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9225 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9227 LOGE("invalid uri, could not play..");
9228 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9231 MMPLAYER_FREEIF(location);
9236 static mmplayer_video_decoded_data_info_t *
9237 __mmplayer_create_stream_from_pad(GstPad *pad)
9239 GstCaps *caps = NULL;
9240 GstStructure *structure = NULL;
9241 unsigned int fourcc = 0;
9242 const gchar *string_format = NULL;
9243 mmplayer_video_decoded_data_info_t *stream = NULL;
9245 MMPixelFormatType format;
9248 caps = gst_pad_get_current_caps(pad);
9250 LOGE("Caps is NULL.");
9255 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9257 structure = gst_caps_get_structure(caps, 0);
9258 gst_structure_get_int(structure, "width", &width);
9259 gst_structure_get_int(structure, "height", &height);
9260 string_format = gst_structure_get_string(structure, "format");
9263 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9264 format = _mmplayer_get_pixtype(fourcc);
9265 gst_video_info_from_caps(&info, caps);
9266 gst_caps_unref(caps);
9269 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9270 LOGE("Wrong condition!!");
9274 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9276 LOGE("failed to alloc mem for video data");
9280 stream->width = width;
9281 stream->height = height;
9282 stream->format = format;
9283 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9289 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9291 unsigned int pitch = 0;
9292 unsigned int size = 0;
9294 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9297 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9298 bo = gst_tizen_memory_get_bos(mem, index);
9300 stream->bo[index] = tbm_bo_ref(bo);
9302 LOGE("failed to get bo for index %d", index);
9305 for (index = 0; index < stream->plane_num; index++) {
9306 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9307 stream->stride[index] = pitch;
9309 stream->elevation[index] = size / pitch;
9311 stream->elevation[index] = stream->height;
9316 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9318 if (stream->format == MM_PIXEL_FORMAT_I420) {
9319 int ret = TBM_SURFACE_ERROR_NONE;
9320 tbm_surface_h surface;
9321 tbm_surface_info_s info;
9323 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9325 ret = tbm_surface_get_info(surface, &info);
9326 if (ret != TBM_SURFACE_ERROR_NONE) {
9327 tbm_surface_destroy(surface);
9331 tbm_surface_destroy(surface);
9332 stream->stride[0] = info.planes[0].stride;
9333 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9334 stream->stride[1] = info.planes[1].stride;
9335 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9336 stream->stride[2] = info.planes[2].stride;
9337 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9338 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9339 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9340 stream->stride[0] = stream->width * 4;
9341 stream->elevation[0] = stream->height;
9342 stream->bo_size = stream->stride[0] * stream->height;
9344 LOGE("Not support format %d", stream->format);
9352 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9354 tbm_bo_handle thandle;
9356 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9357 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9358 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9362 unsigned char *src = NULL;
9363 unsigned char *dest = NULL;
9364 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9366 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9368 LOGE("fail to gst_memory_map");
9372 if (!mapinfo.data) {
9373 LOGE("data pointer is wrong");
9377 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9378 if (!stream->bo[0]) {
9379 LOGE("Fail to tbm_bo_alloc!!");
9383 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9385 LOGE("thandle pointer is wrong");
9389 if (stream->format == MM_PIXEL_FORMAT_I420) {
9390 src_stride[0] = GST_ROUND_UP_4(stream->width);
9391 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9392 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9393 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9396 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9397 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9399 for (i = 0; i < 3; i++) {
9400 src = mapinfo.data + src_offset[i];
9401 dest = thandle.ptr + dest_offset[i];
9406 for (j = 0; j < stream->height >> k; j++) {
9407 memcpy(dest, src, stream->width>>k);
9408 src += src_stride[i];
9409 dest += stream->stride[i];
9412 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9413 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9415 LOGE("Not support format %d", stream->format);
9419 tbm_bo_unmap(stream->bo[0]);
9420 gst_memory_unmap(mem, &mapinfo);
9426 tbm_bo_unmap(stream->bo[0]);
9429 gst_memory_unmap(mem, &mapinfo);
9435 __mmplayer_set_pause_state(mmplayer_t *player)
9437 if (player->sent_bos)
9440 /* rtsp case, get content attrs by GstMessage */
9441 if (MMPLAYER_IS_RTSP_STREAMING(player))
9444 /* it's first time to update all content attrs. */
9445 _mmplayer_update_content_attrs(player, ATTR_ALL);
9449 __mmplayer_set_playing_state(mmplayer_t *player)
9451 gchar *audio_codec = NULL;
9453 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9454 /* initialize because auto resume is done well. */
9455 player->resumed_by_rewind = FALSE;
9456 player->playback_rate = 1.0;
9459 if (player->sent_bos)
9462 /* try to get content metadata */
9464 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9465 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9466 * legacy mmfw-player api
9468 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9470 if ((player->cmd == MMPLAYER_COMMAND_START)
9471 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9472 __mmplayer_handle_missed_plugin(player);
9475 /* check audio codec field is set or not
9476 * we can get it from typefinder or codec's caps.
9478 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9480 /* The codec format can't be sent for audio only case like amr, mid etc.
9481 * Because, parser don't make related TAG.
9482 * So, if it's not set yet, fill it with found data.
9485 if (g_strrstr(player->type, "audio/midi"))
9486 audio_codec = "MIDI";
9487 else if (g_strrstr(player->type, "audio/x-amr"))
9488 audio_codec = "AMR";
9489 else if (g_strrstr(player->type, "audio/mpeg")
9490 && !g_strrstr(player->type, "mpegversion=(int)1"))
9491 audio_codec = "AAC";
9493 audio_codec = "unknown";
9495 if (mm_player_set_attribute((MMHandleType)player, NULL,
9496 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9497 LOGE("failed to set attribute");
9499 LOGD("set audio codec type with caps");