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;
1180 gboolean caps_ret = TRUE;
1182 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1183 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1186 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1187 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1189 LOGD("pad-added signal handling");
1191 /* get mimetype from caps */
1192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1196 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1198 LOGD("detected mimetype : %s", name);
1201 if (strstr(name, "video")) {
1203 gchar *caps_str = NULL;
1205 caps_str = gst_caps_to_string(caps);
1206 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1207 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1208 player->set_mode.video_zc = true;
1210 MMPLAYER_FREEIF(caps_str);
1212 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1213 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1215 LOGD("surface type : %d", stype);
1217 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1218 __mmplayer_gst_create_sinkbin(elem, pad, player);
1222 /* in case of exporting video frame, it requires the 360 video filter.
1223 * it will be handled in _no_more_pads(). */
1224 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1225 __mmplayer_gst_make_fakesink(player, pad, name);
1229 LOGD("video selector is required");
1230 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1232 } else if (strstr(name, "audio")) {
1233 gint samplerate = 0;
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1237 if (player->build_audio_offload)
1238 player->no_more_pad = TRUE; /* remove state holder */
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 gst_structure_get_int(str, "rate", &samplerate);
1244 gst_structure_get_int(str, "channels", &channels);
1246 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1247 __mmplayer_gst_make_fakesink(player, pad, name);
1251 LOGD("audio selector is required");
1252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1253 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1255 } else if (strstr(name, "text")) {
1256 LOGD("text selector is required");
1257 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1258 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1260 LOGE("invalid caps info");
1264 /* check selector and create it */
1265 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1266 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1271 LOGD("input-selector is already created.");
1275 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1277 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1279 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1280 LOGE("failed to link selector");
1281 gst_object_unref(GST_OBJECT(selector));
1286 LOGD("this track will be activated");
1287 g_object_set(selector, "active-pad", sinkpad, NULL);
1290 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1296 gst_caps_unref(caps);
1299 gst_object_unref(GST_OBJECT(sinkpad));
1307 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1309 GstPad *srcpad = NULL;
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1314 LOGD("type %d", type);
1317 LOGD("there is no %d track", type);
1321 srcpad = gst_element_get_static_pad(selector, "src");
1323 LOGE("failed to get srcpad from selector");
1327 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1329 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1331 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1332 if (player->selector[type].block_id) {
1333 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1334 player->selector[type].block_id = 0;
1338 gst_object_unref(GST_OBJECT(srcpad));
1347 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1349 gint active_index = 0;
1352 MMPLAYER_RETURN_IF_FAIL(player);
1354 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1356 /* change track to active pad */
1357 active_index = player->selector[type].active_pad_index;
1358 if ((active_index != DEFAULT_TRACK) &&
1359 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1360 LOGW("failed to change %d type track to %d", type, active_index);
1361 player->selector[type].active_pad_index = DEFAULT_TRACK;
1365 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1366 mm_player_set_attribute((MMHandleType)player, NULL,
1367 "content_text_track_num", player->selector[type].total_track_num,
1368 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1375 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1378 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1380 if (!audio_selector) {
1381 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1383 /* in case the source is changed, output can be changed. */
1384 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1385 LOGD("remove previous audiobin if it exist");
1387 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1388 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1390 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1391 MMPLAYER_FREEIF(player->pipeline->audiobin);
1394 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1395 __mmplayer_pipeline_complete(NULL, player);
1400 /* apply the audio track information */
1401 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1403 /* create audio sink path */
1404 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1405 LOGE("failed to create audio sink path");
1414 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1417 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1419 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1420 LOGD("text path is not supproted");
1424 /* apply the text track information */
1425 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1427 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1428 player->has_closed_caption = TRUE;
1430 /* create text decode path */
1431 player->no_more_pad = TRUE;
1433 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1434 LOGE("failed to create text sink path");
1443 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1445 gint64 dur_bytes = 0L;
1448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1449 player->pipeline->mainbin && player->streamer, FALSE);
1451 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1452 LOGE("fail to get duration.");
1454 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1455 * use file information was already set on Q2 when it was created. */
1456 _mm_player_streaming_set_queue2(player->streamer,
1457 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1458 TRUE, /* use_buffering */
1459 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1460 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1467 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1469 mmplayer_t *player = NULL;
1470 GstElement *video_selector = NULL;
1471 GstElement *audio_selector = NULL;
1472 GstElement *text_selector = NULL;
1475 player = (mmplayer_t *)data;
1477 LOGD("no-more-pad signal handling");
1479 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1480 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1481 LOGW("player is shutting down");
1485 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1486 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1487 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1488 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1489 LOGE("failed to set queue2 buffering");
1494 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1495 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1496 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1498 if (!video_selector && !audio_selector && !text_selector) {
1499 LOGW("there is no selector");
1500 player->no_more_pad = TRUE;
1504 /* create video path followed by video-select */
1505 if (video_selector && !audio_selector && !text_selector)
1506 player->no_more_pad = TRUE;
1508 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1511 /* create audio path followed by audio-select */
1512 if (audio_selector && !text_selector)
1513 player->no_more_pad = TRUE;
1515 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1518 /* create text path followed by text-select */
1519 __mmplayer_create_text_sink_path(player, text_selector);
1522 _mmplayer_set_reconfigure_state(player, FALSE);
1527 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1529 gboolean ret = FALSE;
1530 GstElement *pipeline = NULL;
1531 GstPad *sinkpad = NULL;
1534 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1537 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1539 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1541 LOGE("failed to get pad from sinkbin");
1547 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1548 LOGE("failed to link sinkbin for reusing");
1549 goto EXIT; /* exit either pass or fail */
1553 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1554 LOGE("failed to set state(READY) to sinkbin");
1559 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1560 LOGE("failed to add sinkbin to pipeline");
1565 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1566 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1571 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1572 LOGE("failed to set state(PAUSED) to sinkbin");
1581 gst_object_unref(GST_OBJECT(sinkpad));
1589 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1591 mmplayer_t *player = NULL;
1592 GstCaps *caps = NULL;
1593 gchar *caps_str = NULL;
1594 GstStructure *str = NULL;
1595 const gchar *name = NULL;
1596 GstElement *sinkbin = NULL;
1597 gboolean reusing = FALSE;
1598 gboolean caps_ret = TRUE;
1599 gchar *sink_pad_name = "sink";
1602 player = (mmplayer_t *)data;
1605 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1606 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1608 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1612 caps_str = gst_caps_to_string(caps);
1614 LOGD("detected mimetype : %s", name);
1616 if (strstr(name, "audio")) {
1617 if (player->pipeline->audiobin == NULL) {
1618 const gchar *audio_format = gst_structure_get_string(str, "format");
1620 LOGD("original audio format %s", audio_format);
1621 mm_player_set_attribute((MMHandleType)player, NULL,
1622 "content_audio_format", audio_format, strlen(audio_format), NULL);
1625 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1626 LOGE("failed to create audiobin. continuing without audio");
1630 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1631 LOGD("creating audiobin success");
1634 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1635 LOGD("reusing audiobin");
1636 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1638 } else if (strstr(name, "video")) {
1639 /* 1. zero copy is updated at _decode_pad_added()
1640 * 2. NULL surface type is handled in _decode_pad_added() */
1641 LOGD("zero copy %d", player->set_mode.video_zc);
1642 if (player->pipeline->videobin == NULL) {
1643 int surface_type = 0;
1644 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1645 LOGD("display_surface_type (%d)", surface_type);
1647 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1648 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1649 LOGE("failed to acquire video overlay resource");
1653 player->interrupted_by_resource = FALSE;
1655 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1656 LOGE("failed to create videobin. continuing without video");
1660 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1661 LOGD("creating videosink bin success");
1664 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1665 LOGD("re-using videobin");
1666 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1668 } else if (strstr(name, "text")) {
1669 if (player->pipeline->textbin == NULL) {
1670 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1671 LOGE("failed to create text sink bin. continuing without text");
1675 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1676 player->textsink_linked = 1;
1677 LOGD("creating textsink bin success");
1679 if (!player->textsink_linked) {
1680 LOGD("re-using textbin");
1682 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1683 player->textsink_linked = 1;
1685 /* linked textbin exist which means that the external subtitle path exist already */
1686 LOGW("ignoring internal subtutle since external subtitle is available");
1689 sink_pad_name = "text_sink";
1691 LOGW("unknown mime type %s, ignoring it", name);
1695 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1698 LOGD("[handle: %p] success to create and link sink bin", player);
1700 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1701 * streaming task. if the task blocked, then buffer will not flow to the next element
1702 *(autoplugging element). so this is special hack for streaming. please try to remove it
1704 /* dec stream count. we can remove fakesink if it's zero */
1705 if (player->num_dynamic_pad)
1706 player->num_dynamic_pad--;
1708 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1710 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1711 __mmplayer_pipeline_complete(NULL, player);
1715 MMPLAYER_FREEIF(caps_str);
1718 gst_caps_unref(caps);
1724 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1726 int required_angle = 0; /* Angle required for straight view */
1727 int rotation_angle = 0;
1729 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1730 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1732 /* Counter clockwise */
1733 switch (orientation) {
1738 required_angle = 270;
1741 required_angle = 180;
1744 required_angle = 90;
1748 rotation_angle = display_angle + required_angle;
1749 if (rotation_angle >= 360)
1750 rotation_angle -= 360;
1752 /* chech if supported or not */
1753 if (rotation_angle % 90) {
1754 LOGD("not supported rotation angle = %d", rotation_angle);
1758 switch (rotation_angle) {
1760 *value = MM_DISPLAY_ROTATION_NONE;
1763 *value = MM_DISPLAY_ROTATION_90;
1766 *value = MM_DISPLAY_ROTATION_180;
1769 *value = MM_DISPLAY_ROTATION_270;
1773 LOGD("setting rotation property value : %d", *value);
1779 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1781 int display_rotation = 0;
1782 gchar *org_orient = NULL;
1783 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1786 LOGE("cannot get content attribute");
1787 return MM_ERROR_PLAYER_INTERNAL;
1790 if (display_angle) {
1791 /* update user roation */
1792 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1794 /* Counter clockwise */
1795 switch (display_rotation) {
1796 case MM_DISPLAY_ROTATION_NONE:
1799 case MM_DISPLAY_ROTATION_90:
1800 *display_angle = 90;
1802 case MM_DISPLAY_ROTATION_180:
1803 *display_angle = 180;
1805 case MM_DISPLAY_ROTATION_270:
1806 *display_angle = 270;
1809 LOGW("wrong angle type : %d", display_rotation);
1812 LOGD("check user angle: %d", *display_angle);
1816 /* Counter clockwise */
1817 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1820 if (!strcmp(org_orient, "rotate-90"))
1822 else if (!strcmp(org_orient, "rotate-180"))
1824 else if (!strcmp(org_orient, "rotate-270"))
1827 LOGD("original rotation is %s", org_orient);
1829 LOGD("content_video_orientation get fail");
1832 LOGD("check orientation: %d", *orientation);
1835 return MM_ERROR_NONE;
1838 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1840 int rotation_value = 0;
1841 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1842 int display_angle = 0;
1845 /* check video sinkbin is created */
1846 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1849 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1851 /* get rotation value to set */
1852 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1853 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1854 LOGD("set video param : rotate %d", rotation_value);
1857 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1859 MMHandleType attrs = 0;
1863 /* check video sinkbin is created */
1864 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1867 attrs = MMPLAYER_GET_ATTRS(player);
1868 MMPLAYER_RETURN_IF_FAIL(attrs);
1870 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1871 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1872 LOGD("set video param : visible %d", visible);
1875 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1877 MMHandleType attrs = 0;
1878 int display_method = 0;
1881 /* check video sinkbin is created */
1882 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1885 attrs = MMPLAYER_GET_ATTRS(player);
1886 MMPLAYER_RETURN_IF_FAIL(attrs);
1888 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1889 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1890 LOGD("set video param : method %d", display_method);
1893 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1895 MMHandleType attrs = 0;
1899 /* check video sinkbin is created */
1900 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1903 attrs = MMPLAYER_GET_ATTRS(player);
1904 MMPLAYER_RETURN_IF_FAIL(attrs);
1906 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1907 MMPLAYER_RETURN_IF_FAIL(handle);
1909 gst_video_overlay_set_video_roi_area(
1910 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1912 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1913 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1916 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1918 MMHandleType attrs = 0;
1923 int win_roi_width = 0;
1924 int win_roi_height = 0;
1927 /* check video sinkbin is created */
1928 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1931 attrs = MMPLAYER_GET_ATTRS(player);
1932 MMPLAYER_RETURN_IF_FAIL(attrs);
1934 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1935 MMPLAYER_RETURN_IF_FAIL(handle);
1937 /* It should be set after setting window */
1938 mm_attrs_multiple_get(attrs, NULL,
1939 "display_win_roi_x", &win_roi_x,
1940 "display_win_roi_y", &win_roi_y,
1941 "display_win_roi_width", &win_roi_width,
1942 "display_win_roi_height", &win_roi_height, NULL);
1944 /* After setting window handle, set display roi area */
1945 gst_video_overlay_set_display_roi_area(
1946 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1948 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1949 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1952 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1954 MMHandleType attrs = 0;
1957 /* check video sinkbin is created */
1958 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1961 attrs = MMPLAYER_GET_ATTRS(player);
1962 MMPLAYER_RETURN_IF_FAIL(attrs);
1964 /* common case if using overlay surface */
1965 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1966 MMPLAYER_RETURN_IF_FAIL(handle);
1968 /* default is using wl_surface_id */
1969 LOGD("set video param : wl_surface_id %d", handle);
1970 gst_video_overlay_set_wl_window_wl_surface_id(
1971 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1976 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1978 gboolean update_all_param = FALSE;
1982 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1983 LOGW("videosink is not ready yet");
1984 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1987 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1988 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1989 return MM_ERROR_PLAYER_INTERNAL;
1992 LOGD("param_name : %s", param_name);
1993 if (!g_strcmp0(param_name, "update_all_param"))
1994 update_all_param = TRUE;
1996 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1997 __mmplayer_video_param_set_display_overlay(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1999 __mmplayer_video_param_set_display_method(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2001 __mmplayer_video_param_set_display_visible(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2003 __mmplayer_video_param_set_display_rotation(player);
2004 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2005 __mmplayer_video_param_set_roi_area(player);
2006 if (update_all_param)
2007 __mmplayer_video_param_set_video_roi_area(player);
2011 return MM_ERROR_NONE;
2015 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2017 gboolean disable_overlay = FALSE;
2018 mmplayer_t *player = (mmplayer_t *)hplayer;
2021 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2022 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2023 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2024 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2026 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2027 LOGW("Display control is not supported");
2028 return MM_ERROR_PLAYER_INTERNAL;
2031 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2033 if (audio_only == (bool)disable_overlay) {
2034 LOGE("It's the same with current setting: (%d)", audio_only);
2035 return MM_ERROR_NONE;
2039 LOGE("disable overlay");
2040 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2042 /* release overlay resource */
2043 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2044 LOGE("failed to release overlay resource");
2048 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2049 LOGE("failed to acquire video overlay resource");
2052 player->interrupted_by_resource = FALSE;
2054 LOGD("enable overlay");
2055 __mmplayer_video_param_set_display_overlay(player);
2056 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2061 return MM_ERROR_NONE;
2065 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2067 mmplayer_t *player = (mmplayer_t *)hplayer;
2068 gboolean disable_overlay = FALSE;
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2073 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2075 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2076 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2078 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2079 LOGW("Display control is not supported");
2080 return MM_ERROR_PLAYER_INTERNAL;
2083 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2085 *paudio_only = (bool)disable_overlay;
2087 LOGD("audio_only : %d", *paudio_only);
2091 return MM_ERROR_NONE;
2095 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2097 GList *bucket = element_bucket;
2098 mmplayer_gst_element_t *element = NULL;
2099 mmplayer_gst_element_t *prv_element = NULL;
2100 GstElement *tee_element = NULL;
2101 gint successful_link_count = 0;
2105 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2107 prv_element = (mmplayer_gst_element_t *)bucket->data;
2108 bucket = bucket->next;
2110 for (; bucket; bucket = bucket->next) {
2111 element = (mmplayer_gst_element_t *)bucket->data;
2113 if (element && element->gst) {
2114 if (prv_element && prv_element->gst) {
2115 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2117 prv_element->gst = tee_element;
2119 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2120 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2121 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2125 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2126 LOGD("linking [%s] to [%s] success",
2127 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2128 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2129 successful_link_count++;
2130 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2131 LOGD("keep audio-tee element for next audio pipeline branch");
2132 tee_element = prv_element->gst;
2135 LOGD("linking [%s] to [%s] failed",
2136 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2137 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2143 prv_element = element;
2148 return successful_link_count;
2152 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2154 GList *bucket = element_bucket;
2155 mmplayer_gst_element_t *element = NULL;
2156 int successful_add_count = 0;
2160 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2161 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2163 for (; bucket; bucket = bucket->next) {
2164 element = (mmplayer_gst_element_t *)bucket->data;
2166 if (element && element->gst) {
2167 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2168 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2169 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2170 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2173 successful_add_count++;
2179 return successful_add_count;
2183 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2185 mmplayer_t *player = (mmplayer_t *)data;
2186 GstCaps *caps = NULL;
2187 GstStructure *str = NULL;
2189 gboolean caps_ret = TRUE;
2193 MMPLAYER_RETURN_IF_FAIL(pad);
2194 MMPLAYER_RETURN_IF_FAIL(unused);
2195 MMPLAYER_RETURN_IF_FAIL(data);
2197 caps = gst_pad_get_current_caps(pad);
2201 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2205 LOGD("name = %s", name);
2207 if (strstr(name, "audio")) {
2208 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2210 if (player->audio_stream_changed_cb) {
2211 LOGE("call the audio stream changed cb");
2212 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2214 } else if (strstr(name, "video")) {
2215 if ((name = gst_structure_get_string(str, "format")))
2216 player->set_mode.video_zc = name[0] == 'S';
2218 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2219 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2221 LOGW("invalid caps info");
2226 gst_caps_unref(caps);
2234 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2239 MMPLAYER_RETURN_IF_FAIL(player);
2241 if (player->audio_stream_buff_list) {
2242 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2243 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2246 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2247 __mmplayer_audio_stream_send_data(player, tmp);
2249 MMPLAYER_FREEIF(tmp->pcm_data);
2250 MMPLAYER_FREEIF(tmp);
2253 g_list_free(player->audio_stream_buff_list);
2254 player->audio_stream_buff_list = NULL;
2261 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2263 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2266 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2268 audio_stream.bitrate = a_buffer->bitrate;
2269 audio_stream.channel = a_buffer->channel;
2270 audio_stream.channel_mask = a_buffer->channel_mask;
2271 audio_stream.data_size = a_buffer->data_size;
2272 audio_stream.data = a_buffer->pcm_data;
2273 audio_stream.pcm_format = a_buffer->pcm_format;
2275 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2277 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2283 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2285 mmplayer_t *player = (mmplayer_t *)data;
2286 const gchar *pcm_format = NULL;
2289 guint64 channel_mask = 0;
2290 void *a_data = NULL;
2292 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2293 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2297 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2299 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2300 a_data = mapinfo.data;
2301 a_size = mapinfo.size;
2303 GstCaps *caps = gst_pad_get_current_caps(pad);
2304 GstStructure *structure = gst_caps_get_structure(caps, 0);
2306 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2308 pcm_format = gst_structure_get_string(structure, "format");
2309 gst_structure_get_int(structure, "rate", &rate);
2310 gst_structure_get_int(structure, "channels", &channel);
2311 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2312 gst_caps_unref(GST_CAPS(caps));
2314 /* In case of the sync is false, use buffer list. *
2315 * The num of buffer list depends on the num of audio channels */
2316 if (player->audio_stream_buff_list) {
2317 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2318 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2320 if (channel_mask == tmp->channel_mask) {
2322 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2324 if (tmp->data_size + a_size < tmp->buff_size) {
2325 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2326 tmp->data_size += a_size;
2328 /* send data to client */
2329 __mmplayer_audio_stream_send_data(player, tmp);
2331 if (a_size > tmp->buff_size) {
2332 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2333 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2334 if (tmp->pcm_data == NULL) {
2335 LOGE("failed to realloc data.");
2338 tmp->buff_size = a_size;
2340 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2341 memcpy(tmp->pcm_data, a_data, a_size);
2342 tmp->data_size = a_size;
2347 LOGE("data is empty in list.");
2353 /* create new audio stream data for newly found audio channel */
2354 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2355 if (a_buffer == NULL) {
2356 LOGE("failed to alloc data.");
2359 a_buffer->bitrate = rate;
2360 a_buffer->channel = channel;
2361 a_buffer->channel_mask = channel_mask;
2362 a_buffer->data_size = a_size;
2363 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2365 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2366 /* If sync is FALSE, use buffer list to reduce the IPC. */
2367 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2368 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2369 if (a_buffer->pcm_data == NULL) {
2370 LOGE("failed to alloc data.");
2371 MMPLAYER_FREEIF(a_buffer);
2374 memcpy(a_buffer->pcm_data, a_data, a_size);
2376 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2378 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2380 /* If sync is TRUE, send data directly. */
2381 a_buffer->pcm_data = a_data;
2382 __mmplayer_audio_stream_send_data(player, a_buffer);
2383 MMPLAYER_FREEIF(a_buffer);
2387 gst_buffer_unmap(buffer, &mapinfo);
2392 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2394 mmplayer_t *player = (mmplayer_t *)data;
2395 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2396 GstPad *sinkpad = NULL;
2397 GstElement *queue = NULL, *sink = NULL;
2400 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2402 queue = gst_element_factory_make("queue", NULL);
2403 if (queue == NULL) {
2404 LOGD("fail make queue");
2408 sink = gst_element_factory_make("fakesink", NULL);
2410 LOGD("fail make fakesink");
2414 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2416 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2417 LOGW("failed to link queue & sink");
2421 sinkpad = gst_element_get_static_pad(queue, "sink");
2423 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2424 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2428 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2430 gst_object_unref(sinkpad);
2431 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2432 g_object_set(sink, "sync", TRUE, NULL);
2433 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2435 /* keep the first sink reference only */
2436 if (!audiobin[MMPLAYER_A_SINK].gst) {
2437 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2438 audiobin[MMPLAYER_A_SINK].gst = sink;
2442 _mmplayer_add_signal_connection(player,
2444 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2446 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2449 __mmplayer_add_sink(player, sink);
2451 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2452 LOGE("failed to sync state");
2456 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2457 LOGE("failed to sync state");
2465 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2467 gst_object_unref(GST_OBJECT(queue));
2471 gst_object_unref(GST_OBJECT(sink));
2475 gst_object_unref(GST_OBJECT(sinkpad));
2483 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2485 mmplayer_t *player = (mmplayer_t *)data;
2488 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2490 player->no_more_pad = TRUE;
2491 __mmplayer_pipeline_complete(NULL, player);
2498 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2500 #define MAX_PROPS_LEN 128
2501 mmplayer_gst_element_t *audiobin = NULL;
2502 gint latency_mode = 0;
2503 gchar *stream_type = NULL;
2504 gchar *latency = NULL;
2506 gchar stream_props[MAX_PROPS_LEN] = {0,};
2507 GstStructure *props = NULL;
2510 * It should be set after player creation through attribute.
2511 * But, it can not be changed during playing.
2514 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2516 audiobin = player->pipeline->audiobin;
2518 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2519 if (player->sound.mute) {
2520 LOGD("mute enabled");
2521 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2524 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2525 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2528 snprintf(stream_props, sizeof(stream_props) - 1,
2529 "props,application.process.id.origin=%d", player->client_pid);
2531 snprintf(stream_props, sizeof(stream_props) - 1,
2532 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2533 stream_type, stream_id, player->client_pid);
2535 props = gst_structure_from_string(stream_props, NULL);
2536 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2537 LOGI("props result[%s].", stream_props);
2538 gst_structure_free(props);
2540 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2542 switch (latency_mode) {
2543 case AUDIO_LATENCY_MODE_LOW:
2544 latency = g_strdup("low");
2546 case AUDIO_LATENCY_MODE_MID:
2547 latency = g_strdup("mid");
2549 case AUDIO_LATENCY_MODE_HIGH:
2550 latency = g_strdup("high");
2553 latency = g_strdup("mid");
2557 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2559 LOGD("audiosink property - latency=%s", latency);
2561 MMPLAYER_FREEIF(latency);
2567 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2569 mmplayer_gst_element_t *audiobin = NULL;
2572 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2573 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2575 audiobin = player->pipeline->audiobin;
2577 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2578 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2579 LOGE("failed to create media stream info");
2580 return MM_ERROR_PLAYER_INTERNAL;
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2585 if (player->video360_yaw_radians <= M_PI &&
2586 player->video360_yaw_radians >= -M_PI &&
2587 player->video360_pitch_radians <= M_PI_2 &&
2588 player->video360_pitch_radians >= -M_PI_2) {
2589 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2590 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2591 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2592 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2593 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2594 "source-orientation-y", player->video360_metadata.init_view_heading,
2595 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2599 return MM_ERROR_NONE;
2603 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2605 mmplayer_gst_element_t *audiobin = NULL;
2606 GstPad *sink_pad = NULL;
2607 GstCaps *acaps = NULL;
2609 int pitch_control = 0;
2610 double pitch_value = 1.0;
2613 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2614 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2616 audiobin = player->pipeline->audiobin;
2618 LOGD("make element for normal audio playback");
2620 /* audio bin structure for playback. {} means optional.
2621 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2623 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2624 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2627 /* for pitch control */
2628 mm_attrs_multiple_get(player->attrs, NULL,
2629 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2630 MM_PLAYER_PITCH_VALUE, &pitch_value,
2633 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2634 if (pitch_control && (player->videodec_linked == 0)) {
2635 GstElementFactory *factory;
2637 factory = gst_element_factory_find("pitch");
2639 gst_object_unref(factory);
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2648 LOGW("there is no pitch element");
2653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2655 /* replaygain volume */
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2657 if (player->sound.rg_enable)
2658 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2663 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2665 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2666 /* currently, only openalsink uses volume element */
2667 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2668 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2670 if (player->sound.mute) {
2671 LOGD("mute enabled");
2672 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2676 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2678 /* audio effect element. if audio effect is enabled */
2679 if ((strcmp(player->ini.audioeffect_element, ""))
2681 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2682 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2684 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2686 if ((!player->bypass_audio_effect)
2687 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2688 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2689 if (!_mmplayer_audio_effect_custom_apply(player))
2690 LOGI("apply audio effect(custom) setting success");
2694 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2695 && (player->set_mode.rich_audio)) {
2696 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2700 /* create audio sink */
2701 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2702 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2703 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2705 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2706 if (player->is_360_feature_enabled &&
2707 player->is_content_spherical &&
2709 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2710 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2711 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2713 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2718 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2720 gst_caps_unref(acaps);
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2724 player->is_openal_plugin_used = TRUE;
2726 if (player->is_360_feature_enabled && player->is_content_spherical)
2727 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2731 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2732 (player->videodec_linked && player->ini.use_system_clock)) {
2733 LOGD("system clock will be used.");
2734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2737 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2738 __mmplayer_gst_set_pulsesink_property(player);
2739 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2740 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2746 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2748 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2749 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2750 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2751 gst_object_unref(GST_OBJECT(sink_pad));
2753 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2756 return MM_ERROR_NONE;
2758 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2760 return MM_ERROR_PLAYER_INTERNAL;
2764 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2766 mmplayer_gst_element_t *audiobin = NULL;
2767 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2769 gchar *dst_format = NULL;
2771 int dst_samplerate = 0;
2772 int dst_channels = 0;
2773 GstCaps *caps = NULL;
2774 char *caps_str = NULL;
2777 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2778 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2780 audiobin = player->pipeline->audiobin;
2782 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2784 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2786 [case 1] extract interleave audio pcm without playback
2787 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2788 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2790 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2792 [case 2] deinterleave for each channel without playback
2793 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2794 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2796 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2797 - fakesink (sync or not)
2800 [case 3] [case 1(sync only)] + playback
2801 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2803 * src - ... - tee - queue1 - playback path
2804 - queue2 - [case1 pipeline with sync]
2806 [case 4] [case 2(sync only)] + playback
2807 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2809 * src - ... - tee - queue1 - playback path
2810 - queue2 - [case2 pipeline with sync]
2814 /* 1. create tee and playback path
2815 'tee' should be added at first to copy the decoded stream
2817 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2818 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2819 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2821 /* tee - path 1 : for playback path */
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2823 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2825 /* tee - path 2 : for extract path */
2826 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2827 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2830 /* if there is tee, 'tee - path 2' is linked here */
2832 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2835 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2837 /* 2. decide the extract pcm format */
2838 mm_attrs_multiple_get(player->attrs, NULL,
2839 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2840 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2841 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2844 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2845 dst_format, dst_len, dst_samplerate, dst_channels);
2847 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2848 mm_attrs_multiple_get(player->attrs, NULL,
2849 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2850 "content_audio_samplerate", &dst_samplerate,
2851 "content_audio_channels", &dst_channels,
2854 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2855 dst_format, dst_len, dst_samplerate, dst_channels);
2857 /* If there is no enough information, set it to platform default value. */
2858 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2859 LOGD("set platform default format");
2860 dst_format = DEFAULT_PCM_OUT_FORMAT;
2862 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2863 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2866 /* 3. create capsfilter */
2867 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2868 caps = gst_caps_new_simple("audio/x-raw",
2869 "format", G_TYPE_STRING, dst_format,
2870 "rate", G_TYPE_INT, dst_samplerate,
2871 "channels", G_TYPE_INT, dst_channels,
2874 caps_str = gst_caps_to_string(caps);
2875 LOGD("new caps : %s", caps_str);
2877 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2880 gst_caps_unref(caps);
2881 MMPLAYER_FREEIF(caps_str);
2883 /* 4-1. create deinterleave to extract pcm for each channel */
2884 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2885 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2886 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2888 /* audiosink will be added after getting signal for each channel */
2889 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2890 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2891 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2892 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2893 player->no_more_pad = FALSE;
2895 /* 4-2. create fakesink to extract interlevaed pcm */
2896 LOGD("add audio fakesink for interleaved audio");
2897 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2898 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2899 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2900 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2902 _mmplayer_add_signal_connection(player,
2903 G_OBJECT(audiobin[extract_sink_id].gst),
2904 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2906 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2909 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2913 return MM_ERROR_NONE;
2915 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2917 return MM_ERROR_PLAYER_INTERNAL;
2921 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2923 int ret = MM_ERROR_NONE;
2924 mmplayer_gst_element_t *audiobin = NULL;
2925 GList *element_bucket = NULL;
2928 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2929 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2931 audiobin = player->pipeline->audiobin;
2933 if (player->build_audio_offload) { /* skip all the audio filters */
2934 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2936 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2937 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2938 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2940 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2944 /* FIXME: need to mention the supportable condition at API reference */
2945 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2946 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2948 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2950 if (ret != MM_ERROR_NONE)
2953 LOGD("success to make audio bin element");
2954 *bucket = element_bucket;
2957 return MM_ERROR_NONE;
2960 LOGE("failed to make audio bin element");
2961 g_list_free(element_bucket);
2965 return MM_ERROR_PLAYER_INTERNAL;
2969 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2971 mmplayer_gst_element_t *first_element = NULL;
2972 mmplayer_gst_element_t *audiobin = NULL;
2974 GstPad *ghostpad = NULL;
2975 GList *element_bucket = NULL;
2979 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2982 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2984 LOGE("failed to allocate memory for audiobin");
2985 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2989 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2990 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2991 if (!audiobin[MMPLAYER_A_BIN].gst) {
2992 LOGE("failed to create audiobin");
2997 player->pipeline->audiobin = audiobin;
2999 /* create audio filters and audiosink */
3000 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3003 /* adding created elements to bin */
3004 LOGD("adding created elements to bin");
3005 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3008 /* linking elements in the bucket by added order. */
3009 LOGD("Linking elements in the bucket by added order.");
3010 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3013 /* get first element's sinkpad for creating ghostpad */
3014 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3015 if (!first_element) {
3016 LOGE("failed to get first elem");
3020 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3022 LOGE("failed to get pad from first element of audiobin");
3026 ghostpad = gst_ghost_pad_new("sink", pad);
3028 LOGE("failed to create ghostpad");
3032 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3033 LOGE("failed to add ghostpad to audiobin");
3037 gst_object_unref(pad);
3039 g_list_free(element_bucket);
3042 return MM_ERROR_NONE;
3045 LOGD("ERROR : releasing audiobin");
3048 gst_object_unref(GST_OBJECT(pad));
3051 gst_object_unref(GST_OBJECT(ghostpad));
3054 g_list_free(element_bucket);
3056 /* release element which are not added to bin */
3057 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3058 /* NOTE : skip bin */
3059 if (audiobin[i].gst) {
3060 GstObject *parent = NULL;
3061 parent = gst_element_get_parent(audiobin[i].gst);
3064 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3065 audiobin[i].gst = NULL;
3067 gst_object_unref(GST_OBJECT(parent));
3071 /* release audiobin with it's childs */
3072 if (audiobin[MMPLAYER_A_BIN].gst)
3073 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3075 MMPLAYER_FREEIF(audiobin);
3077 player->pipeline->audiobin = NULL;
3079 return MM_ERROR_PLAYER_INTERNAL;
3083 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3085 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3089 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3091 int ret = MM_ERROR_NONE;
3093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3094 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3096 MMPLAYER_VIDEO_BO_LOCK(player);
3098 if (player->video_bo_list) {
3099 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3100 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3101 if (tmp && tmp->bo == bo) {
3103 LOGD("release bo %p", bo);
3104 tbm_bo_unref(tmp->bo);
3105 MMPLAYER_VIDEO_BO_UNLOCK(player);
3106 MMPLAYER_VIDEO_BO_SIGNAL(player);
3111 /* hw codec is running or the list was reset for DRC. */
3112 LOGW("there is no bo list.");
3114 MMPLAYER_VIDEO_BO_UNLOCK(player);
3116 LOGW("failed to find bo %p", bo);
3121 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3126 MMPLAYER_RETURN_IF_FAIL(player);
3128 MMPLAYER_VIDEO_BO_LOCK(player);
3129 if (player->video_bo_list) {
3130 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3131 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3132 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3135 tbm_bo_unref(tmp->bo);
3139 g_list_free(player->video_bo_list);
3140 player->video_bo_list = NULL;
3142 player->video_bo_size = 0;
3143 MMPLAYER_VIDEO_BO_UNLOCK(player);
3150 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3153 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3154 gboolean ret = TRUE;
3156 /* check DRC, if it is, destroy the prev bo list to create again */
3157 if (player->video_bo_size != size) {
3158 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3159 __mmplayer_video_stream_destroy_bo_list(player);
3160 player->video_bo_size = size;
3163 MMPLAYER_VIDEO_BO_LOCK(player);
3165 if ((!player->video_bo_list) ||
3166 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3168 /* create bo list */
3170 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3172 if (player->video_bo_list) {
3173 /* if bo list did not created all, try it again. */
3174 idx = g_list_length(player->video_bo_list);
3175 LOGD("bo list exist(len: %d)", idx);
3178 for (; idx < player->ini.num_of_video_bo; idx++) {
3179 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3181 LOGE("Fail to alloc bo_info.");
3184 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3186 LOGE("Fail to tbm_bo_alloc.");
3187 MMPLAYER_FREEIF(bo_info);
3190 bo_info->used = FALSE;
3191 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3194 /* update video num buffers */
3195 LOGD("video_num_buffers : %d", idx);
3196 mm_player_set_attribute((MMHandleType)player, NULL,
3197 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3198 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3202 MMPLAYER_VIDEO_BO_UNLOCK(player);
3208 /* get bo from list*/
3209 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3210 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3211 if (tmp && (tmp->used == FALSE)) {
3212 LOGD("found bo %p to use", tmp->bo);
3214 MMPLAYER_VIDEO_BO_UNLOCK(player);
3215 return tbm_bo_ref(tmp->bo);
3219 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3220 MMPLAYER_VIDEO_BO_UNLOCK(player);
3224 if (player->ini.video_bo_timeout <= 0) {
3225 MMPLAYER_VIDEO_BO_WAIT(player);
3227 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3228 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3235 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3237 mmplayer_t *player = (mmplayer_t *)data;
3239 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3241 /* send prerolled pkt */
3242 player->video_stream_prerolled = false;
3244 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3246 /* not to send prerolled pkt again */
3247 player->video_stream_prerolled = true;
3251 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3253 mmplayer_t *player = (mmplayer_t *)data;
3254 mmplayer_video_decoded_data_info_t *stream = NULL;
3255 GstMemory *mem = NULL;
3258 MMPLAYER_RETURN_IF_FAIL(player);
3259 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3261 if (player->video_stream_prerolled) {
3262 player->video_stream_prerolled = false;
3263 LOGD("skip the prerolled pkt not to send it again");
3267 /* clear stream data structure */
3268 stream = __mmplayer_create_stream_from_pad(pad);
3270 LOGE("failed to alloc stream");
3274 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3276 /* set size and timestamp */
3277 mem = gst_buffer_peek_memory(buffer, 0);
3278 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3279 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3281 /* check zero-copy */
3282 if (player->set_mode.video_zc &&
3283 player->set_mode.video_export &&
3284 gst_is_tizen_memory(mem)) {
3285 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3286 stream->internal_buffer = gst_buffer_ref(buffer);
3287 } else { /* sw codec */
3288 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3291 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3295 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3296 LOGE("failed to send video decoded data.");
3303 LOGE("release video stream resource.");
3304 if (gst_is_tizen_memory(mem)) {
3306 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3308 tbm_bo_unref(stream->bo[i]);
3311 /* unref gst buffer */
3312 if (stream->internal_buffer)
3313 gst_buffer_unref(stream->internal_buffer);
3316 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3318 MMPLAYER_FREEIF(stream);
3323 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3325 mmplayer_gst_element_t *videobin = NULL;
3328 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3330 videobin = player->pipeline->videobin;
3332 /* Set spatial media metadata and/or user settings to the element.
3334 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3335 "projection-type", player->video360_metadata.projection_type, NULL);
3337 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3338 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3340 if (player->video360_metadata.full_pano_width_pixels &&
3341 player->video360_metadata.full_pano_height_pixels &&
3342 player->video360_metadata.cropped_area_image_width &&
3343 player->video360_metadata.cropped_area_image_height) {
3344 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3345 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3346 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3347 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3348 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3349 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3350 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3354 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3355 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3356 "horizontal-fov", player->video360_horizontal_fov,
3357 "vertical-fov", player->video360_vertical_fov, NULL);
3360 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3362 "zoom", 1.0f / player->video360_zoom, NULL);
3365 if (player->video360_yaw_radians <= M_PI &&
3366 player->video360_yaw_radians >= -M_PI &&
3367 player->video360_pitch_radians <= M_PI_2 &&
3368 player->video360_pitch_radians >= -M_PI_2) {
3369 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3370 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3371 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3372 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3373 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3374 "pose-yaw", player->video360_metadata.init_view_heading,
3375 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3378 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3379 "passthrough", !player->is_video360_enabled, NULL);
3386 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3388 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3389 GList *element_bucket = NULL;
3392 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3394 /* create video360 filter */
3395 if (player->is_360_feature_enabled && player->is_content_spherical) {
3396 LOGD("create video360 element");
3397 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3398 __mmplayer_gst_set_video360_property(player);
3402 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3403 LOGD("skip creating the videoconv and rotator");
3404 return MM_ERROR_NONE;
3407 /* in case of sw codec & overlay surface type, except 360 playback.
3408 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3409 LOGD("create video converter: %s", video_csc);
3410 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3413 *bucket = element_bucket;
3415 return MM_ERROR_NONE;
3417 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3418 g_list_free(element_bucket);
3422 return MM_ERROR_PLAYER_INTERNAL;
3426 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3428 gchar *factory_name = NULL;
3430 switch (surface_type) {
3431 case MM_DISPLAY_SURFACE_OVERLAY:
3432 if (strlen(player->ini.videosink_element_overlay) > 0)
3433 factory_name = player->ini.videosink_element_overlay;
3435 case MM_DISPLAY_SURFACE_REMOTE:
3436 case MM_DISPLAY_SURFACE_NULL:
3437 if (strlen(player->ini.videosink_element_fake) > 0)
3438 factory_name = player->ini.videosink_element_fake;
3441 LOGE("unidentified surface type");
3445 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3446 return factory_name;
3450 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3452 gchar *factory_name = NULL;
3453 mmplayer_gst_element_t *videobin = NULL;
3458 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3460 videobin = player->pipeline->videobin;
3461 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3463 attrs = MMPLAYER_GET_ATTRS(player);
3465 LOGE("cannot get content attribute");
3466 return MM_ERROR_PLAYER_INTERNAL;
3469 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3470 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3471 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3472 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3473 "use-tbm", use_tbm, NULL);
3476 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3477 return MM_ERROR_PLAYER_INTERNAL;
3479 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3482 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3483 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3486 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3488 LOGD("disable last-sample");
3489 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3492 if (player->set_mode.video_export) {
3494 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3495 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3496 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3498 _mmplayer_add_signal_connection(player,
3499 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3500 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3502 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3505 _mmplayer_add_signal_connection(player,
3506 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3507 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3509 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3513 if (videobin[MMPLAYER_V_SINK].gst) {
3514 GstPad *sink_pad = NULL;
3515 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3517 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3518 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3519 gst_object_unref(GST_OBJECT(sink_pad));
3521 LOGE("failed to get sink pad from videosink");
3525 return MM_ERROR_NONE;
3530 * - video overlay surface(arm/x86) : tizenwlsink
3533 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3536 GList *element_bucket = NULL;
3537 mmplayer_gst_element_t *first_element = NULL;
3538 mmplayer_gst_element_t *videobin = NULL;
3539 gchar *videosink_factory_name = NULL;
3542 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3545 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3547 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3549 player->pipeline->videobin = videobin;
3552 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3553 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3554 if (!videobin[MMPLAYER_V_BIN].gst) {
3555 LOGE("failed to create videobin");
3559 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3562 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3563 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3565 /* additional setting for sink plug-in */
3566 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3567 LOGE("failed to set video property");
3571 /* store it as it's sink element */
3572 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3574 /* adding created elements to bin */
3575 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3576 LOGE("failed to add elements");
3580 /* Linking elements in the bucket by added order */
3581 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3582 LOGE("failed to link elements");
3586 /* get first element's sinkpad for creating ghostpad */
3587 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3588 if (!first_element) {
3589 LOGE("failed to get first element from bucket");
3593 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3595 LOGE("failed to get pad from first element");
3599 /* create ghostpad */
3600 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3601 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3602 LOGE("failed to add ghostpad to videobin");
3605 gst_object_unref(pad);
3607 /* done. free allocated variables */
3608 g_list_free(element_bucket);
3612 return MM_ERROR_NONE;
3615 LOGE("ERROR : releasing videobin");
3616 g_list_free(element_bucket);
3619 gst_object_unref(GST_OBJECT(pad));
3621 /* release videobin with it's childs */
3622 if (videobin[MMPLAYER_V_BIN].gst)
3623 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3625 MMPLAYER_FREEIF(videobin);
3626 player->pipeline->videobin = NULL;
3628 return MM_ERROR_PLAYER_INTERNAL;
3632 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3634 GList *element_bucket = NULL;
3635 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3637 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3638 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3639 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3640 "signal-handoffs", FALSE,
3643 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3644 _mmplayer_add_signal_connection(player,
3645 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3646 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3648 G_CALLBACK(__mmplayer_update_subtitle),
3651 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3652 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3654 if (!player->play_subtitle) {
3655 LOGD("add textbin sink as sink element of whole pipeline.");
3656 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3659 /* adding created elements to bin */
3660 LOGD("adding created elements to bin");
3661 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3662 LOGE("failed to add elements");
3666 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3667 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3668 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3670 /* linking elements in the bucket by added order. */
3671 LOGD("Linking elements in the bucket by added order.");
3672 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3673 LOGE("failed to link elements");
3677 /* done. free allocated variables */
3678 g_list_free(element_bucket);
3680 if (textbin[MMPLAYER_T_QUEUE].gst) {
3682 GstPad *ghostpad = NULL;
3684 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3686 LOGE("failed to get sink pad of text queue");
3690 ghostpad = gst_ghost_pad_new("text_sink", pad);
3691 gst_object_unref(pad);
3694 LOGE("failed to create ghostpad of textbin");
3698 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3699 LOGE("failed to add ghostpad to textbin");
3700 gst_object_unref(ghostpad);
3705 return MM_ERROR_NONE;
3708 g_list_free(element_bucket);
3710 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3711 LOGE("remove textbin sink from sink list");
3712 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3715 /* release element at __mmplayer_gst_create_text_sink_bin */
3716 return MM_ERROR_PLAYER_INTERNAL;
3720 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3722 mmplayer_gst_element_t *textbin = NULL;
3723 GList *element_bucket = NULL;
3724 int surface_type = 0;
3729 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3732 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3734 LOGE("failed to allocate memory for textbin");
3735 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3739 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3740 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3741 if (!textbin[MMPLAYER_T_BIN].gst) {
3742 LOGE("failed to create textbin");
3747 player->pipeline->textbin = textbin;
3750 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3751 LOGD("surface type for subtitle : %d", surface_type);
3752 switch (surface_type) {
3753 case MM_DISPLAY_SURFACE_OVERLAY:
3754 case MM_DISPLAY_SURFACE_NULL:
3755 case MM_DISPLAY_SURFACE_REMOTE:
3756 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3757 LOGE("failed to make plain text elements");
3768 return MM_ERROR_NONE;
3772 LOGD("ERROR : releasing textbin");
3774 g_list_free(element_bucket);
3776 /* release signal */
3777 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3779 /* release element which are not added to bin */
3780 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3781 /* NOTE : skip bin */
3782 if (textbin[i].gst) {
3783 GstObject *parent = NULL;
3784 parent = gst_element_get_parent(textbin[i].gst);
3787 gst_object_unref(GST_OBJECT(textbin[i].gst));
3788 textbin[i].gst = NULL;
3790 gst_object_unref(GST_OBJECT(parent));
3795 /* release textbin with it's childs */
3796 if (textbin[MMPLAYER_T_BIN].gst)
3797 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3799 MMPLAYER_FREEIF(textbin);
3800 player->pipeline->textbin = NULL;
3803 return MM_ERROR_PLAYER_INTERNAL;
3807 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3809 mmplayer_gst_element_t *mainbin = NULL;
3810 mmplayer_gst_element_t *textbin = NULL;
3811 MMHandleType attrs = 0;
3812 GstElement *subsrc = NULL;
3813 GstElement *subparse = NULL;
3814 gchar *subtitle_uri = NULL;
3815 const gchar *charset = NULL;
3821 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3823 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3825 mainbin = player->pipeline->mainbin;
3827 attrs = MMPLAYER_GET_ATTRS(player);
3829 LOGE("cannot get content attribute");
3830 return MM_ERROR_PLAYER_INTERNAL;
3833 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3834 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3835 LOGE("subtitle uri is not proper filepath.");
3836 return MM_ERROR_PLAYER_INVALID_URI;
3839 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3840 LOGE("failed to get storage info of subtitle path");
3841 return MM_ERROR_PLAYER_INVALID_URI;
3844 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3846 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3847 player->subtitle_language_list = NULL;
3848 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3850 /* create the subtitle source */
3851 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3853 LOGE("failed to create filesrc element");
3856 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3858 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3859 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3861 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3862 LOGW("failed to add queue");
3863 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3864 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3865 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3870 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3872 LOGE("failed to create subparse element");
3876 charset = _mmplayer_get_charset(subtitle_uri);
3878 LOGD("detected charset is %s", charset);
3879 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3882 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3883 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3885 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3886 LOGW("failed to add subparse");
3887 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3888 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3889 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3893 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3894 LOGW("failed to link subsrc and subparse");
3898 player->play_subtitle = TRUE;
3899 player->adjust_subtitle_pos = 0;
3901 LOGD("play subtitle using subtitle file");
3903 if (player->pipeline->textbin == NULL) {
3904 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3905 LOGE("failed to create text sink bin. continuing without text");
3909 textbin = player->pipeline->textbin;
3911 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3912 LOGW("failed to add textbin");
3914 /* release signal */
3915 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3917 /* release textbin with it's childs */
3918 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3919 MMPLAYER_FREEIF(player->pipeline->textbin);
3920 player->pipeline->textbin = textbin = NULL;
3924 LOGD("link text input selector and textbin ghost pad");
3926 player->textsink_linked = 1;
3927 player->external_text_idx = 0;
3928 LOGI("textsink is linked");
3930 textbin = player->pipeline->textbin;
3931 LOGD("text bin has been created. reuse it.");
3932 player->external_text_idx = 1;
3935 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3936 LOGW("failed to link subparse and textbin");
3940 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3942 LOGE("failed to get sink pad from textsink to probe data");
3946 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3947 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3949 gst_object_unref(pad);
3952 /* create dot. for debugging */
3953 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3956 return MM_ERROR_NONE;
3959 /* release text pipeline resource */
3960 player->textsink_linked = 0;
3962 /* release signal */
3963 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3965 if (player->pipeline->textbin) {
3966 LOGE("remove textbin");
3968 /* release textbin with it's childs */
3969 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3970 MMPLAYER_FREEIF(player->pipeline->textbin);
3971 player->pipeline->textbin = NULL;
3975 /* release subtitle elem */
3976 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3977 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3979 return MM_ERROR_PLAYER_INTERNAL;
3983 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3985 mmplayer_t *player = (mmplayer_t *)data;
3986 MMMessageParamType msg = {0, };
3987 GstClockTime duration = 0;
3988 gpointer text = NULL;
3989 guint text_size = 0;
3990 gboolean ret = TRUE;
3991 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3995 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3996 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3998 if (player->is_subtitle_force_drop) {
3999 LOGW("subtitle is dropped forcedly.");
4003 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4004 text = mapinfo.data;
4005 text_size = mapinfo.size;
4007 if (player->set_mode.subtitle_off) {
4008 LOGD("subtitle is OFF.");
4012 if (!text || (text_size == 0)) {
4013 LOGD("There is no subtitle to be displayed.");
4017 msg.data = (void *)text;
4019 duration = GST_BUFFER_DURATION(buffer);
4021 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4022 if (player->duration > GST_BUFFER_PTS(buffer))
4023 duration = player->duration - GST_BUFFER_PTS(buffer);
4026 LOGI("subtitle duration is invalid, subtitle duration change "
4027 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4029 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4031 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4033 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4034 gst_buffer_unmap(buffer, &mapinfo);
4041 static GstPadProbeReturn
4042 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4044 mmplayer_t *player = (mmplayer_t *)u_data;
4045 GstClockTime cur_timestamp = 0;
4046 gint64 adjusted_timestamp = 0;
4047 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4049 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4051 if (player->set_mode.subtitle_off) {
4052 LOGD("subtitle is OFF.");
4056 if (player->adjust_subtitle_pos == 0) {
4057 LOGD("nothing to do");
4061 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4062 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4064 if (adjusted_timestamp < 0) {
4065 LOGD("adjusted_timestamp under zero");
4070 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4071 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4072 GST_TIME_ARGS(cur_timestamp),
4073 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4075 return GST_PAD_PROBE_OK;
4079 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4083 /* check player and subtitlebin are created */
4084 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4085 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4087 if (position == 0) {
4088 LOGD("nothing to do");
4090 return MM_ERROR_NONE;
4093 /* check current postion */
4094 player->adjust_subtitle_pos = position;
4096 LOGD("save adjust_subtitle_pos in player");
4100 return MM_ERROR_NONE;
4104 * This function is to create audio or video pipeline for playing.
4106 * @param player [in] handle of player
4108 * @return This function returns zero on success.
4113 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4115 int ret = MM_ERROR_NONE;
4116 mmplayer_gst_element_t *mainbin = NULL;
4117 MMHandleType attrs = 0;
4120 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4122 /* get profile attribute */
4123 attrs = MMPLAYER_GET_ATTRS(player);
4125 LOGE("failed to get content attribute");
4129 /* create pipeline handles */
4130 if (player->pipeline) {
4131 LOGE("pipeline should be released before create new one");
4135 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4137 /* create mainbin */
4138 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4139 if (mainbin == NULL)
4142 /* create pipeline */
4143 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4144 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4145 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4146 LOGE("failed to create pipeline");
4151 player->pipeline->mainbin = mainbin;
4153 /* create the source and decoder elements */
4154 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4155 ret = _mmplayer_gst_build_es_pipeline(player);
4157 ret = _mmplayer_gst_build_pipeline(player);
4159 if (ret != MM_ERROR_NONE) {
4160 LOGE("failed to create some elements");
4164 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4165 if (__mmplayer_check_subtitle(player)
4166 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4167 LOGE("failed to create text pipeline");
4170 ret = _mmplayer_gst_add_bus_watch(player);
4171 if (ret != MM_ERROR_NONE) {
4172 LOGE("failed to add bus watch");
4177 return MM_ERROR_NONE;
4180 __mmplayer_gst_destroy_pipeline(player);
4181 return MM_ERROR_PLAYER_INTERNAL;
4185 __mmplayer_reset_gapless_state(mmplayer_t *player)
4188 MMPLAYER_RETURN_IF_FAIL(player
4190 && player->pipeline->audiobin
4191 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4193 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4200 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4203 int ret = MM_ERROR_NONE;
4207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4209 /* cleanup stuffs */
4210 MMPLAYER_FREEIF(player->type);
4211 player->no_more_pad = FALSE;
4212 player->num_dynamic_pad = 0;
4213 player->demux_pad_index = 0;
4215 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4216 player->subtitle_language_list = NULL;
4217 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4219 MMPLAYER_RECONFIGURE_LOCK(player);
4220 __mmplayer_reset_gapless_state(player);
4221 MMPLAYER_RECONFIGURE_UNLOCK(player);
4223 if (player->streamer) {
4224 _mm_player_streaming_initialize(player->streamer, FALSE);
4225 _mm_player_streaming_destroy(player->streamer);
4226 player->streamer = NULL;
4229 /* cleanup unlinked mime type */
4230 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4231 MMPLAYER_FREEIF(player->unlinked_video_mime);
4232 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4234 /* cleanup running stuffs */
4235 _mmplayer_cancel_eos_timer(player);
4237 /* cleanup gst stuffs */
4238 if (player->pipeline) {
4239 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4240 GstTagList *tag_list = player->pipeline->tag_list;
4242 /* first we need to disconnect all signal hander */
4243 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4246 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4247 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4248 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4249 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4250 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4251 gst_object_unref(bus);
4253 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4254 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4255 if (ret != MM_ERROR_NONE) {
4256 LOGE("fail to change state to NULL");
4257 return MM_ERROR_PLAYER_INTERNAL;
4260 LOGW("succeeded in changing state to NULL");
4262 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4265 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4266 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4268 /* free avsysaudiosink
4269 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4270 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4272 MMPLAYER_FREEIF(audiobin);
4273 MMPLAYER_FREEIF(videobin);
4274 MMPLAYER_FREEIF(textbin);
4275 MMPLAYER_FREEIF(mainbin);
4279 gst_tag_list_unref(tag_list);
4281 MMPLAYER_FREEIF(player->pipeline);
4283 MMPLAYER_FREEIF(player->album_art);
4285 if (player->v_stream_caps) {
4286 gst_caps_unref(player->v_stream_caps);
4287 player->v_stream_caps = NULL;
4290 if (player->a_stream_caps) {
4291 gst_caps_unref(player->a_stream_caps);
4292 player->a_stream_caps = NULL;
4295 if (player->s_stream_caps) {
4296 gst_caps_unref(player->s_stream_caps);
4297 player->s_stream_caps = NULL;
4299 _mmplayer_track_destroy(player);
4301 if (player->sink_elements)
4302 g_list_free(player->sink_elements);
4303 player->sink_elements = NULL;
4305 if (player->bufmgr) {
4306 tbm_bufmgr_deinit(player->bufmgr);
4307 player->bufmgr = NULL;
4310 LOGW("finished destroy pipeline");
4318 __mmplayer_gst_realize(mmplayer_t *player)
4321 int ret = MM_ERROR_NONE;
4325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4327 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4329 ret = __mmplayer_gst_create_pipeline(player);
4331 LOGE("failed to create pipeline");
4335 /* set pipeline state to READY */
4336 /* NOTE : state change to READY must be performed sync. */
4337 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4338 ret = _mmplayer_gst_set_state(player,
4339 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4341 if (ret != MM_ERROR_NONE) {
4342 /* return error if failed to set state */
4343 LOGE("failed to set READY state");
4347 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4349 /* create dot before error-return. for debugging */
4350 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4358 __mmplayer_gst_unrealize(mmplayer_t *player)
4360 int ret = MM_ERROR_NONE;
4364 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4366 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4367 MMPLAYER_PRINT_STATE(player);
4369 /* release miscellaneous information */
4370 __mmplayer_release_misc(player);
4372 /* destroy pipeline */
4373 ret = __mmplayer_gst_destroy_pipeline(player);
4374 if (ret != MM_ERROR_NONE) {
4375 LOGE("failed to destory pipeline");
4379 /* release miscellaneous information.
4380 these info needs to be released after pipeline is destroyed. */
4381 __mmplayer_release_misc_post(player);
4383 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4391 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4396 LOGW("set_message_callback is called with invalid player handle");
4397 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4400 player->msg_cb = callback;
4401 player->msg_cb_param = user_param;
4403 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4407 return MM_ERROR_NONE;
4411 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4413 int ret = MM_ERROR_NONE;
4418 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4419 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4420 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4422 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4424 if (strstr(uri, "es_buff://")) {
4425 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4426 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4427 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4428 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4430 tmp = g_ascii_strdown(uri, strlen(uri));
4431 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4432 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4434 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4436 } else if (strstr(uri, "mms://")) {
4437 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4438 } else if ((path = strstr(uri, "mem://"))) {
4439 ret = __mmplayer_set_mem_uri(data, path, param);
4441 ret = __mmplayer_set_file_uri(data, uri);
4444 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4445 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4446 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4447 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4449 /* dump parse result */
4450 SECURE_LOGW("incoming uri : %s", uri);
4451 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4452 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4460 __mmplayer_can_do_interrupt(mmplayer_t *player)
4462 if (!player || !player->pipeline || !player->attrs) {
4463 LOGW("not initialized");
4467 if (player->audio_decoded_cb) {
4468 LOGW("not support in pcm extraction mode");
4472 /* check if seeking */
4473 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4474 MMMessageParamType msg_param;
4475 memset(&msg_param, 0, sizeof(MMMessageParamType));
4476 msg_param.code = MM_ERROR_PLAYER_SEEK;
4477 player->seek_state = MMPLAYER_SEEK_NONE;
4478 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4482 /* check other thread */
4483 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4484 LOGW("locked already, cmd state : %d", player->cmd);
4486 /* check application command */
4487 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4488 LOGW("playing.. should wait cmd lock then, will be interrupted");
4490 /* lock will be released at mrp_resource_release_cb() */
4491 MMPLAYER_CMD_LOCK(player);
4494 LOGW("nothing to do");
4497 LOGW("can interrupt immediately");
4501 FAILED: /* with CMD UNLOCKED */
4504 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4509 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4512 mmplayer_t *player = NULL;
4513 MMMessageParamType msg = {0, };
4515 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4520 LOGE("user_data is null");
4523 player = (mmplayer_t *)user_data;
4525 if (!__mmplayer_can_do_interrupt(player)) {
4526 LOGW("no need to interrupt, so leave");
4527 /* FIXME: there is no way to avoid releasing resource. */
4531 player->interrupted_by_resource = TRUE;
4533 /* get last play position */
4534 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4535 msg.union_type = MM_MSG_UNION_TIME;
4536 msg.time.elapsed = pos;
4537 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4539 LOGW("failed to get play position.");
4542 LOGD("video resource conflict so, resource will be freed by unrealizing");
4543 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4544 LOGE("failed to unrealize");
4546 /* lock is called in __mmplayer_can_do_interrupt() */
4547 MMPLAYER_CMD_UNLOCK(player);
4549 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4550 player->hw_resource[res_idx] = NULL;
4554 return TRUE; /* release all the resources */
4558 __mmplayer_initialize_video_roi(mmplayer_t *player)
4560 player->video_roi.scale_x = 0.0;
4561 player->video_roi.scale_y = 0.0;
4562 player->video_roi.scale_width = 1.0;
4563 player->video_roi.scale_height = 1.0;
4567 _mmplayer_create_player(MMHandleType handle)
4569 int ret = MM_ERROR_PLAYER_INTERNAL;
4570 bool enabled = false;
4572 mmplayer_t *player = MM_PLAYER_CAST(handle);
4576 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4578 /* initialize player state */
4579 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4580 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4581 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4582 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4584 /* check current state */
4585 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4587 /* construct attributes */
4588 player->attrs = _mmplayer_construct_attribute(handle);
4590 if (!player->attrs) {
4591 LOGE("Failed to construct attributes");
4595 /* initialize gstreamer with configured parameter */
4596 if (!__mmplayer_init_gstreamer(player)) {
4597 LOGE("Initializing gstreamer failed");
4598 _mmplayer_deconstruct_attribute(handle);
4602 /* create lock. note that g_tread_init() has already called in gst_init() */
4603 g_mutex_init(&player->fsink_lock);
4605 /* create update tag lock */
4606 g_mutex_init(&player->update_tag_lock);
4608 /* create gapless play mutex */
4609 g_mutex_init(&player->gapless_play_thread_mutex);
4611 /* create gapless play cond */
4612 g_cond_init(&player->gapless_play_thread_cond);
4614 /* create gapless play thread */
4615 player->gapless_play_thread =
4616 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4617 if (!player->gapless_play_thread) {
4618 LOGE("failed to create gapless play thread");
4619 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4620 g_mutex_clear(&player->gapless_play_thread_mutex);
4621 g_cond_clear(&player->gapless_play_thread_cond);
4625 player->bus_msg_q = g_queue_new();
4626 if (!player->bus_msg_q) {
4627 LOGE("failed to create queue for bus_msg");
4628 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4632 ret = _mmplayer_initialize_video_capture(player);
4633 if (ret != MM_ERROR_NONE) {
4634 LOGE("failed to initialize video capture");
4638 /* initialize resource manager */
4639 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4640 __resource_release_cb, player, &player->resource_manager)
4641 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4642 LOGE("failed to initialize resource manager");
4643 ret = MM_ERROR_PLAYER_INTERNAL;
4647 /* create video bo lock and cond */
4648 g_mutex_init(&player->video_bo_mutex);
4649 g_cond_init(&player->video_bo_cond);
4651 /* create subtitle info lock and cond */
4652 g_mutex_init(&player->subtitle_info_mutex);
4653 g_cond_init(&player->subtitle_info_cond);
4655 player->streaming_type = STREAMING_SERVICE_NONE;
4657 /* give default value of audio effect setting */
4658 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4659 player->sound.rg_enable = false;
4660 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4662 player->play_subtitle = FALSE;
4663 player->has_closed_caption = FALSE;
4664 player->pending_resume = FALSE;
4665 if (player->ini.dump_element_keyword[0][0] == '\0')
4666 player->ini.set_dump_element_flag = FALSE;
4668 player->ini.set_dump_element_flag = TRUE;
4670 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4671 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4672 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4674 /* Set video360 settings to their defaults for just-created player.
4677 player->is_360_feature_enabled = FALSE;
4678 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4679 LOGI("spherical feature info: %d", enabled);
4681 player->is_360_feature_enabled = TRUE;
4683 LOGE("failed to get spherical feature info");
4686 player->is_content_spherical = FALSE;
4687 player->is_video360_enabled = TRUE;
4688 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4689 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4690 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4691 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4692 player->video360_zoom = 1.0f;
4693 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4694 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4696 __mmplayer_initialize_video_roi(player);
4698 /* set player state to null */
4699 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4700 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4704 return MM_ERROR_NONE;
4708 g_mutex_clear(&player->fsink_lock);
4709 /* free update tag lock */
4710 g_mutex_clear(&player->update_tag_lock);
4711 g_queue_free(player->bus_msg_q);
4712 player->bus_msg_q = NULL;
4713 /* free gapless play thread */
4714 if (player->gapless_play_thread) {
4715 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4716 player->gapless_play_thread_exit = TRUE;
4717 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4718 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4720 g_thread_join(player->gapless_play_thread);
4721 player->gapless_play_thread = NULL;
4723 g_mutex_clear(&player->gapless_play_thread_mutex);
4724 g_cond_clear(&player->gapless_play_thread_cond);
4727 /* release attributes */
4728 _mmplayer_deconstruct_attribute(handle);
4736 __mmplayer_init_gstreamer(mmplayer_t *player)
4738 static gboolean initialized = FALSE;
4739 static const int max_argc = 50;
4741 gchar **argv = NULL;
4742 gchar **argv2 = NULL;
4748 LOGD("gstreamer already initialized.");
4753 argc = malloc(sizeof(int));
4754 argv = malloc(sizeof(gchar *) * max_argc);
4755 argv2 = malloc(sizeof(gchar *) * max_argc);
4757 if (!argc || !argv || !argv2)
4760 memset(argv, 0, sizeof(gchar *) * max_argc);
4761 memset(argv2, 0, sizeof(gchar *) * max_argc);
4765 argv[0] = g_strdup("mmplayer");
4768 for (i = 0; i < 5; i++) {
4769 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4770 if (strlen(player->ini.gst_param[i]) > 0) {
4771 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4776 /* we would not do fork for scanning plugins */
4777 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4780 /* check disable registry scan */
4781 if (player->ini.skip_rescan) {
4782 argv[*argc] = g_strdup("--gst-disable-registry-update");
4786 /* check disable segtrap */
4787 if (player->ini.disable_segtrap) {
4788 argv[*argc] = g_strdup("--gst-disable-segtrap");
4792 LOGD("initializing gstreamer with following parameter");
4793 LOGD("argc : %d", *argc);
4796 for (i = 0; i < arg_count; i++) {
4798 LOGD("argv[%d] : %s", i, argv2[i]);
4801 /* initializing gstreamer */
4802 if (!gst_init_check(argc, &argv, &err)) {
4803 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4810 for (i = 0; i < arg_count; i++) {
4812 LOGD("release - argv[%d] : %s", i, argv2[i]);
4814 MMPLAYER_FREEIF(argv2[i]);
4817 MMPLAYER_FREEIF(argv);
4818 MMPLAYER_FREEIF(argv2);
4819 MMPLAYER_FREEIF(argc);
4829 for (i = 0; i < arg_count; i++) {
4830 LOGD("free[%d] : %s", i, argv2[i]);
4831 MMPLAYER_FREEIF(argv2[i]);
4834 MMPLAYER_FREEIF(argv);
4835 MMPLAYER_FREEIF(argv2);
4836 MMPLAYER_FREEIF(argc);
4842 __mmplayer_check_async_state_transition(mmplayer_t *player)
4844 GstState element_state = GST_STATE_VOID_PENDING;
4845 GstState element_pending_state = GST_STATE_VOID_PENDING;
4846 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4847 GstElement *element = NULL;
4848 gboolean async = FALSE;
4850 /* check player handle */
4851 MMPLAYER_RETURN_IF_FAIL(player &&
4853 player->pipeline->mainbin &&
4854 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4857 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4859 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4860 LOGD("don't need to check the pipeline state");
4864 MMPLAYER_PRINT_STATE(player);
4866 /* wait for state transition */
4867 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4868 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4870 if (ret == GST_STATE_CHANGE_FAILURE) {
4871 LOGE(" [%s] state : %s pending : %s",
4872 GST_ELEMENT_NAME(element),
4873 gst_element_state_get_name(element_state),
4874 gst_element_state_get_name(element_pending_state));
4876 /* dump state of all element */
4877 _mmplayer_dump_pipeline_state(player);
4882 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4887 _mmplayer_destroy(MMHandleType handle)
4889 mmplayer_t *player = MM_PLAYER_CAST(handle);
4893 /* check player handle */
4894 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4896 /* destroy can called at anytime */
4897 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4899 /* check async state transition */
4900 __mmplayer_check_async_state_transition(player);
4902 /* release gapless play thread */
4903 if (player->gapless_play_thread) {
4904 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4905 player->gapless_play_thread_exit = TRUE;
4906 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4907 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4909 LOGD("waitting for gapless play thread exit");
4910 g_thread_join(player->gapless_play_thread);
4911 g_mutex_clear(&player->gapless_play_thread_mutex);
4912 g_cond_clear(&player->gapless_play_thread_cond);
4913 LOGD("gapless play thread released");
4916 _mmplayer_release_video_capture(player);
4918 /* de-initialize resource manager */
4919 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4920 player->resource_manager))
4921 LOGE("failed to deinitialize resource manager");
4923 /* release miscellaneous information */
4924 __mmplayer_release_misc(player);
4926 /* release pipeline */
4927 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4928 LOGE("failed to destory pipeline");
4929 return MM_ERROR_PLAYER_INTERNAL;
4932 g_queue_free(player->bus_msg_q);
4934 /* release subtitle info lock and cond */
4935 g_mutex_clear(&player->subtitle_info_mutex);
4936 g_cond_clear(&player->subtitle_info_cond);
4938 __mmplayer_release_dump_list(player->dump_list);
4940 /* release miscellaneous information.
4941 these info needs to be released after pipeline is destroyed. */
4942 __mmplayer_release_misc_post(player);
4944 /* release attributes */
4945 _mmplayer_deconstruct_attribute(handle);
4947 if (player->uri_info.uri_list) {
4948 GList *uri_list = player->uri_info.uri_list;
4949 for (; uri_list; uri_list = g_list_next(uri_list)) {
4950 gchar *uri = uri_list->data;
4951 MMPLAYER_FREEIF(uri);
4953 g_list_free(player->uri_info.uri_list);
4954 player->uri_info.uri_list = NULL;
4958 g_mutex_clear(&player->fsink_lock);
4961 g_mutex_clear(&player->update_tag_lock);
4963 /* release video bo lock and cond */
4964 g_mutex_clear(&player->video_bo_mutex);
4965 g_cond_clear(&player->video_bo_cond);
4969 return MM_ERROR_NONE;
4973 _mmplayer_realize(MMHandleType hplayer)
4975 mmplayer_t *player = (mmplayer_t *)hplayer;
4976 int ret = MM_ERROR_NONE;
4979 MMHandleType attrs = 0;
4980 int video_codec_type = 0;
4981 int audio_codec_type = 0;
4982 int default_codec_type = 0;
4985 /* check player handle */
4986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4988 /* check current state */
4989 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4991 attrs = MMPLAYER_GET_ATTRS(player);
4993 LOGE("fail to get attributes.");
4994 return MM_ERROR_PLAYER_INTERNAL;
4996 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4997 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4999 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5000 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5002 if (ret != MM_ERROR_NONE) {
5003 LOGE("failed to parse profile");
5008 if (uri && (strstr(uri, "es_buff://"))) {
5009 if (strstr(uri, "es_buff://push_mode"))
5010 player->es_player_push_mode = TRUE;
5012 player->es_player_push_mode = FALSE;
5015 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5016 LOGW("mms protocol is not supported format.");
5017 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5020 if (MMPLAYER_IS_STREAMING(player))
5021 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5023 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5025 player->smooth_streaming = FALSE;
5026 player->videodec_linked = 0;
5027 player->audiodec_linked = 0;
5028 player->textsink_linked = 0;
5029 player->is_external_subtitle_present = FALSE;
5030 player->is_external_subtitle_added_now = FALSE;
5031 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5032 player->video360_metadata.is_spherical = -1;
5033 player->is_openal_plugin_used = FALSE;
5034 player->demux_pad_index = 0;
5035 player->subtitle_language_list = NULL;
5036 player->is_subtitle_force_drop = FALSE;
5038 _mmplayer_track_initialize(player);
5039 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5041 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5042 gint prebuffer_ms = 0, rebuffer_ms = 0;
5044 player->streamer = _mm_player_streaming_create();
5045 _mm_player_streaming_initialize(player->streamer, TRUE);
5047 mm_attrs_multiple_get(player->attrs, NULL,
5048 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5049 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5051 if (prebuffer_ms > 0) {
5052 prebuffer_ms = MAX(prebuffer_ms, 1000);
5053 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5056 if (rebuffer_ms > 0) {
5057 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5058 rebuffer_ms = MAX(rebuffer_ms, 1000);
5059 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5062 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5063 player->streamer->buffering_req.rebuffer_time);
5066 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5067 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5068 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5070 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5072 if (audio_codec_type != default_codec_type) {
5073 LOGD("audio dec sorting is required");
5074 player->need_audio_dec_sorting = TRUE;
5077 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5078 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5079 LOGD("video dec sorting is required");
5080 player->need_video_dec_sorting = TRUE;
5083 /* realize pipeline */
5084 ret = __mmplayer_gst_realize(player);
5085 if (ret != MM_ERROR_NONE)
5086 LOGE("fail to realize the player.");
5088 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5096 _mmplayer_unrealize(MMHandleType hplayer)
5098 mmplayer_t *player = (mmplayer_t *)hplayer;
5099 int ret = MM_ERROR_NONE;
5103 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5105 MMPLAYER_CMD_UNLOCK(player);
5106 /* destroy the gst bus msg thread which is created during realize.
5107 this funct have to be called before getting cmd lock. */
5108 _mmplayer_bus_msg_thread_destroy(player);
5109 MMPLAYER_CMD_LOCK(player);
5111 /* check current state */
5112 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5114 /* check async state transition */
5115 __mmplayer_check_async_state_transition(player);
5117 /* unrealize pipeline */
5118 ret = __mmplayer_gst_unrealize(player);
5120 if (!player->interrupted_by_resource) {
5121 int rm_ret = MM_ERROR_NONE;
5122 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5124 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5125 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5126 if (rm_ret != MM_ERROR_NONE)
5127 LOGE("failed to release [%d] resources", res_idx);
5136 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5138 mmplayer_t *player = (mmplayer_t *)hplayer;
5140 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5142 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5146 _mmplayer_get_state(MMHandleType hplayer, int *state)
5148 mmplayer_t *player = (mmplayer_t *)hplayer;
5150 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5152 *state = MMPLAYER_CURRENT_STATE(player);
5154 return MM_ERROR_NONE;
5158 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5160 GstElement *vol_element = NULL;
5161 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5165 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5167 /* check pipeline handle */
5168 if (!player->pipeline || !player->pipeline->audiobin) {
5169 LOGD("'%s' will be applied when audiobin is created", prop_name);
5171 /* NOTE : stored value will be used in create_audiobin
5172 * returning MM_ERROR_NONE here makes application to able to
5173 * set audio volume or mute at anytime.
5175 return MM_ERROR_NONE;
5178 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5179 volume_elem_id = MMPLAYER_A_SINK;
5181 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5183 LOGE("failed to get vol element %d", volume_elem_id);
5184 return MM_ERROR_PLAYER_INTERNAL;
5187 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5189 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5190 LOGE("there is no '%s' property", prop_name);
5191 return MM_ERROR_PLAYER_INTERNAL;
5194 if (!strcmp(prop_name, "volume")) {
5195 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5196 } else if (!strcmp(prop_name, "mute")) {
5197 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5199 LOGE("invalid property %s", prop_name);
5200 return MM_ERROR_PLAYER_INTERNAL;
5203 return MM_ERROR_NONE;
5207 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5209 int ret = MM_ERROR_NONE;
5210 mmplayer_t *player = (mmplayer_t *)hplayer;
5213 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5215 LOGD("volume = %f", volume);
5217 /* invalid factor range or not */
5218 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5219 LOGE("Invalid volume value");
5220 return MM_ERROR_INVALID_ARGUMENT;
5223 player->sound.volume = volume;
5225 ret = __mmplayer_gst_set_volume_property(player, "volume");
5232 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5234 mmplayer_t *player = (mmplayer_t *)hplayer;
5238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5239 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5241 *volume = player->sound.volume;
5243 LOGD("current vol = %f", *volume);
5246 return MM_ERROR_NONE;
5250 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5252 int ret = MM_ERROR_NONE;
5253 mmplayer_t *player = (mmplayer_t *)hplayer;
5256 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5258 LOGD("mute = %d", mute);
5260 player->sound.mute = mute;
5262 ret = __mmplayer_gst_set_volume_property(player, "mute");
5269 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5271 mmplayer_t *player = (mmplayer_t *)hplayer;
5275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5276 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5278 *mute = player->sound.mute;
5280 LOGD("current mute = %d", *mute);
5284 return MM_ERROR_NONE;
5288 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5290 mmplayer_t *player = (mmplayer_t *)hplayer;
5294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5296 player->audio_stream_changed_cb = callback;
5297 player->audio_stream_changed_cb_user_param = user_param;
5298 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5302 return MM_ERROR_NONE;
5306 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5308 mmplayer_t *player = (mmplayer_t *)hplayer;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 player->audio_decoded_cb = callback;
5315 player->audio_decoded_cb_user_param = user_param;
5316 player->audio_extract_opt = opt;
5317 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5321 return MM_ERROR_NONE;
5325 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5327 mmplayer_t *player = (mmplayer_t *)hplayer;
5331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5333 if (callback && !player->bufmgr)
5334 player->bufmgr = tbm_bufmgr_init(-1);
5336 player->set_mode.video_export = (callback) ? true : false;
5337 player->video_decoded_cb = callback;
5338 player->video_decoded_cb_user_param = user_param;
5340 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5344 return MM_ERROR_NONE;
5348 _mmplayer_start(MMHandleType hplayer)
5350 mmplayer_t *player = (mmplayer_t *)hplayer;
5351 gint ret = MM_ERROR_NONE;
5355 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5357 /* check current state */
5358 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5360 /* start pipeline */
5361 ret = _mmplayer_gst_start(player);
5362 if (ret != MM_ERROR_NONE)
5363 LOGE("failed to start player.");
5365 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5366 LOGD("force playing start even during buffering");
5367 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5375 /* NOTE: post "not supported codec message" to application
5376 * when one codec is not found during AUTOPLUGGING in MSL.
5377 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5378 * And, if any codec is not found, don't send message here.
5379 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5382 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5384 MMMessageParamType msg_param;
5385 memset(&msg_param, 0, sizeof(MMMessageParamType));
5386 gboolean post_msg_direct = FALSE;
5390 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5392 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5393 player->not_supported_codec, player->can_support_codec);
5395 if (player->not_found_demuxer) {
5396 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5397 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5399 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5400 MMPLAYER_FREEIF(msg_param.data);
5402 return MM_ERROR_NONE;
5405 if (player->not_supported_codec) {
5406 if (player->can_support_codec) {
5407 // There is one codec to play
5408 post_msg_direct = TRUE;
5410 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5411 post_msg_direct = TRUE;
5414 if (post_msg_direct) {
5415 MMMessageParamType msg_param;
5416 memset(&msg_param, 0, sizeof(MMMessageParamType));
5418 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5419 LOGW("not found AUDIO codec, posting error code to application.");
5421 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5422 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5423 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5424 LOGW("not found VIDEO codec, posting error code to application.");
5426 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5427 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5430 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5432 MMPLAYER_FREEIF(msg_param.data);
5434 return MM_ERROR_NONE;
5436 // no any supported codec case
5437 LOGW("not found any codec, posting error code to application.");
5439 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5440 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5441 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5443 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5444 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5447 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5449 MMPLAYER_FREEIF(msg_param.data);
5455 return MM_ERROR_NONE;
5458 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5460 GstState element_state = GST_STATE_VOID_PENDING;
5461 GstState element_pending_state = GST_STATE_VOID_PENDING;
5462 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5463 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5465 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5467 MMPLAYER_RECONFIGURE_LOCK(player);
5468 if (!player->gapless.reconfigure) {
5469 MMPLAYER_RECONFIGURE_UNLOCK(player);
5473 LOGI("reconfigure is under process");
5474 MMPLAYER_RECONFIGURE_WAIT(player);
5475 MMPLAYER_RECONFIGURE_UNLOCK(player);
5476 LOGI("reconfigure is completed.");
5478 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5479 &element_state, &element_pending_state, timeout * GST_SECOND);
5480 if (result == GST_STATE_CHANGE_FAILURE)
5481 LOGW("failed to get pipeline state in %d sec", timeout);
5486 /* NOTE : it should be able to call 'stop' anytime*/
5488 _mmplayer_stop(MMHandleType hplayer)
5490 mmplayer_t *player = (mmplayer_t *)hplayer;
5491 int ret = MM_ERROR_NONE;
5495 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5497 /* check current state */
5498 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5500 /* need to wait till the rebuilding pipeline is completed */
5501 __mmplayer_check_pipeline_reconfigure_state(player);
5502 MMPLAYER_RECONFIGURE_LOCK(player);
5503 __mmplayer_reset_gapless_state(player);
5504 MMPLAYER_RECONFIGURE_UNLOCK(player);
5506 /* NOTE : application should not wait for EOS after calling STOP */
5507 _mmplayer_cancel_eos_timer(player);
5510 player->seek_state = MMPLAYER_SEEK_NONE;
5513 ret = _mmplayer_gst_stop(player);
5515 if (ret != MM_ERROR_NONE)
5516 LOGE("failed to stop player.");
5524 _mmplayer_pause(MMHandleType hplayer)
5526 mmplayer_t *player = (mmplayer_t *)hplayer;
5527 gint64 pos_nsec = 0;
5528 gboolean async = FALSE;
5529 gint ret = MM_ERROR_NONE;
5533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5535 /* check current state */
5536 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5538 /* check pipline reconfigure state */
5539 __mmplayer_check_pipeline_reconfigure_state(player);
5541 switch (MMPLAYER_CURRENT_STATE(player)) {
5542 case MM_PLAYER_STATE_READY:
5544 /* check prepare async or not.
5545 * In the case of streaming playback, it's recommned to avoid blocking wait.
5547 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5548 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5550 /* Changing back sync of rtspsrc to async */
5551 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5552 LOGD("async prepare working mode for rtsp");
5558 case MM_PLAYER_STATE_PLAYING:
5560 /* NOTE : store current point to overcome some bad operation
5561 *(returning zero when getting current position in paused state) of some
5564 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5565 LOGW("getting current position failed in paused");
5567 player->last_position = pos_nsec;
5569 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5570 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5571 This causes problem is position calculation during normal pause resume scenarios also.
5572 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5573 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5574 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5575 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5581 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5582 LOGD("doing async pause in case of ms buff src");
5586 /* pause pipeline */
5587 ret = _mmplayer_gst_pause(player, async);
5589 if (ret != MM_ERROR_NONE)
5590 LOGE("failed to pause player. ret : 0x%x", ret);
5592 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5593 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5594 LOGE("failed to update display_rotation");
5602 /* in case of streaming, pause could take long time.*/
5604 _mmplayer_abort_pause(MMHandleType hplayer)
5606 mmplayer_t *player = (mmplayer_t *)hplayer;
5607 int ret = MM_ERROR_NONE;
5611 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5613 player->pipeline->mainbin,
5614 MM_ERROR_PLAYER_NOT_INITIALIZED);
5616 LOGD("set the pipeline state to READY");
5618 /* set state to READY */
5619 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5620 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5621 if (ret != MM_ERROR_NONE) {
5622 LOGE("fail to change state to READY");
5623 return MM_ERROR_PLAYER_INTERNAL;
5626 LOGD("succeeded in changing state to READY");
5631 _mmplayer_resume(MMHandleType hplayer)
5633 mmplayer_t *player = (mmplayer_t *)hplayer;
5634 int ret = MM_ERROR_NONE;
5635 gboolean async = FALSE;
5639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5641 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5642 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5643 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5647 /* Changing back sync mode rtspsrc to async */
5648 LOGD("async resume for rtsp case");
5652 /* check current state */
5653 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5655 ret = _mmplayer_gst_resume(player, async);
5656 if (ret != MM_ERROR_NONE)
5657 LOGE("failed to resume player.");
5659 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5660 LOGD("force resume even during buffering");
5661 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5670 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5672 mmplayer_t *player = (mmplayer_t *)hplayer;
5673 gint64 pos_nsec = 0;
5674 int ret = MM_ERROR_NONE;
5676 signed long long start = 0, stop = 0;
5677 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5680 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5681 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5683 /* The sound of video is not supported under 0.0 and over 2.0. */
5684 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5685 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5688 _mmplayer_set_mute(hplayer, mute);
5690 if (player->playback_rate == rate)
5691 return MM_ERROR_NONE;
5693 /* If the position is reached at start potion during fast backward, EOS is posted.
5694 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5696 player->playback_rate = rate;
5698 current_state = MMPLAYER_CURRENT_STATE(player);
5700 if (current_state != MM_PLAYER_STATE_PAUSED)
5701 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5703 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5705 if ((current_state == MM_PLAYER_STATE_PAUSED)
5706 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5707 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5708 pos_nsec = player->last_position;
5713 stop = GST_CLOCK_TIME_NONE;
5715 start = GST_CLOCK_TIME_NONE;
5719 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5720 player->playback_rate,
5722 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5723 GST_SEEK_TYPE_SET, start,
5724 GST_SEEK_TYPE_SET, stop)) {
5725 LOGE("failed to set speed playback");
5726 return MM_ERROR_PLAYER_SEEK;
5729 LOGD("succeeded to set speed playback as %0.1f", rate);
5733 return MM_ERROR_NONE;;
5737 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5739 mmplayer_t *player = (mmplayer_t *)hplayer;
5740 int ret = MM_ERROR_NONE;
5744 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5746 /* check pipline reconfigure state */
5747 __mmplayer_check_pipeline_reconfigure_state(player);
5749 ret = _mmplayer_gst_set_position(player, position, FALSE);
5757 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5759 mmplayer_t *player = (mmplayer_t *)hplayer;
5760 int ret = MM_ERROR_NONE;
5762 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5763 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5765 if (g_strrstr(player->type, "video/mpegts"))
5766 __mmplayer_update_duration_value(player);
5768 *duration = player->duration;
5773 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5775 mmplayer_t *player = (mmplayer_t *)hplayer;
5776 int ret = MM_ERROR_NONE;
5778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5780 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5786 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5788 mmplayer_t *player = (mmplayer_t *)hplayer;
5789 int ret = MM_ERROR_NONE;
5793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5795 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5803 __mmplayer_is_midi_type(gchar *str_caps)
5805 if ((g_strrstr(str_caps, "audio/midi")) ||
5806 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5807 (g_strrstr(str_caps, "application/x-smaf")) ||
5808 (g_strrstr(str_caps, "audio/x-imelody")) ||
5809 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5810 (g_strrstr(str_caps, "audio/xmf")) ||
5811 (g_strrstr(str_caps, "audio/mxmf"))) {
5820 __mmplayer_is_only_mp3_type(gchar *str_caps)
5822 if (g_strrstr(str_caps, "application/x-id3") ||
5823 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5829 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5831 GstStructure *caps_structure = NULL;
5832 gint samplerate = 0;
5836 MMPLAYER_RETURN_IF_FAIL(player && caps);
5838 caps_structure = gst_caps_get_structure(caps, 0);
5840 /* set stream information */
5841 gst_structure_get_int(caps_structure, "rate", &samplerate);
5842 gst_structure_get_int(caps_structure, "channels", &channels);
5844 mm_player_set_attribute((MMHandleType)player, NULL,
5845 "content_audio_samplerate", samplerate,
5846 "content_audio_channels", channels, NULL);
5848 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5852 __mmplayer_update_content_type_info(mmplayer_t *player)
5855 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5857 if (__mmplayer_is_midi_type(player->type)) {
5858 player->bypass_audio_effect = TRUE;
5862 if (!player->streamer) {
5863 LOGD("no need to check streaming type");
5867 if (g_strrstr(player->type, "application/x-hls")) {
5868 /* If it can't know exact type when it parses uri because of redirection case,
5869 * it will be fixed by typefinder or when doing autoplugging.
5871 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5872 player->streamer->is_adaptive_streaming = TRUE;
5873 } else if (g_strrstr(player->type, "application/dash+xml")) {
5874 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5875 player->streamer->is_adaptive_streaming = TRUE;
5878 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5879 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5880 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5882 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5883 if (player->streamer->is_adaptive_streaming)
5884 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5886 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5890 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5895 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5896 GstCaps *caps, gpointer data)
5898 mmplayer_t *player = (mmplayer_t *)data;
5903 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5905 /* store type string */
5906 MMPLAYER_FREEIF(player->type);
5907 player->type = gst_caps_to_string(caps);
5909 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5910 player, player->type, probability, gst_caps_get_size(caps));
5912 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5913 (g_strrstr(player->type, "audio/x-raw-int"))) {
5914 LOGE("not support media format");
5916 if (player->msg_posted == FALSE) {
5917 MMMessageParamType msg_param;
5918 memset(&msg_param, 0, sizeof(MMMessageParamType));
5920 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5921 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5923 /* don't post more if one was sent already */
5924 player->msg_posted = TRUE;
5929 __mmplayer_update_content_type_info(player);
5931 pad = gst_element_get_static_pad(tf, "src");
5933 LOGE("fail to get typefind src pad.");
5937 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5938 gboolean async = FALSE;
5939 LOGE("failed to autoplug %s", player->type);
5941 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5943 if (async && player->msg_posted == FALSE)
5944 __mmplayer_handle_missed_plugin(player);
5948 gst_object_unref(GST_OBJECT(pad));
5956 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5958 GstElement *decodebin = NULL;
5962 /* create decodebin */
5963 decodebin = gst_element_factory_make("decodebin", NULL);
5966 LOGE("fail to create decodebin");
5970 /* raw pad handling signal */
5971 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5972 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5974 /* no-more-pad pad handling signal */
5975 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5976 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5978 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5979 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5981 /* This signal is emitted when a pad for which there is no further possible
5982 decoding is added to the decodebin.*/
5983 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5984 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5986 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5987 before looking for any elements that can handle that stream.*/
5988 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5989 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5991 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5992 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5993 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5995 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5996 before looking for any elements that can handle that stream.*/
5997 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5998 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6000 /* This signal is emitted once decodebin has finished decoding all the data.*/
6001 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6002 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6004 /* This signal is emitted when a element is added to the bin.*/
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6006 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6013 __mmplayer_gst_make_queue2(mmplayer_t *player)
6015 GstElement *queue2 = NULL;
6016 gint64 dur_bytes = 0L;
6017 mmplayer_gst_element_t *mainbin = NULL;
6018 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6021 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6023 mainbin = player->pipeline->mainbin;
6025 queue2 = gst_element_factory_make("queue2", "queue2");
6027 LOGE("failed to create buffering queue element");
6031 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6032 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6034 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6036 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6037 * skip the pull mode(file or ring buffering) setting. */
6038 if (dur_bytes > 0) {
6039 if (!g_strrstr(player->type, "video/mpegts")) {
6040 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6041 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6047 _mm_player_streaming_set_queue2(player->streamer,
6051 (guint64)dur_bytes); /* no meaning at the moment */
6057 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6059 mmplayer_gst_element_t *mainbin = NULL;
6060 GstElement *decodebin = NULL;
6061 GstElement *queue2 = NULL;
6062 GstPad *sinkpad = NULL;
6063 GstPad *qsrcpad = NULL;
6066 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6068 mainbin = player->pipeline->mainbin;
6070 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6072 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6073 LOGW("need to check: muxed buffer is not null");
6076 queue2 = __mmplayer_gst_make_queue2(player);
6078 LOGE("failed to make queue2");
6082 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6083 LOGE("failed to add buffering queue");
6087 sinkpad = gst_element_get_static_pad(queue2, "sink");
6088 qsrcpad = gst_element_get_static_pad(queue2, "src");
6090 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6091 LOGE("failed to link [%s:%s]-[%s:%s]",
6092 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6096 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6097 LOGE("failed to sync queue2 state with parent");
6101 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6102 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6106 gst_object_unref(GST_OBJECT(sinkpad));
6110 /* create decodebin */
6111 decodebin = _mmplayer_gst_make_decodebin(player);
6113 LOGE("failed to make decodebin");
6117 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6118 LOGE("failed to add decodebin");
6122 /* to force caps on the decodebin element and avoid reparsing stuff by
6123 * typefind. It also avoids a deadlock in the way typefind activates pads in
6124 * the state change */
6125 g_object_set(decodebin, "sink-caps", caps, NULL);
6127 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6129 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6130 LOGE("failed to link [%s:%s]-[%s:%s]",
6131 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6135 gst_object_unref(GST_OBJECT(sinkpad));
6137 gst_object_unref(GST_OBJECT(qsrcpad));
6140 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6141 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6143 /* set decodebin property about buffer in streaming playback. *
6144 * in case of HLS/DASH, it does not need to have big buffer *
6145 * because it is kind of adaptive streaming. */
6146 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6147 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6148 gint high_percent = 0;
6150 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6151 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6153 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6155 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6157 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6158 "high-percent", high_percent,
6159 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6160 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6161 "max-size-buffers", 0, NULL); // disable or automatic
6164 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6165 LOGE("failed to sync decodebin state with parent");
6176 gst_object_unref(GST_OBJECT(sinkpad));
6179 gst_object_unref(GST_OBJECT(qsrcpad));
6182 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6183 * You need to explicitly set elements to the NULL state before
6184 * dropping the final reference, to allow them to clean up.
6186 gst_element_set_state(queue2, GST_STATE_NULL);
6188 /* And, it still has a parent "player".
6189 * You need to let the parent manage the object instead of unreffing the object directly.
6191 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6192 gst_object_unref(queue2);
6197 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6198 * You need to explicitly set elements to the NULL state before
6199 * dropping the final reference, to allow them to clean up.
6201 gst_element_set_state(decodebin, GST_STATE_NULL);
6203 /* And, it still has a parent "player".
6204 * You need to let the parent manage the object instead of unreffing the object directly.
6207 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6208 gst_object_unref(decodebin);
6216 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6220 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6221 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6223 LOGD("class : %s, mime : %s", factory_class, mime);
6225 /* add missing plugin */
6226 /* NOTE : msl should check missing plugin for image mime type.
6227 * Some motion jpeg clips can have playable audio track.
6228 * So, msl have to play audio after displaying popup written video format not supported.
6230 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6231 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6232 LOGD("not found demuxer");
6233 player->not_found_demuxer = TRUE;
6234 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6240 if (!g_strrstr(factory_class, "Demuxer")) {
6241 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6242 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6243 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6245 /* check that clip have multi tracks or not */
6246 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6247 LOGD("video plugin is already linked");
6249 LOGW("add VIDEO to missing plugin");
6250 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6251 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6253 } else if (g_str_has_prefix(mime, "audio")) {
6254 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6255 LOGD("audio plugin is already linked");
6257 LOGW("add AUDIO to missing plugin");
6258 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6259 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6267 return MM_ERROR_NONE;
6271 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6273 mmplayer_t *player = (mmplayer_t *)data;
6277 MMPLAYER_RETURN_IF_FAIL(player);
6279 /* remove fakesink. */
6280 if (!_mmplayer_gst_remove_fakesink(player,
6281 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6282 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6283 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6284 * source element are not same. To overcome this situation, this function will called
6285 * several places and several times. Therefore, this is not an error case.
6290 LOGD("[handle: %p] pipeline has completely constructed", player);
6292 if ((player->msg_posted == FALSE) &&
6293 (player->cmd >= MMPLAYER_COMMAND_START))
6294 __mmplayer_handle_missed_plugin(player);
6296 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6300 __mmplayer_check_profile(void)
6303 static int profile_tv = -1;
6305 if (__builtin_expect(profile_tv != -1, 1))
6308 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6309 switch (*profileName) {
6324 __mmplayer_get_next_uri(mmplayer_t *player)
6326 mmplayer_parse_profile_t profile;
6328 guint num_of_list = 0;
6331 num_of_list = g_list_length(player->uri_info.uri_list);
6332 uri_idx = player->uri_info.uri_idx;
6334 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6335 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6336 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6338 LOGW("next uri does not exist");
6342 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6343 LOGE("failed to parse profile");
6347 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6348 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6349 LOGW("uri type is not supported(%d)", profile.uri_type);
6353 LOGD("success to find next uri %d", uri_idx);
6357 if (!uri || uri_idx == num_of_list) {
6358 LOGE("failed to find next uri");
6362 player->uri_info.uri_idx = uri_idx;
6363 if (mm_player_set_attribute((MMHandleType)player, NULL,
6364 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6365 LOGE("failed to set attribute");
6369 SECURE_LOGD("next playback uri: %s", uri);
6374 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6376 #define REPEAT_COUNT_INFINITE -1
6377 #define REPEAT_COUNT_MIN 2
6378 #define ORIGINAL_URI_ONLY 1
6380 MMHandleType attrs = 0;
6384 guint num_of_uri = 0;
6385 int profile_tv = -1;
6389 LOGD("checking for gapless play option");
6391 if (player->build_audio_offload) {
6392 LOGE("offload path is not supportable.");
6396 if (player->pipeline->textbin) {
6397 LOGE("subtitle path is enabled. gapless play is not supported.");
6401 attrs = MMPLAYER_GET_ATTRS(player);
6403 LOGE("fail to get attributes.");
6407 mm_attrs_multiple_get(player->attrs, NULL,
6408 "content_video_found", &video,
6409 "profile_play_count", &count,
6410 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6412 /* gapless playback is not supported in case of video at TV profile. */
6413 profile_tv = __mmplayer_check_profile();
6414 if (profile_tv && video) {
6415 LOGW("not support video gapless playback");
6419 /* check repeat count in case of audio */
6421 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6422 LOGW("gapless is disabled");
6426 num_of_uri = g_list_length(player->uri_info.uri_list);
6428 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6430 if (num_of_uri == ORIGINAL_URI_ONLY) {
6431 /* audio looping path */
6432 if (count >= REPEAT_COUNT_MIN) {
6433 /* decrease play count */
6434 /* we succeeded to rewind. update play count and then wait for next EOS */
6436 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6437 } else if (count != REPEAT_COUNT_INFINITE) {
6438 LOGD("there is no next uri and no repeat");
6441 LOGD("looping cnt %d", count);
6443 /* gapless playback path */
6444 if (!__mmplayer_get_next_uri(player)) {
6445 LOGE("failed to get next uri");
6452 LOGE("unable to play gapless path. EOS will be posted soon");
6457 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6459 mmplayer_selector_t *selector = &player->selector[type];
6460 mmplayer_gst_element_t *sinkbin = NULL;
6461 main_element_id_e selectorId = MMPLAYER_M_NUM;
6462 main_element_id_e sinkId = MMPLAYER_M_NUM;
6463 GstPad *srcpad = NULL;
6464 GstPad *sinkpad = NULL;
6465 gboolean send_notice = FALSE;
6468 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6470 LOGD("type %d", type);
6473 case MM_PLAYER_TRACK_TYPE_AUDIO:
6474 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6475 sinkId = MMPLAYER_A_BIN;
6476 sinkbin = player->pipeline->audiobin;
6478 case MM_PLAYER_TRACK_TYPE_VIDEO:
6479 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6480 sinkId = MMPLAYER_V_BIN;
6481 sinkbin = player->pipeline->videobin;
6484 case MM_PLAYER_TRACK_TYPE_TEXT:
6485 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6486 sinkId = MMPLAYER_T_BIN;
6487 sinkbin = player->pipeline->textbin;
6490 LOGE("requested type is not supportable");
6495 if (player->pipeline->mainbin[selectorId].gst) {
6498 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6500 if (selector->event_probe_id != 0)
6501 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6502 selector->event_probe_id = 0;
6504 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6505 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6507 if (srcpad && sinkpad) {
6508 /* after getting drained signal there is no data flows, so no need to do pad_block */
6509 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6510 gst_pad_unlink(srcpad, sinkpad);
6512 /* send custom event to sink pad to handle it at video sink */
6514 LOGD("send custom event to sinkpad");
6515 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6516 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6517 gst_pad_send_event(sinkpad, event);
6521 gst_object_unref(sinkpad);
6524 gst_object_unref(srcpad);
6527 LOGD("selector release");
6529 /* release and unref requests pad from the selector */
6530 for (n = 0; n < selector->channels->len; n++) {
6531 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6532 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6534 g_ptr_array_set_size(selector->channels, 0);
6536 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6537 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6539 player->pipeline->mainbin[selectorId].gst = NULL;
6547 __mmplayer_deactivate_old_path(mmplayer_t *player)
6550 MMPLAYER_RETURN_IF_FAIL(player);
6552 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6553 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6554 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6555 LOGE("deactivate selector error");
6559 _mmplayer_track_destroy(player);
6560 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6562 if (player->streamer) {
6563 _mm_player_streaming_initialize(player->streamer, FALSE);
6564 _mm_player_streaming_destroy(player->streamer);
6565 player->streamer = NULL;
6568 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6574 if (!player->msg_posted) {
6575 MMMessageParamType msg = {0,};
6578 msg.code = MM_ERROR_PLAYER_INTERNAL;
6579 LOGE("gapless_uri_play> deactivate error");
6581 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6582 player->msg_posted = TRUE;
6588 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6590 int result = MM_ERROR_NONE;
6591 mmplayer_t *player = (mmplayer_t *)hplayer;
6594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6595 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6597 if (mm_player_set_attribute(hplayer, NULL,
6598 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6599 LOGE("failed to set attribute");
6600 result = MM_ERROR_PLAYER_INTERNAL;
6602 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6603 LOGE("failed to add the original uri in the uri list.");
6611 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6613 mmplayer_t *player = (mmplayer_t *)hplayer;
6614 guint num_of_list = 0;
6618 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6619 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6621 if (player->pipeline && player->pipeline->textbin) {
6622 LOGE("subtitle path is enabled.");
6623 return MM_ERROR_PLAYER_INVALID_STATE;
6626 num_of_list = g_list_length(player->uri_info.uri_list);
6628 if (is_first_path) {
6629 if (num_of_list == 0) {
6630 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6631 SECURE_LOGD("add original path : %s", uri);
6633 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6634 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6636 SECURE_LOGD("change original path : %s", uri);
6639 MMHandleType attrs = 0;
6640 attrs = MMPLAYER_GET_ATTRS(player);
6642 if (num_of_list == 0) {
6643 char *original_uri = NULL;
6646 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6648 if (!original_uri) {
6649 LOGE("there is no original uri.");
6650 return MM_ERROR_PLAYER_INVALID_STATE;
6653 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6654 player->uri_info.uri_idx = 0;
6656 SECURE_LOGD("add original path at first : %s", original_uri);
6660 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6661 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6665 return MM_ERROR_NONE;
6669 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6671 mmplayer_t *player = (mmplayer_t *)hplayer;
6672 char *next_uri = NULL;
6673 guint num_of_list = 0;
6676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6678 num_of_list = g_list_length(player->uri_info.uri_list);
6680 if (num_of_list > 0) {
6681 gint uri_idx = player->uri_info.uri_idx;
6683 if (uri_idx < num_of_list-1)
6688 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6689 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6691 *uri = g_strdup(next_uri);
6695 return MM_ERROR_NONE;
6699 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6700 GstCaps *caps, gpointer data)
6702 mmplayer_t *player = (mmplayer_t *)data;
6703 const gchar *klass = NULL;
6704 const gchar *mime = NULL;
6705 gchar *caps_str = NULL;
6707 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6708 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6709 caps_str = gst_caps_to_string(caps);
6711 LOGW("unknown type of caps : %s from %s",
6712 caps_str, GST_ELEMENT_NAME(elem));
6714 MMPLAYER_FREEIF(caps_str);
6716 /* There is no available codec. */
6717 __mmplayer_check_not_supported_codec(player, klass, mime);
6721 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6722 GstCaps *caps, gpointer data)
6724 mmplayer_t *player = (mmplayer_t *)data;
6725 const char *mime = NULL;
6726 gboolean ret = TRUE;
6728 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6729 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6731 if (g_str_has_prefix(mime, "audio")) {
6732 GstStructure *caps_structure = NULL;
6733 gint samplerate = 0;
6735 gchar *caps_str = NULL;
6737 caps_structure = gst_caps_get_structure(caps, 0);
6738 gst_structure_get_int(caps_structure, "rate", &samplerate);
6739 gst_structure_get_int(caps_structure, "channels", &channels);
6741 if ((channels > 0 && samplerate == 0)) {
6742 LOGD("exclude audio...");
6746 caps_str = gst_caps_to_string(caps);
6747 /* set it directly because not sent by TAG */
6748 if (g_strrstr(caps_str, "mobile-xmf"))
6749 mm_player_set_attribute((MMHandleType)player, NULL,
6750 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6752 MMPLAYER_FREEIF(caps_str);
6753 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6754 LOGD("already video linked");
6757 LOGD("found new stream");
6764 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6766 gboolean ret = FALSE;
6767 GDBusConnection *conn = NULL;
6769 GVariant *result = NULL;
6770 const gchar *dbus_device_type = NULL;
6771 const gchar *dbus_ret = NULL;
6774 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6776 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6781 result = g_dbus_connection_call_sync(conn,
6782 "org.pulseaudio.Server",
6783 "/org/pulseaudio/StreamManager",
6784 "org.pulseaudio.StreamManager",
6785 "GetCurrentMediaRoutingPath",
6786 g_variant_new("(s)", "out"),
6787 G_VARIANT_TYPE("(ss)"),
6788 G_DBUS_CALL_FLAGS_NONE,
6792 if (!result || err) {
6793 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6798 /* device type is listed in stream-map.json at mmfw-sysconf */
6799 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6801 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6802 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6805 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6806 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6807 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6808 LOGD("audio offload is supportable");
6814 LOGD("audio offload is not supportable");
6817 g_variant_unref(result);
6819 g_object_unref(conn);
6824 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6826 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6827 gint64 position = 0;
6829 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6830 player->pipeline && player->pipeline->mainbin);
6832 MMPLAYER_CMD_LOCK(player);
6833 current_state = MMPLAYER_CURRENT_STATE(player);
6835 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6836 LOGW("getting current position failed in paused");
6838 _mmplayer_unrealize((MMHandleType)player);
6839 _mmplayer_realize((MMHandleType)player);
6841 _mmplayer_set_position((MMHandleType)player, position);
6843 /* async not to be blocked in streaming case */
6844 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6846 _mmplayer_pause((MMHandleType)player);
6848 if (current_state == MM_PLAYER_STATE_PLAYING)
6849 _mmplayer_start((MMHandleType)player);
6850 MMPLAYER_CMD_UNLOCK(player);
6852 LOGD("rebuilding audio pipeline is completed.");
6855 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6857 mmplayer_t *player = (mmplayer_t *)user_data;
6858 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6859 gboolean is_supportable = FALSE;
6861 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6862 LOGW("failed to get device type");
6864 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6866 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6867 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6868 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6869 LOGD("ignore this dev connected info");
6873 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6874 if (player->build_audio_offload == is_supportable) {
6875 LOGD("keep current pipeline without re-building");
6879 /* rebuild pipeline */
6880 LOGD("re-build pipeline - offload: %d", is_supportable);
6881 player->build_audio_offload = FALSE;
6882 __mmplayer_rebuild_audio_pipeline(player);
6888 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6890 unsigned int id = 0;
6892 if (player->audio_device_cb_id != 0) {
6893 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6897 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6898 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6899 LOGD("added device connected cb (%u)", id);
6900 player->audio_device_cb_id = id;
6902 LOGW("failed to add device connected cb");
6909 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6911 mmplayer_t *player = (mmplayer_t *)hplayer;
6914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6915 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6917 *activated = player->build_audio_offload;
6919 LOGD("offload activated : %d", (int)*activated);
6922 return MM_ERROR_NONE;
6926 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6929 this function need to be updated according to the supported media format
6930 @see player->ini.audio_offload_media_format */
6932 if (__mmplayer_is_only_mp3_type(player->type)) {
6933 LOGD("offload supportable media format type");
6941 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6943 gboolean ret = FALSE;
6944 GstElementFactory *factory = NULL;
6947 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6949 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6950 if (!__mmplayer_is_offload_supported_type(player))
6953 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6954 LOGD("there is no audio offload sink");
6958 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6959 LOGW("there is no audio device type to support offload");
6963 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6965 LOGW("there is no installed audio offload sink element");
6968 gst_object_unref(factory);
6970 if (__mmplayer_acquire_hw_resource(player,
6971 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6972 LOGE("failed to acquire audio offload decoder resource");
6976 if (!__mmplayer_add_audio_device_connected_cb(player))
6979 if (!__mmplayer_is_audio_offload_device_type(player))
6982 LOGD("audio offload can be built");
6987 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6993 static GstAutoplugSelectResult
6994 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6996 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6997 int audio_offload = 0;
6999 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7000 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7002 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7003 LOGD("expose audio path to build offload output path");
7004 player->build_audio_offload = TRUE;
7005 /* update codec info */
7006 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7007 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7008 player->audiodec_linked = 1;
7010 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7014 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7015 And need to consider the multi-track audio content.
7016 There is no HW audio decoder in public. */
7018 /* set stream information */
7019 if (!player->audiodec_linked)
7020 __mmplayer_set_audio_attrs(player, caps);
7022 /* update codec info */
7023 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7024 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7025 player->audiodec_linked = 1;
7027 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7029 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7030 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7032 /* mark video decoder for acquire */
7033 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7034 LOGW("video decoder resource is already acquired, skip it.");
7035 ret = GST_AUTOPLUG_SELECT_SKIP;
7039 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7040 LOGE("failed to acquire video decoder resource");
7041 ret = GST_AUTOPLUG_SELECT_SKIP;
7044 player->interrupted_by_resource = FALSE;
7047 /* update codec info */
7048 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7049 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7050 player->videodec_linked = 1;
7058 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7059 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7061 #define DEFAULT_IDX 0xFFFF
7062 #define MIN_FACTORY_NUM 2
7063 mmplayer_t *player = (mmplayer_t *)data;
7064 GValueArray *new_factories = NULL;
7065 GValue val = { 0, };
7066 GstElementFactory *factory = NULL;
7067 const gchar *klass = NULL;
7068 gchar *factory_name = NULL;
7069 guint hw_dec_idx = DEFAULT_IDX;
7070 guint first_sw_dec_idx = DEFAULT_IDX;
7071 guint last_sw_dec_idx = DEFAULT_IDX;
7072 guint new_pos = DEFAULT_IDX;
7073 guint rm_pos = DEFAULT_IDX;
7074 int audio_codec_type;
7075 int video_codec_type;
7076 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7078 if (factories->n_values < MIN_FACTORY_NUM)
7081 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7082 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7085 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7087 for (int i = 0 ; i < factories->n_values ; i++) {
7088 gchar *hw_dec_info = NULL;
7089 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7091 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7092 klass = gst_element_factory_get_klass(factory);
7093 factory_name = GST_OBJECT_NAME(factory);
7096 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7098 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7099 if (!player->need_audio_dec_sorting) {
7100 LOGD("sorting is not required");
7103 codec_type = audio_codec_type;
7104 hw_dec_info = player->ini.audiocodec_element_hw;
7105 sw_dec_info = player->ini.audiocodec_element_sw;
7106 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7107 if (!player->need_video_dec_sorting) {
7108 LOGD("sorting is not required");
7111 codec_type = video_codec_type;
7112 hw_dec_info = player->ini.videocodec_element_hw;
7113 sw_dec_info = player->ini.videocodec_element_sw;
7118 if (g_strrstr(factory_name, hw_dec_info)) {
7121 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7122 if (strstr(factory_name, sw_dec_info[j])) {
7123 last_sw_dec_idx = i;
7124 if (first_sw_dec_idx == DEFAULT_IDX) {
7125 first_sw_dec_idx = i;
7130 if (first_sw_dec_idx == DEFAULT_IDX)
7131 LOGW("unknown codec %s", factory_name);
7135 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7138 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7139 if (hw_dec_idx < first_sw_dec_idx)
7141 new_pos = first_sw_dec_idx;
7142 rm_pos = hw_dec_idx + 1;
7143 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7144 if (last_sw_dec_idx < hw_dec_idx)
7146 new_pos = last_sw_dec_idx + 1;
7147 rm_pos = hw_dec_idx;
7152 /* change position - insert H/W decoder according to the new position */
7153 new_factories = g_value_array_copy(factories);
7154 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7155 g_value_init (&val, G_TYPE_OBJECT);
7156 g_value_set_object (&val, factory);
7157 g_value_array_insert(new_factories, new_pos, &val);
7158 g_value_unset (&val);
7159 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7161 for (int i = 0 ; i < new_factories->n_values ; i++) {
7162 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7164 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7165 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7167 LOGE("[Re-arranged] failed to get factory object");
7170 return new_factories;
7174 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7175 GstCaps *caps, GstElementFactory *factory, gpointer data)
7177 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7178 mmplayer_t *player = (mmplayer_t *)data;
7180 gchar *factory_name = NULL;
7181 gchar *caps_str = NULL;
7182 const gchar *klass = NULL;
7185 factory_name = GST_OBJECT_NAME(factory);
7186 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7187 caps_str = gst_caps_to_string(caps);
7189 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7191 /* store type string */
7192 if (player->type == NULL) {
7193 player->type = gst_caps_to_string(caps);
7194 __mmplayer_update_content_type_info(player);
7197 /* filtering exclude keyword */
7198 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7199 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7200 LOGW("skipping [%s] by exculde keyword [%s]",
7201 factory_name, player->ini.exclude_element_keyword[idx]);
7203 result = GST_AUTOPLUG_SELECT_SKIP;
7208 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7209 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7210 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7211 factory_name, player->ini.unsupported_codec_keyword[idx]);
7212 result = GST_AUTOPLUG_SELECT_SKIP;
7217 /* exclude webm format */
7218 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7219 * because webm format is not supportable.
7220 * If webm is disabled in "autoplug-continue", there is no state change
7221 * failure or error because the decodebin will expose the pad directly.
7222 * It make MSL invoke _prepare_async_callback.
7223 * So, we need to disable webm format in "autoplug-select" */
7224 if (caps_str && strstr(caps_str, "webm")) {
7225 LOGW("webm is not supported");
7226 result = GST_AUTOPLUG_SELECT_SKIP;
7230 /* check factory class for filtering */
7231 /* NOTE : msl don't need to use image plugins.
7232 * So, those plugins should be skipped for error handling.
7234 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7235 LOGD("skipping [%s] by not required", factory_name);
7236 result = GST_AUTOPLUG_SELECT_SKIP;
7240 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7241 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7242 // TO CHECK : subtitle if needed, add subparse exception.
7243 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7244 result = GST_AUTOPLUG_SELECT_SKIP;
7248 if (g_strrstr(factory_name, "mpegpsdemux")) {
7249 LOGD("skipping PS container - not support");
7250 result = GST_AUTOPLUG_SELECT_SKIP;
7254 if (g_strrstr(factory_name, "mssdemux"))
7255 player->smooth_streaming = TRUE;
7257 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7258 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7261 GstStructure *str = NULL;
7262 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7264 /* don't make video because of not required */
7265 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7266 (!player->set_mode.video_export)) {
7267 LOGD("no need video decoding, expose pad");
7268 result = GST_AUTOPLUG_SELECT_EXPOSE;
7272 /* get w/h for omx state-tune */
7273 /* FIXME: deprecated? */
7274 str = gst_caps_get_structure(caps, 0);
7275 gst_structure_get_int(str, "width", &width);
7278 if (player->v_stream_caps) {
7279 gst_caps_unref(player->v_stream_caps);
7280 player->v_stream_caps = NULL;
7283 player->v_stream_caps = gst_caps_copy(caps);
7284 LOGD("take caps for video state tune");
7285 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7289 if (g_strrstr(klass, "Codec/Decoder")) {
7290 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7291 if (result != GST_AUTOPLUG_SELECT_TRY) {
7292 LOGW("skip add decoder");
7298 MMPLAYER_FREEIF(caps_str);
7304 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7307 //mmplayer_t *player = (mmplayer_t *)data;
7308 GstCaps *caps = NULL;
7310 LOGD("[Decodebin2] pad-removed signal");
7312 caps = gst_pad_query_caps(new_pad, NULL);
7314 LOGW("query caps is NULL");
7318 gchar *caps_str = NULL;
7319 caps_str = gst_caps_to_string(caps);
7321 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7323 MMPLAYER_FREEIF(caps_str);
7324 gst_caps_unref(caps);
7328 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7330 mmplayer_t *player = (mmplayer_t *)data;
7331 GstIterator *iter = NULL;
7332 GValue item = { 0, };
7334 gboolean done = FALSE;
7335 gboolean is_all_drained = TRUE;
7338 MMPLAYER_RETURN_IF_FAIL(player);
7340 LOGD("__mmplayer_gst_decode_drained");
7342 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7343 LOGW("Fail to get cmd lock");
7347 if (!__mmplayer_verify_gapless_play_path(player)) {
7348 LOGD("decoding is finished.");
7349 MMPLAYER_CMD_UNLOCK(player);
7353 _mmplayer_set_reconfigure_state(player, TRUE);
7354 MMPLAYER_CMD_UNLOCK(player);
7356 /* check decodebin src pads whether they received EOS or not */
7357 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7360 switch (gst_iterator_next(iter, &item)) {
7361 case GST_ITERATOR_OK:
7362 pad = g_value_get_object(&item);
7363 if (pad && !GST_PAD_IS_EOS(pad)) {
7364 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7365 is_all_drained = FALSE;
7368 g_value_reset(&item);
7370 case GST_ITERATOR_RESYNC:
7371 gst_iterator_resync(iter);
7373 case GST_ITERATOR_ERROR:
7374 case GST_ITERATOR_DONE:
7379 g_value_unset(&item);
7380 gst_iterator_free(iter);
7382 if (!is_all_drained) {
7383 LOGD("Wait util the all pads get EOS.");
7388 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7389 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7391 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7392 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7393 __mmplayer_deactivate_old_path(player);
7399 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7401 mmplayer_t *player = (mmplayer_t *)data;
7402 const gchar *klass = NULL;
7403 gchar *factory_name = NULL;
7405 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7406 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7408 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7410 if (__mmplayer_add_dump_buffer_probe(player, element))
7411 LOGD("add buffer probe");
7413 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7414 gchar *selected = NULL;
7415 selected = g_strdup(GST_ELEMENT_NAME(element));
7416 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7419 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7420 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7421 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7423 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7424 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7426 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7427 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7428 "max-video-width", player->adaptive_info.limit.width,
7429 "max-video-height", player->adaptive_info.limit.height, NULL);
7431 } else if (g_strrstr(klass, "Demuxer")) {
7433 LOGD("plugged element is demuxer. take it");
7435 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7436 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7439 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7440 int surface_type = 0;
7442 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7445 // to support trust-zone only
7446 if (g_strrstr(factory_name, "asfdemux")) {
7447 LOGD("set file-location %s", player->profile.uri);
7448 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7449 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7450 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7451 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7452 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7453 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7454 (__mmplayer_is_only_mp3_type(player->type))) {
7455 LOGD("[mpegaudioparse] set streaming pull mode.");
7456 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7458 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7459 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7462 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7463 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7464 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7466 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7467 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7469 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7470 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7471 (MMPLAYER_IS_DASH_STREAMING(player))) {
7472 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7473 _mm_player_streaming_set_multiqueue(player->streamer, element);
7474 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7483 __mmplayer_release_misc(mmplayer_t *player)
7486 bool cur_mode = player->set_mode.rich_audio;
7489 MMPLAYER_RETURN_IF_FAIL(player);
7491 player->sent_bos = FALSE;
7492 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7494 player->seek_state = MMPLAYER_SEEK_NONE;
7496 player->total_bitrate = 0;
7497 player->total_maximum_bitrate = 0;
7499 player->not_found_demuxer = 0;
7501 player->last_position = 0;
7502 player->duration = 0;
7503 player->http_content_size = 0;
7504 player->not_supported_codec = MISSING_PLUGIN_NONE;
7505 player->can_support_codec = FOUND_PLUGIN_NONE;
7506 player->pending_seek.is_pending = false;
7507 player->pending_seek.pos = 0;
7508 player->msg_posted = FALSE;
7509 player->has_many_types = FALSE;
7510 player->is_subtitle_force_drop = FALSE;
7511 player->play_subtitle = FALSE;
7512 player->adjust_subtitle_pos = 0;
7513 player->has_closed_caption = FALSE;
7514 player->set_mode.video_export = false;
7515 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7516 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7518 player->set_mode.rich_audio = cur_mode;
7520 if (player->audio_device_cb_id > 0 &&
7521 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7522 LOGW("failed to remove audio device_connected_callback");
7523 player->audio_device_cb_id = 0;
7525 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7526 player->bitrate[i] = 0;
7527 player->maximum_bitrate[i] = 0;
7530 /* free memory related to audio effect */
7531 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7533 if (player->adaptive_info.var_list) {
7534 g_list_free_full(player->adaptive_info.var_list, g_free);
7535 player->adaptive_info.var_list = NULL;
7538 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7539 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7540 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7542 /* Reset video360 settings to their defaults in case if the pipeline is to be
7545 player->video360_metadata.is_spherical = -1;
7546 player->is_openal_plugin_used = FALSE;
7548 player->is_content_spherical = FALSE;
7549 player->is_video360_enabled = TRUE;
7550 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7551 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7552 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7553 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7554 player->video360_zoom = 1.0f;
7555 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7556 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7558 player->sound.rg_enable = false;
7560 __mmplayer_initialize_video_roi(player);
7565 __mmplayer_release_misc_post(mmplayer_t *player)
7567 char *original_uri = NULL;
7570 /* player->pipeline is already released before. */
7571 MMPLAYER_RETURN_IF_FAIL(player);
7573 player->video_decoded_cb = NULL;
7574 player->video_decoded_cb_user_param = NULL;
7575 player->video_stream_prerolled = false;
7577 player->audio_decoded_cb = NULL;
7578 player->audio_decoded_cb_user_param = NULL;
7579 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7581 player->audio_stream_changed_cb = NULL;
7582 player->audio_stream_changed_cb_user_param = NULL;
7584 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7586 /* clean found audio decoders */
7587 if (player->audio_decoders) {
7588 GList *a_dec = player->audio_decoders;
7589 for (; a_dec; a_dec = g_list_next(a_dec)) {
7590 gchar *name = a_dec->data;
7591 MMPLAYER_FREEIF(name);
7593 g_list_free(player->audio_decoders);
7594 player->audio_decoders = NULL;
7597 /* clean the uri list except original uri */
7598 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7599 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7601 LOGW("failed to get original uri info");
7603 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7604 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7606 GList *uri_list = player->uri_info.uri_list;
7607 for (; uri_list; uri_list = g_list_next(uri_list)) {
7608 gchar *uri = uri_list->data;
7609 if (original_uri != uri)
7610 MMPLAYER_FREEIF(uri);
7614 /* clear the audio stream buffer list */
7615 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7617 /* clear the video stream bo list */
7618 __mmplayer_video_stream_destroy_bo_list(player);
7619 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7621 if (player->profile.input_mem.buf) {
7622 free(player->profile.input_mem.buf);
7623 player->profile.input_mem.buf = NULL;
7625 player->profile.input_mem.len = 0;
7626 player->profile.input_mem.offset = 0;
7628 player->uri_info.uri_idx = 0;
7633 __mmplayer_check_subtitle(mmplayer_t *player)
7635 MMHandleType attrs = 0;
7636 char *subtitle_uri = NULL;
7640 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7642 /* get subtitle attribute */
7643 attrs = MMPLAYER_GET_ATTRS(player);
7647 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7648 if (!subtitle_uri || !strlen(subtitle_uri))
7651 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7652 player->is_external_subtitle_present = TRUE;
7660 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7662 MMPLAYER_RETURN_IF_FAIL(player);
7664 if (player->eos_timer) {
7665 LOGD("cancel eos timer");
7666 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7667 player->eos_timer = 0;
7674 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7678 MMPLAYER_RETURN_IF_FAIL(player);
7679 MMPLAYER_RETURN_IF_FAIL(sink);
7681 player->sink_elements = g_list_append(player->sink_elements, sink);
7687 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7691 MMPLAYER_RETURN_IF_FAIL(player);
7692 MMPLAYER_RETURN_IF_FAIL(sink);
7694 player->sink_elements = g_list_remove(player->sink_elements, sink);
7700 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7701 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7703 mmplayer_signal_item_t *item = NULL;
7706 MMPLAYER_RETURN_IF_FAIL(player);
7708 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7709 LOGE("invalid signal type [%d]", type);
7713 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7715 LOGE("cannot connect signal [%s]", signal);
7720 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7721 player->signals[type] = g_list_append(player->signals[type], item);
7727 /* NOTE : be careful with calling this api. please refer to below glib comment
7728 * glib comment : Note that there is a bug in GObject that makes this function much
7729 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7730 * will no longer be called, but, the signal handler is not currently disconnected.
7731 * If the instance is itself being freed at the same time than this doesn't matter,
7732 * since the signal will automatically be removed, but if instance persists,
7733 * then the signal handler will leak. You should not remove the signal yourself
7734 * because in a future versions of GObject, the handler will automatically be
7737 * It's possible to work around this problem in a way that will continue to work
7738 * with future versions of GObject by checking that the signal handler is still
7739 * connected before disconnected it:
7741 * if (g_signal_handler_is_connected(instance, id))
7742 * g_signal_handler_disconnect(instance, id);
7745 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7747 GList *sig_list = NULL;
7748 mmplayer_signal_item_t *item = NULL;
7752 MMPLAYER_RETURN_IF_FAIL(player);
7754 LOGD("release signals type : %d", type);
7756 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7757 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7758 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7759 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7760 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7761 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7765 sig_list = player->signals[type];
7767 for (; sig_list; sig_list = sig_list->next) {
7768 item = sig_list->data;
7770 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7771 if (g_signal_handler_is_connected(item->obj, item->sig))
7772 g_signal_handler_disconnect(item->obj, item->sig);
7775 MMPLAYER_FREEIF(item);
7778 g_list_free(player->signals[type]);
7779 player->signals[type] = NULL;
7787 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7789 mmplayer_t *player = 0;
7790 int prev_display_surface_type = 0;
7794 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7796 player = MM_PLAYER_CAST(handle);
7798 /* check video sinkbin is created */
7799 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7800 LOGW("Videosink is already created");
7801 return MM_ERROR_NONE;
7804 LOGD("videosink element is not yet ready");
7806 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7807 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7809 return MM_ERROR_INVALID_ARGUMENT;
7812 /* load previous attributes */
7813 if (player->attrs) {
7814 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7815 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7816 if (prev_display_surface_type == surface_type) {
7817 LOGD("incoming display surface type is same as previous one, do nothing..");
7819 return MM_ERROR_NONE;
7822 LOGE("failed to load attributes");
7824 return MM_ERROR_PLAYER_INTERNAL;
7827 /* videobin is not created yet, so we just set attributes related to display surface */
7828 LOGD("store display attribute for given surface type(%d)", surface_type);
7829 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7830 "display_overlay", wl_surface_id, NULL);
7833 return MM_ERROR_NONE;
7836 /* Note : if silent is true, then subtitle would not be displayed. :*/
7838 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7840 mmplayer_t *player = (mmplayer_t *)hplayer;
7844 /* check player handle */
7845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7847 player->set_mode.subtitle_off = silent;
7849 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7853 return MM_ERROR_NONE;
7857 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7859 mmplayer_gst_element_t *mainbin = NULL;
7860 mmplayer_gst_element_t *textbin = NULL;
7861 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7862 GstState current_state = GST_STATE_VOID_PENDING;
7863 GstState element_state = GST_STATE_VOID_PENDING;
7864 GstState element_pending_state = GST_STATE_VOID_PENDING;
7866 GstEvent *event = NULL;
7867 int result = MM_ERROR_NONE;
7869 GstClock *curr_clock = NULL;
7870 GstClockTime base_time, start_time, curr_time;
7875 /* check player handle */
7876 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7878 player->pipeline->mainbin &&
7879 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7881 mainbin = player->pipeline->mainbin;
7882 textbin = player->pipeline->textbin;
7884 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7886 // sync clock with current pipeline
7887 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7888 curr_time = gst_clock_get_time(curr_clock);
7890 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7891 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7893 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7894 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7896 if (current_state > GST_STATE_READY) {
7897 // sync state with current pipeline
7898 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7899 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7900 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7902 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7903 if (GST_STATE_CHANGE_FAILURE == ret) {
7904 LOGE("fail to state change.");
7905 result = MM_ERROR_PLAYER_INTERNAL;
7909 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7910 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7913 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7914 gst_object_unref(curr_clock);
7917 // seek to current position
7918 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7919 result = MM_ERROR_PLAYER_INVALID_STATE;
7920 LOGE("gst_element_query_position failed, invalid state");
7924 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7925 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);
7927 _mmplayer_gst_send_event_to_sink(player, event);
7929 result = MM_ERROR_PLAYER_INTERNAL;
7930 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7934 /* sync state with current pipeline */
7935 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7936 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7937 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7939 return MM_ERROR_NONE;
7942 /* release text pipeline resource */
7943 player->textsink_linked = 0;
7945 /* release signal */
7946 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7948 /* release textbin with it's childs */
7949 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7950 MMPLAYER_FREEIF(player->pipeline->textbin);
7951 player->pipeline->textbin = NULL;
7953 /* release subtitle elem */
7954 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7955 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7961 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7963 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7964 GstState current_state = GST_STATE_VOID_PENDING;
7966 MMHandleType attrs = 0;
7967 mmplayer_gst_element_t *mainbin = NULL;
7968 mmplayer_gst_element_t *textbin = NULL;
7970 gchar *subtitle_uri = NULL;
7971 int result = MM_ERROR_NONE;
7972 const gchar *charset = NULL;
7976 /* check player handle */
7977 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7979 player->pipeline->mainbin &&
7980 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7981 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7983 mainbin = player->pipeline->mainbin;
7984 textbin = player->pipeline->textbin;
7986 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7987 if (current_state < GST_STATE_READY) {
7988 result = MM_ERROR_PLAYER_INVALID_STATE;
7989 LOGE("Pipeline is not in proper state");
7993 attrs = MMPLAYER_GET_ATTRS(player);
7995 LOGE("cannot get content attribute");
7996 result = MM_ERROR_PLAYER_INTERNAL;
8000 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8001 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8002 LOGE("subtitle uri is not proper filepath");
8003 result = MM_ERROR_PLAYER_INVALID_URI;
8007 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8008 LOGE("failed to get storage info of subtitle path");
8009 result = MM_ERROR_PLAYER_INVALID_URI;
8013 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8014 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8016 if (!strcmp(filepath, subtitle_uri)) {
8017 LOGD("subtitle path is not changed");
8020 if (mm_player_set_attribute((MMHandleType)player, NULL,
8021 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8022 LOGE("failed to set attribute");
8027 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8028 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8029 player->subtitle_language_list = NULL;
8030 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8032 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8033 if (ret != GST_STATE_CHANGE_SUCCESS) {
8034 LOGE("failed to change state of textbin to READY");
8035 result = MM_ERROR_PLAYER_INTERNAL;
8039 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8040 if (ret != GST_STATE_CHANGE_SUCCESS) {
8041 LOGE("failed to change state of subparse to READY");
8042 result = MM_ERROR_PLAYER_INTERNAL;
8046 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8047 if (ret != GST_STATE_CHANGE_SUCCESS) {
8048 LOGE("failed to change state of filesrc to READY");
8049 result = MM_ERROR_PLAYER_INTERNAL;
8053 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8055 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8057 charset = _mmplayer_get_charset(filepath);
8059 LOGD("detected charset is %s", charset);
8060 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8063 result = _mmplayer_sync_subtitle_pipeline(player);
8070 /* API to switch between external subtitles */
8072 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8074 int result = MM_ERROR_NONE;
8075 mmplayer_t *player = (mmplayer_t *)hplayer;
8080 /* check player handle */
8081 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8083 /* filepath can be null in idle state */
8085 /* check file path */
8086 if ((path = strstr(filepath, "file://")))
8087 result = _mmplayer_exist_file_path(path + 7);
8089 result = _mmplayer_exist_file_path(filepath);
8091 if (result != MM_ERROR_NONE) {
8092 LOGE("invalid subtitle path 0x%X", result);
8093 return result; /* file not found or permission denied */
8097 if (!player->pipeline) {
8099 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8100 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8101 LOGE("failed to set attribute");
8102 return MM_ERROR_PLAYER_INTERNAL;
8105 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8106 /* check filepath */
8107 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8109 if (!__mmplayer_check_subtitle(player)) {
8110 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8111 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8112 LOGE("failed to set attribute");
8113 return MM_ERROR_PLAYER_INTERNAL;
8116 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8117 LOGE("fail to create text pipeline");
8118 return MM_ERROR_PLAYER_INTERNAL;
8121 result = _mmplayer_sync_subtitle_pipeline(player);
8123 result = __mmplayer_change_external_subtitle_language(player, filepath);
8126 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8127 player->is_external_subtitle_added_now = TRUE;
8129 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8130 if (!player->subtitle_language_list) {
8131 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8132 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8133 LOGW("subtitle language list is not updated yet");
8135 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8143 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8145 int result = MM_ERROR_NONE;
8146 gchar *change_pad_name = NULL;
8147 GstPad *sinkpad = NULL;
8148 mmplayer_gst_element_t *mainbin = NULL;
8149 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8150 GstCaps *caps = NULL;
8151 gint total_track_num = 0;
8155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8156 MM_ERROR_PLAYER_NOT_INITIALIZED);
8158 LOGD("Change Track(%d) to %d", type, index);
8160 mainbin = player->pipeline->mainbin;
8162 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8163 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8164 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8165 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8167 /* Changing Video Track is not supported. */
8168 LOGE("Track Type Error");
8172 if (mainbin[elem_idx].gst == NULL) {
8173 result = MM_ERROR_PLAYER_NO_OP;
8174 LOGD("Req track doesn't exist");
8178 total_track_num = player->selector[type].total_track_num;
8179 if (total_track_num <= 0) {
8180 result = MM_ERROR_PLAYER_NO_OP;
8181 LOGD("Language list is not available");
8185 if ((index < 0) || (index >= total_track_num)) {
8186 result = MM_ERROR_INVALID_ARGUMENT;
8187 LOGD("Not a proper index : %d", index);
8191 /*To get the new pad from the selector*/
8192 change_pad_name = g_strdup_printf("sink_%u", index);
8193 if (change_pad_name == NULL) {
8194 result = MM_ERROR_PLAYER_INTERNAL;
8195 LOGD("Pad does not exists");
8199 LOGD("new active pad name: %s", change_pad_name);
8201 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8202 if (sinkpad == NULL) {
8203 LOGD("sinkpad is NULL");
8204 result = MM_ERROR_PLAYER_INTERNAL;
8208 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8209 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8211 caps = gst_pad_get_current_caps(sinkpad);
8212 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8215 gst_object_unref(sinkpad);
8217 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8218 __mmplayer_set_audio_attrs(player, caps);
8221 MMPLAYER_FREEIF(change_pad_name);
8226 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8228 int result = MM_ERROR_NONE;
8229 mmplayer_t *player = NULL;
8230 mmplayer_gst_element_t *mainbin = NULL;
8232 gint current_active_index = 0;
8234 GstState current_state = GST_STATE_VOID_PENDING;
8235 GstEvent *event = NULL;
8240 player = (mmplayer_t *)hplayer;
8241 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8243 if (!player->pipeline) {
8244 LOGE("Track %d pre setting -> %d", type, index);
8246 player->selector[type].active_pad_index = index;
8250 mainbin = player->pipeline->mainbin;
8252 current_active_index = player->selector[type].active_pad_index;
8254 /*If index is same as running index no need to change the pad*/
8255 if (current_active_index == index)
8258 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8259 result = MM_ERROR_PLAYER_INVALID_STATE;
8263 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8264 if (current_state < GST_STATE_PAUSED) {
8265 result = MM_ERROR_PLAYER_INVALID_STATE;
8266 LOGW("Pipeline not in porper state");
8270 result = __mmplayer_change_selector_pad(player, type, index);
8271 if (result != MM_ERROR_NONE) {
8272 LOGE("change selector pad error");
8276 player->selector[type].active_pad_index = index;
8278 if (current_state == GST_STATE_PLAYING) {
8279 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8280 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8281 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8283 _mmplayer_gst_send_event_to_sink(player, event);
8285 result = MM_ERROR_PLAYER_INTERNAL;
8295 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8297 mmplayer_t *player = (mmplayer_t *)hplayer;
8301 /* check player handle */
8302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8304 *silent = player->set_mode.subtitle_off;
8306 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8310 return MM_ERROR_NONE;
8314 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8316 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8317 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8319 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8320 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8324 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8325 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8326 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8327 mmplayer_dump_t *dump_s;
8328 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8329 if (dump_s == NULL) {
8330 LOGE("malloc fail");
8334 dump_s->dump_element_file = NULL;
8335 dump_s->dump_pad = NULL;
8336 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8338 if (dump_s->dump_pad) {
8339 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8340 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]);
8341 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8342 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);
8343 /* add list for removed buffer probe and close FILE */
8344 player->dump_list = g_list_append(player->dump_list, dump_s);
8345 LOGD("%s sink pad added buffer probe for dump", factory_name);
8348 MMPLAYER_FREEIF(dump_s);
8349 LOGE("failed to get %s sink pad added", factory_name);
8356 static GstPadProbeReturn
8357 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8359 FILE *dump_data = (FILE *)u_data;
8361 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8362 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8364 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8366 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8368 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8370 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8372 gst_buffer_unmap(buffer, &probe_info);
8374 return GST_PAD_PROBE_OK;
8378 __mmplayer_release_dump_list(GList *dump_list)
8380 GList *d_list = dump_list;
8385 for (; d_list; d_list = g_list_next(d_list)) {
8386 mmplayer_dump_t *dump_s = d_list->data;
8387 if (dump_s->dump_pad) {
8388 if (dump_s->probe_handle_id)
8389 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8390 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8392 if (dump_s->dump_element_file) {
8393 fclose(dump_s->dump_element_file);
8394 dump_s->dump_element_file = NULL;
8396 MMPLAYER_FREEIF(dump_s);
8398 g_list_free(dump_list);
8403 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8405 mmplayer_t *player = (mmplayer_t *)hplayer;
8409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8410 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8412 *exist = (bool)player->has_closed_caption;
8416 return MM_ERROR_NONE;
8420 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8425 LOGD("unref internal gst buffer %p", buffer);
8427 gst_buffer_unref((GstBuffer *)buffer);
8434 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8436 mmplayer_t *player = (mmplayer_t *)hplayer;
8440 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8441 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8443 if (MMPLAYER_IS_STREAMING(player))
8444 *timeout = (int)player->ini.live_state_change_timeout;
8446 *timeout = (int)player->ini.localplayback_state_change_timeout;
8448 LOGD("timeout = %d", *timeout);
8451 return MM_ERROR_NONE;
8455 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8459 MMPLAYER_RETURN_IF_FAIL(player);
8461 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8463 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8464 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8465 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8466 player->storage_info[i].id = -1;
8467 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8469 if (path_type != MMPLAYER_PATH_MAX)
8478 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8480 int ret = MM_ERROR_NONE;
8481 mmplayer_t *player = (mmplayer_t *)hplayer;
8482 MMMessageParamType msg_param = {0, };
8485 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8487 LOGW("state changed storage %d:%d", id, state);
8489 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8490 return MM_ERROR_NONE;
8492 /* FIXME: text path should be handled seperately. */
8493 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8494 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8495 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8496 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8497 LOGW("external storage is removed");
8499 if (player->msg_posted == FALSE) {
8500 memset(&msg_param, 0, sizeof(MMMessageParamType));
8501 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8502 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8503 player->msg_posted = TRUE;
8506 /* unrealize the player */
8507 ret = _mmplayer_unrealize(hplayer);
8508 if (ret != MM_ERROR_NONE)
8509 LOGE("failed to unrealize");
8517 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8519 int ret = MM_ERROR_NONE;
8520 mmplayer_t *player = (mmplayer_t *)hplayer;
8521 int idx = 0, total = 0;
8522 gchar *result = NULL, *tmp = NULL;
8525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8526 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8528 total = *num = g_list_length(player->adaptive_info.var_list);
8530 LOGW("There is no stream variant info.");
8534 result = g_strdup("");
8535 for (idx = 0 ; idx < total ; idx++) {
8536 stream_variant_t *v_data = NULL;
8537 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8540 gchar data[64] = {0};
8541 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8543 tmp = g_strconcat(result, data, NULL);
8547 LOGW("There is no variant data in %d", idx);
8552 *var_info = (char *)result;
8554 LOGD("variant info %d:%s", *num, *var_info);
8560 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8562 int ret = MM_ERROR_NONE;
8563 mmplayer_t *player = (mmplayer_t *)hplayer;
8566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8568 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8570 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8571 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8572 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8574 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8575 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8576 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8577 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8579 /* FIXME: seek to current position for applying new variant limitation */
8588 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8590 int ret = MM_ERROR_NONE;
8591 mmplayer_t *player = (mmplayer_t *)hplayer;
8594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8597 *bandwidth = player->adaptive_info.limit.bandwidth;
8598 *width = player->adaptive_info.limit.width;
8599 *height = player->adaptive_info.limit.height;
8601 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8608 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8610 int ret = MM_ERROR_NONE;
8611 mmplayer_t *player = (mmplayer_t *)hplayer;
8614 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8615 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8616 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8618 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8620 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8621 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8622 else /* live case */
8623 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8625 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8632 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8634 #define IDX_FIRST_SW_CODEC 0
8635 mmplayer_t *player = (mmplayer_t *)hplayer;
8636 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8641 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8642 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8643 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8645 switch (stream_type) {
8646 case MM_PLAYER_STREAM_TYPE_AUDIO:
8647 /* to support audio codec selection, codec info have to be added in ini file as below.
8648 audio codec element hw = xxxx
8649 audio codec element sw = avdec
8650 and in case of audio hw codec is supported and selected,
8651 audio filter elements should be applied depending on the hw capabilities.
8653 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8654 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8655 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8656 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8657 LOGE("There is no audio codec info for codec_type %d", codec_type);
8658 return MM_ERROR_PLAYER_NO_OP;
8661 case MM_PLAYER_STREAM_TYPE_VIDEO:
8662 /* to support video codec selection, codec info have to be added in ini file as below.
8663 video codec element hw = omx
8664 video codec element sw = avdec */
8665 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8666 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8667 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8668 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8669 LOGE("There is no video codec info for codec_type %d", codec_type);
8670 return MM_ERROR_PLAYER_NO_OP;
8674 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8675 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8679 LOGD("update %s codec_type to %d", attr_name, codec_type);
8680 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8683 return MM_ERROR_NONE;
8687 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8689 mmplayer_t *player = (mmplayer_t *)hplayer;
8690 GstElement *rg_vol_element = NULL;
8694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8696 player->sound.rg_enable = enabled;
8698 /* just hold rgvolume enable value if pipeline is not ready */
8699 if (!player->pipeline || !player->pipeline->audiobin) {
8700 LOGD("pipeline is not ready. holding rgvolume enable value");
8701 return MM_ERROR_NONE;
8704 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8706 if (!rg_vol_element) {
8707 LOGD("rgvolume element is not created");
8708 return MM_ERROR_PLAYER_INTERNAL;
8712 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8714 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8718 return MM_ERROR_NONE;
8722 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8724 mmplayer_t *player = (mmplayer_t *)hplayer;
8725 GstElement *rg_vol_element = NULL;
8726 gboolean enable = FALSE;
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8733 /* just hold enable_rg value if pipeline is not ready */
8734 if (!player->pipeline || !player->pipeline->audiobin) {
8735 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8736 *enabled = player->sound.rg_enable;
8737 return MM_ERROR_NONE;
8740 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8742 if (!rg_vol_element) {
8743 LOGD("rgvolume element is not created");
8744 return MM_ERROR_PLAYER_INTERNAL;
8747 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8748 *enabled = (bool)enable;
8752 return MM_ERROR_NONE;
8756 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8758 mmplayer_t *player = (mmplayer_t *)hplayer;
8759 MMHandleType attrs = 0;
8761 int ret = MM_ERROR_NONE;
8765 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8767 attrs = MMPLAYER_GET_ATTRS(player);
8768 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8770 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8772 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8773 return MM_ERROR_PLAYER_INTERNAL;
8776 player->video_roi.scale_x = scale_x;
8777 player->video_roi.scale_y = scale_y;
8778 player->video_roi.scale_width = scale_width;
8779 player->video_roi.scale_height = scale_height;
8781 /* check video sinkbin is created */
8782 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8783 return MM_ERROR_NONE;
8785 if (!gst_video_overlay_set_video_roi_area(
8786 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8787 scale_x, scale_y, scale_width, scale_height))
8788 ret = MM_ERROR_PLAYER_INTERNAL;
8790 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8791 scale_x, scale_y, scale_width, scale_height);
8799 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8801 mmplayer_t *player = (mmplayer_t *)hplayer;
8802 int ret = MM_ERROR_NONE;
8806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8807 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8809 *scale_x = player->video_roi.scale_x;
8810 *scale_y = player->video_roi.scale_y;
8811 *scale_width = player->video_roi.scale_width;
8812 *scale_height = player->video_roi.scale_height;
8814 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8815 *scale_x, *scale_y, *scale_width, *scale_height);
8821 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8823 mmplayer_t *player = (mmplayer_t *)hplayer;
8827 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8829 player->client_pid = pid;
8831 LOGD("client pid[%d] %p", pid, player);
8835 return MM_ERROR_NONE;
8839 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8841 mmplayer_t *player = (mmplayer_t *)hplayer;
8842 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8843 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8847 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8848 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8851 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8853 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8855 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8856 return MM_ERROR_NONE;
8858 /* in case of audio codec default type is HW */
8860 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8861 if (player->ini.support_audio_effect)
8862 return MM_ERROR_NONE;
8863 elem_id = MMPLAYER_A_FILTER;
8865 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8866 if (player->ini.support_replaygain_control)
8867 return MM_ERROR_NONE;
8868 elem_id = MMPLAYER_A_RGVOL;
8870 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8871 if (player->ini.support_pitch_control)
8872 return MM_ERROR_NONE;
8873 elem_id = MMPLAYER_A_PITCH;
8875 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8876 if (player->ini.support_audio_effect)
8877 return MM_ERROR_NONE;
8879 /* default case handling is not required */
8882 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8883 LOGW("audio control option [%d] is not available", opt);
8886 /* setting pcm exporting option is allowed before READY state */
8887 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8888 return MM_ERROR_PLAYER_INVALID_STATE;
8890 /* check whether the audio filter exist or not after READY state,
8891 because the sw codec could be added during auto-plugging in some cases */
8892 if (!player->pipeline ||
8893 !player->pipeline->audiobin ||
8894 !player->pipeline->audiobin[elem_id].gst) {
8895 LOGW("there is no audio elem [%d]", elem_id);
8900 LOGD("audio control opt %d, available %d", opt, *available);
8904 return MM_ERROR_NONE;
8908 __mmplayer_update_duration_value(mmplayer_t *player)
8910 gboolean ret = FALSE;
8911 gint64 dur_nsec = 0;
8912 LOGD("try to update duration");
8914 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8915 player->duration = dur_nsec;
8916 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8920 if (player->duration < 0) {
8921 LOGW("duration is Non-Initialized !!!");
8922 player->duration = 0;
8925 /* update streaming service type */
8926 player->streaming_type = _mmplayer_get_stream_service_type(player);
8928 /* check duration is OK */
8929 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8930 /* FIXIT : find another way to get duration here. */
8931 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8937 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8939 /* update audio params
8940 NOTE : We need original audio params and it can be only obtained from src pad of audio
8941 decoder. Below code only valid when we are not using 'resampler' just before
8942 'audioconverter'. */
8943 GstCaps *caps_a = NULL;
8945 gint samplerate = 0, channels = 0;
8946 GstStructure *p = NULL;
8947 GstElement *aconv = NULL;
8949 LOGD("try to update audio attrs");
8951 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8953 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8954 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8955 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8956 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8958 LOGE("there is no audio converter");
8962 pad = gst_element_get_static_pad(aconv, "sink");
8965 LOGW("failed to get pad from audio converter");
8969 caps_a = gst_pad_get_current_caps(pad);
8971 LOGW("not ready to get audio caps");
8972 gst_object_unref(pad);
8976 p = gst_caps_get_structure(caps_a, 0);
8978 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8980 gst_structure_get_int(p, "rate", &samplerate);
8981 gst_structure_get_int(p, "channels", &channels);
8983 mm_player_set_attribute((MMHandleType)player, NULL,
8984 "content_audio_samplerate", samplerate,
8985 "content_audio_channels", channels, NULL);
8987 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8989 gst_caps_unref(caps_a);
8990 gst_object_unref(pad);
8996 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8998 LOGD("try to update video attrs");
9000 GstCaps *caps_v = NULL;
9004 GstStructure *p = NULL;
9006 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9007 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9009 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9011 LOGD("no videosink sink pad");
9015 caps_v = gst_pad_get_current_caps(pad);
9016 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9017 if (!caps_v && player->v_stream_caps) {
9018 caps_v = player->v_stream_caps;
9019 gst_caps_ref(caps_v);
9023 LOGD("no negitiated caps from videosink");
9024 gst_object_unref(pad);
9028 p = gst_caps_get_structure(caps_v, 0);
9029 gst_structure_get_int(p, "width", &width);
9030 gst_structure_get_int(p, "height", &height);
9032 mm_player_set_attribute((MMHandleType)player, NULL,
9033 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9035 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9037 SECURE_LOGD("width : %d height : %d", width, height);
9039 gst_caps_unref(caps_v);
9040 gst_object_unref(pad);
9043 mm_player_set_attribute((MMHandleType)player, NULL,
9044 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9045 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9052 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9054 gboolean ret = FALSE;
9055 guint64 data_size = 0;
9059 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9060 if (!player->duration)
9063 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9064 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9065 if (stat(path, &sb) == 0)
9066 data_size = (guint64)sb.st_size;
9068 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9069 data_size = player->http_content_size;
9072 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9075 guint64 bitrate = 0;
9076 guint64 msec_dur = 0;
9078 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9080 bitrate = data_size * 8 * 1000 / msec_dur;
9081 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9082 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9083 mm_player_set_attribute((MMHandleType)player, NULL,
9084 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9087 LOGD("player duration is less than 0");
9091 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9092 if (player->total_bitrate) {
9093 mm_player_set_attribute((MMHandleType)player, NULL,
9094 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9103 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9105 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9106 data->uri_type = uri_type;
9110 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9112 int ret = MM_ERROR_PLAYER_INVALID_URI;
9114 char *buffer = NULL;
9115 char *seperator = strchr(path, ',');
9116 char ext[100] = {0,}, size[100] = {0,};
9119 if ((buffer = strstr(path, "ext="))) {
9120 buffer += strlen("ext=");
9122 if (strlen(buffer)) {
9123 strncpy(ext, buffer, 99);
9125 if ((seperator = strchr(ext, ','))
9126 || (seperator = strchr(ext, ' '))
9127 || (seperator = strchr(ext, '\0'))) {
9128 seperator[0] = '\0';
9133 if ((buffer = strstr(path, "size="))) {
9134 buffer += strlen("size=");
9136 if (strlen(buffer) > 0) {
9137 strncpy(size, buffer, 99);
9139 if ((seperator = strchr(size, ','))
9140 || (seperator = strchr(size, ' '))
9141 || (seperator = strchr(size, '\0'))) {
9142 seperator[0] = '\0';
9145 mem_size = atoi(size);
9150 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9152 if (mem_size && param) {
9153 if (data->input_mem.buf)
9154 free(data->input_mem.buf);
9155 data->input_mem.buf = malloc(mem_size);
9157 if (data->input_mem.buf) {
9158 memcpy(data->input_mem.buf, param, mem_size);
9159 data->input_mem.len = mem_size;
9160 ret = MM_ERROR_NONE;
9162 LOGE("failed to alloc mem %d", mem_size);
9163 ret = MM_ERROR_PLAYER_INTERNAL;
9166 data->input_mem.offset = 0;
9167 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9174 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9176 gchar *location = NULL;
9179 int ret = MM_ERROR_NONE;
9181 if ((path = strstr(uri, "file://"))) {
9182 location = g_filename_from_uri(uri, NULL, &err);
9183 if (!location || (err != NULL)) {
9184 LOGE("Invalid URI '%s' for filesrc: %s", path,
9185 (err != NULL) ? err->message : "unknown error");
9189 MMPLAYER_FREEIF(location);
9191 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9192 return MM_ERROR_PLAYER_INVALID_URI;
9194 LOGD("path from uri: %s", location);
9197 path = (location != NULL) ? (location) : ((char *)uri);
9200 ret = _mmplayer_exist_file_path(path);
9202 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9203 if (ret == MM_ERROR_NONE) {
9204 if (_mmplayer_is_sdp_file(path)) {
9205 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9206 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9207 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9209 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9210 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9212 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9213 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9215 LOGE("invalid uri, could not play..");
9216 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9219 MMPLAYER_FREEIF(location);
9224 static mmplayer_video_decoded_data_info_t *
9225 __mmplayer_create_stream_from_pad(GstPad *pad)
9227 GstCaps *caps = NULL;
9228 GstStructure *structure = NULL;
9229 unsigned int fourcc = 0;
9230 const gchar *string_format = NULL;
9231 mmplayer_video_decoded_data_info_t *stream = NULL;
9233 MMPixelFormatType format;
9236 caps = gst_pad_get_current_caps(pad);
9238 LOGE("Caps is NULL.");
9243 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9245 structure = gst_caps_get_structure(caps, 0);
9246 gst_structure_get_int(structure, "width", &width);
9247 gst_structure_get_int(structure, "height", &height);
9248 string_format = gst_structure_get_string(structure, "format");
9251 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9252 format = _mmplayer_get_pixtype(fourcc);
9253 gst_video_info_from_caps(&info, caps);
9254 gst_caps_unref(caps);
9257 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9258 LOGE("Wrong condition!!");
9262 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9264 LOGE("failed to alloc mem for video data");
9268 stream->width = width;
9269 stream->height = height;
9270 stream->format = format;
9271 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9277 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9279 unsigned int pitch = 0;
9280 unsigned int size = 0;
9282 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9285 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9286 bo = gst_tizen_memory_get_bos(mem, index);
9288 stream->bo[index] = tbm_bo_ref(bo);
9290 LOGE("failed to get bo for index %d", index);
9293 for (index = 0; index < stream->plane_num; index++) {
9294 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9295 stream->stride[index] = pitch;
9297 stream->elevation[index] = size / pitch;
9299 stream->elevation[index] = stream->height;
9304 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9306 if (stream->format == MM_PIXEL_FORMAT_I420) {
9307 int ret = TBM_SURFACE_ERROR_NONE;
9308 tbm_surface_h surface;
9309 tbm_surface_info_s info;
9311 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9313 ret = tbm_surface_get_info(surface, &info);
9314 if (ret != TBM_SURFACE_ERROR_NONE) {
9315 tbm_surface_destroy(surface);
9319 tbm_surface_destroy(surface);
9320 stream->stride[0] = info.planes[0].stride;
9321 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9322 stream->stride[1] = info.planes[1].stride;
9323 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9324 stream->stride[2] = info.planes[2].stride;
9325 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9326 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9327 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9328 stream->stride[0] = stream->width * 4;
9329 stream->elevation[0] = stream->height;
9330 stream->bo_size = stream->stride[0] * stream->height;
9332 LOGE("Not support format %d", stream->format);
9340 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9342 tbm_bo_handle thandle;
9344 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9345 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9346 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9350 unsigned char *src = NULL;
9351 unsigned char *dest = NULL;
9352 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9354 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9356 LOGE("fail to gst_memory_map");
9360 if (!mapinfo.data) {
9361 LOGE("data pointer is wrong");
9365 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9366 if (!stream->bo[0]) {
9367 LOGE("Fail to tbm_bo_alloc!!");
9371 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9373 LOGE("thandle pointer is wrong");
9377 if (stream->format == MM_PIXEL_FORMAT_I420) {
9378 src_stride[0] = GST_ROUND_UP_4(stream->width);
9379 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9380 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9381 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9384 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9385 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9387 for (i = 0; i < 3; i++) {
9388 src = mapinfo.data + src_offset[i];
9389 dest = thandle.ptr + dest_offset[i];
9394 for (j = 0; j < stream->height >> k; j++) {
9395 memcpy(dest, src, stream->width>>k);
9396 src += src_stride[i];
9397 dest += stream->stride[i];
9400 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9401 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9403 LOGE("Not support format %d", stream->format);
9407 tbm_bo_unmap(stream->bo[0]);
9408 gst_memory_unmap(mem, &mapinfo);
9414 tbm_bo_unmap(stream->bo[0]);
9417 gst_memory_unmap(mem, &mapinfo);
9423 __mmplayer_set_pause_state(mmplayer_t *player)
9425 if (player->sent_bos)
9428 /* rtsp case, get content attrs by GstMessage */
9429 if (MMPLAYER_IS_RTSP_STREAMING(player))
9432 /* it's first time to update all content attrs. */
9433 _mmplayer_update_content_attrs(player, ATTR_ALL);
9437 __mmplayer_set_playing_state(mmplayer_t *player)
9439 gchar *audio_codec = NULL;
9441 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9442 /* initialize because auto resume is done well. */
9443 player->resumed_by_rewind = FALSE;
9444 player->playback_rate = 1.0;
9447 if (player->sent_bos)
9450 /* try to get content metadata */
9452 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9453 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9454 * legacy mmfw-player api
9456 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9458 if ((player->cmd == MMPLAYER_COMMAND_START)
9459 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9460 __mmplayer_handle_missed_plugin(player);
9463 /* check audio codec field is set or not
9464 * we can get it from typefinder or codec's caps.
9466 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9468 /* The codec format can't be sent for audio only case like amr, mid etc.
9469 * Because, parser don't make related TAG.
9470 * So, if it's not set yet, fill it with found data.
9473 if (g_strrstr(player->type, "audio/midi"))
9474 audio_codec = "MIDI";
9475 else if (g_strrstr(player->type, "audio/x-amr"))
9476 audio_codec = "AMR";
9477 else if (g_strrstr(player->type, "audio/mpeg")
9478 && !g_strrstr(player->type, "mpegversion=(int)1"))
9479 audio_codec = "AAC";
9481 audio_codec = "unknown";
9483 if (mm_player_set_attribute((MMHandleType)player, NULL,
9484 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9485 LOGE("failed to set attribute");
9487 LOGD("set audio codec type with caps");