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