4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
144 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
145 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
146 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
147 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
151 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
152 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
153 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
155 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_release_misc(mmplayer_t *player);
157 static void __mmplayer_release_misc_post(mmplayer_t *player);
158 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
159 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
160 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
162 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
164 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
165 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
166 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
167 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
168 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
170 static gpointer __mmplayer_gapless_play_thread(gpointer data);
171 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
172 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
173 static void __mmplayer_release_dump_list(GList *dump_list);
174 static int __mmplayer_gst_realize(mmplayer_t *player);
175 static int __mmplayer_gst_unrealize(mmplayer_t *player);
176 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
177 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
180 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
181 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
182 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
183 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
184 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
185 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
186 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
187 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
188 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
189 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
190 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
194 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
195 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
196 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
198 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
199 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
200 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
201 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
203 static void __mmplayer_set_pause_state(mmplayer_t *player);
204 static void __mmplayer_set_playing_state(mmplayer_t *player);
205 /*===========================================================================================
207 | FUNCTION DEFINITIONS |
209 ========================================================================================== */
211 /* This function should be called after the pipeline goes PAUSED or higher
214 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
216 static gboolean has_duration = FALSE;
217 static gboolean has_video_attrs = FALSE;
218 static gboolean has_audio_attrs = FALSE;
219 static gboolean has_bitrate = FALSE;
220 gboolean missing_only = FALSE;
221 gboolean all = FALSE;
222 MMHandleType attrs = 0;
226 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
228 /* check player state here */
229 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
230 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
231 /* give warning now only */
232 LOGW("be careful. content attributes may not available in this state ");
235 /* get content attribute first */
236 attrs = MMPLAYER_GET_ATTRS(player);
238 LOGE("cannot get content attribute");
242 /* get update flag */
244 if (flag & ATTR_MISSING_ONLY) {
246 LOGD("updating missed attr only");
249 if (flag & ATTR_ALL) {
251 has_duration = FALSE;
252 has_video_attrs = FALSE;
253 has_audio_attrs = FALSE;
256 LOGD("updating all attrs");
259 if (missing_only && all) {
260 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
261 missing_only = FALSE;
264 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
265 has_duration = __mmplayer_update_duration_value(player);
267 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
268 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
270 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
271 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
273 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
274 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
282 _mmplayer_get_stream_service_type(mmplayer_t *player)
284 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
288 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
290 player->pipeline->mainbin &&
291 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
292 STREAMING_SERVICE_NONE);
294 /* streaming service type if streaming */
295 if (!MMPLAYER_IS_STREAMING(player))
296 return STREAMING_SERVICE_NONE;
298 streaming_type = (player->duration == 0) ?
299 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
301 switch (streaming_type) {
302 case STREAMING_SERVICE_LIVE:
303 LOGD("it's live streaming");
305 case STREAMING_SERVICE_VOD:
306 LOGD("it's vod streaming");
309 LOGE("should not get here");
315 return streaming_type;
318 /* this function sets the player state and also report
319 * it to applicaton by calling callback function
322 _mmplayer_set_state(mmplayer_t *player, int state)
324 MMMessageParamType msg = {0, };
326 MMPLAYER_RETURN_IF_FAIL(player);
328 if (MMPLAYER_CURRENT_STATE(player) == state) {
329 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
330 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
334 /* update player states */
335 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
336 MMPLAYER_CURRENT_STATE(player) = state;
338 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
339 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
342 MMPLAYER_PRINT_STATE(player);
344 switch (MMPLAYER_CURRENT_STATE(player)) {
345 case MM_PLAYER_STATE_NULL:
346 case MM_PLAYER_STATE_READY:
348 case MM_PLAYER_STATE_PAUSED:
349 __mmplayer_set_pause_state(player);
351 case MM_PLAYER_STATE_PLAYING:
352 __mmplayer_set_playing_state(player);
354 case MM_PLAYER_STATE_NONE:
356 LOGW("invalid target state, there is nothing to do.");
361 /* post message to application */
362 if (MMPLAYER_TARGET_STATE(player) == state) {
363 /* fill the message with state of player */
364 msg.union_type = MM_MSG_UNION_STATE;
365 msg.state.previous = MMPLAYER_PREV_STATE(player);
366 msg.state.current = MMPLAYER_CURRENT_STATE(player);
368 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
370 /* state changed by resource callback */
371 if (player->interrupted_by_resource)
372 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
373 else /* state changed by usecase */
374 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
377 LOGD("intermediate state, do nothing.");
378 MMPLAYER_PRINT_STATE(player);
382 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
383 && !player->sent_bos) {
384 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
385 player->sent_bos = TRUE;
392 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
394 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
395 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
399 LOGD("incomming command : %d ", command);
401 current_state = MMPLAYER_CURRENT_STATE(player);
402 pending_state = MMPLAYER_PENDING_STATE(player);
404 MMPLAYER_PRINT_STATE(player);
407 case MMPLAYER_COMMAND_CREATE:
409 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
411 if (current_state == MM_PLAYER_STATE_NULL ||
412 current_state == MM_PLAYER_STATE_READY ||
413 current_state == MM_PLAYER_STATE_PAUSED ||
414 current_state == MM_PLAYER_STATE_PLAYING)
419 case MMPLAYER_COMMAND_DESTROY:
421 /* destroy can called anytime */
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
427 case MMPLAYER_COMMAND_REALIZE:
429 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
431 if (pending_state != MM_PLAYER_STATE_NONE) {
434 /* need ready state to realize */
435 if (current_state == MM_PLAYER_STATE_READY)
438 if (current_state != MM_PLAYER_STATE_NULL)
444 case MMPLAYER_COMMAND_UNREALIZE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL)
453 case MMPLAYER_COMMAND_START:
455 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
457 if (pending_state == MM_PLAYER_STATE_NONE) {
458 if (current_state == MM_PLAYER_STATE_PLAYING)
460 else if (current_state != MM_PLAYER_STATE_READY &&
461 current_state != MM_PLAYER_STATE_PAUSED)
463 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
465 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
466 LOGD("player is going to paused state, just change the pending state as playing");
473 case MMPLAYER_COMMAND_STOP:
475 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
477 if (current_state == MM_PLAYER_STATE_READY)
480 /* need playing/paused state to stop */
481 if (current_state != MM_PLAYER_STATE_PLAYING &&
482 current_state != MM_PLAYER_STATE_PAUSED)
487 case MMPLAYER_COMMAND_PAUSE:
489 if (MMPLAYER_IS_LIVE_STREAMING(player))
492 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
493 goto NOT_COMPLETED_SEEK;
495 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
497 if (pending_state == MM_PLAYER_STATE_NONE) {
498 if (current_state == MM_PLAYER_STATE_PAUSED)
500 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
504 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
505 if (current_state == MM_PLAYER_STATE_PAUSED)
506 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
513 case MMPLAYER_COMMAND_RESUME:
515 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
516 goto NOT_COMPLETED_SEEK;
518 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
520 if (pending_state == MM_PLAYER_STATE_NONE) {
521 if (current_state == MM_PLAYER_STATE_PLAYING)
523 else if (current_state != MM_PLAYER_STATE_PAUSED)
525 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
527 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
528 LOGD("player is going to paused state, just change the pending state as playing");
538 player->cmd = command;
540 return MM_ERROR_NONE;
543 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
544 MMPLAYER_STATE_GET_NAME(current_state), command);
545 return MM_ERROR_PLAYER_INVALID_STATE;
548 LOGW("not completed seek");
549 return MM_ERROR_PLAYER_DOING_SEEK;
552 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
553 return MM_ERROR_PLAYER_NO_OP;
556 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
557 return MM_ERROR_PLAYER_NO_OP;
560 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
562 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
563 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
566 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
569 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
570 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
572 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
573 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
576 LOGE("invalid mmplayer resource type %d", type);
577 return MM_ERROR_PLAYER_INTERNAL;
580 if (player->hw_resource[type] != NULL) {
581 LOGD("[%d type] resource was already acquired", type);
582 return MM_ERROR_NONE;
585 LOGD("mark for acquire [%d type] resource", type);
586 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
587 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
593 rm_ret = mm_resource_manager_commit(player->resource_manager);
594 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
595 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
596 return MM_ERROR_PLAYER_INTERNAL;
600 return MM_ERROR_NONE;
603 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
605 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
609 if (player->hw_resource[type] == NULL) {
610 LOGD("there is no acquired [%d type] resource", type);
611 return MM_ERROR_NONE;
614 LOGD("mark for release [%d type] resource", type);
615 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
616 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
617 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
618 return MM_ERROR_PLAYER_INTERNAL;
621 player->hw_resource[type] = NULL;
623 rm_ret = mm_resource_manager_commit(player->resource_manager);
624 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
625 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
626 return MM_ERROR_PLAYER_INTERNAL;
630 return MM_ERROR_NONE;
634 __mmplayer_initialize_gapless_play(mmplayer_t *player)
640 player->smooth_streaming = FALSE;
641 player->videodec_linked = 0;
642 player->audiodec_linked = 0;
643 player->textsink_linked = 0;
644 player->is_external_subtitle_present = FALSE;
645 player->is_external_subtitle_added_now = FALSE;
646 player->not_supported_codec = MISSING_PLUGIN_NONE;
647 player->can_support_codec = FOUND_PLUGIN_NONE;
648 player->pending_seek.is_pending = false;
649 player->pending_seek.pos = 0;
650 player->msg_posted = FALSE;
651 player->has_many_types = FALSE;
652 player->no_more_pad = FALSE;
653 player->not_found_demuxer = 0;
654 player->seek_state = MMPLAYER_SEEK_NONE;
655 player->is_subtitle_force_drop = FALSE;
656 player->play_subtitle = FALSE;
657 player->adjust_subtitle_pos = 0;
659 player->total_bitrate = 0;
660 player->total_maximum_bitrate = 0;
662 _mmplayer_track_initialize(player);
663 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
665 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
666 player->bitrate[i] = 0;
667 player->maximum_bitrate[i] = 0;
670 if (player->v_stream_caps) {
671 gst_caps_unref(player->v_stream_caps);
672 player->v_stream_caps = NULL;
675 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
677 /* clean found audio decoders */
678 if (player->audio_decoders) {
679 GList *a_dec = player->audio_decoders;
680 for (; a_dec; a_dec = g_list_next(a_dec)) {
681 gchar *name = a_dec->data;
682 MMPLAYER_FREEIF(name);
684 g_list_free(player->audio_decoders);
685 player->audio_decoders = NULL;
688 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
693 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
695 LOGI("set pipeline reconfigure state %d", state);
696 MMPLAYER_RECONFIGURE_LOCK(player);
697 player->gapless.reconfigure = state;
698 if (!state) /* wake up the waiting job */
699 MMPLAYER_RECONFIGURE_SIGNAL(player);
700 MMPLAYER_RECONFIGURE_UNLOCK(player);
704 __mmplayer_gapless_play_thread(gpointer data)
706 mmplayer_t *player = (mmplayer_t *)data;
707 mmplayer_gst_element_t *mainbin = NULL;
709 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
711 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
712 while (!player->gapless_play_thread_exit) {
713 LOGD("gapless play thread started. waiting for signal.");
714 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
716 LOGD("reconfigure pipeline for gapless play.");
718 if (player->gapless_play_thread_exit) {
719 _mmplayer_set_reconfigure_state(player, FALSE);
720 LOGD("exiting gapless play thread");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 /* Initialize Player values */
733 __mmplayer_initialize_gapless_play(player);
735 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
745 GSource *source = NULL;
749 source = g_main_context_find_source_by_id(context, source_id);
750 if (source != NULL) {
751 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
752 g_source_destroy(source);
759 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
762 GstMessage *msg = NULL;
763 GQueue *queue = NULL;
766 MMPLAYER_RETURN_IF_FAIL(player);
768 /* disconnecting bus watch */
769 if (player->bus_watcher)
770 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
771 player->bus_watcher = 0;
773 /* destroy the gst bus msg thread */
774 if (player->bus_msg_thread) {
775 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
776 player->bus_msg_thread_exit = TRUE;
777 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
778 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
780 LOGD("gst bus msg thread exit.");
781 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
782 player->bus_msg_thread = NULL;
784 g_mutex_clear(&player->bus_msg_thread_mutex);
785 g_cond_clear(&player->bus_msg_thread_cond);
788 g_mutex_lock(&player->bus_msg_q_lock);
789 queue = player->bus_msg_q;
790 while (!g_queue_is_empty(queue)) {
791 msg = (GstMessage *)g_queue_pop_head(queue);
796 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
797 gst_message_unref(msg);
799 g_mutex_unlock(&player->bus_msg_q_lock);
805 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
807 GstElement *parent = NULL;
809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
810 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
813 MMPLAYER_FSINK_LOCK(player);
815 /* get parent of fakesink */
816 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
818 LOGD("fakesink already removed");
822 gst_element_set_locked_state(fakesink->gst, TRUE);
824 /* setting the state to NULL never returns async
825 * so no need to wait for completion of state transiton
827 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
828 LOGE("fakesink state change failure!");
829 /* FIXIT : should I return here? or try to proceed to next? */
832 /* remove fakesink from it's parent */
833 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
834 LOGE("failed to remove fakesink");
836 gst_object_unref(parent);
841 gst_object_unref(parent);
843 LOGD("state-holder removed");
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
852 gst_element_set_locked_state(fakesink->gst, FALSE);
854 MMPLAYER_FSINK_UNLOCK(player);
858 static GstPadProbeReturn
859 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
861 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
862 return GST_PAD_PROBE_OK;
866 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
868 gint64 stop_running_time = 0;
869 gint64 position_running_time = 0;
873 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
874 if ((player->gapless.update_segment[idx] == TRUE) ||
875 !(player->selector[idx].event_probe_id)) {
877 LOGW("[%d] skip", idx);
882 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
884 gst_segment_to_running_time(&player->gapless.segment[idx],
885 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
886 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
888 gst_segment_to_running_time(&player->gapless.segment[idx],
889 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
891 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
893 gst_segment_to_running_time(&player->gapless.segment[idx],
894 GST_FORMAT_TIME, player->duration);
897 position_running_time =
898 gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].position);
901 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
902 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
904 GST_TIME_ARGS(stop_running_time),
905 GST_TIME_ARGS(position_running_time),
906 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
907 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
909 position_running_time = MAX(position_running_time, stop_running_time);
910 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].start);
912 position_running_time = MAX(0, position_running_time);
913 position = MAX(position, position_running_time);
917 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
918 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
919 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
921 player->gapless.start_time[stream_type] += position;
927 static GstPadProbeReturn
928 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
930 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
931 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
932 mmplayer_t *player = (mmplayer_t *)data;
933 GstCaps *caps = NULL;
934 GstStructure *str = NULL;
935 const gchar *name = NULL;
936 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
937 gboolean caps_ret = TRUE;
939 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
940 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
941 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
942 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
943 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
946 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
950 if (strstr(name, "audio")) {
951 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
952 } else if (strstr(name, "video")) {
953 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
955 /* text track is not supportable */
956 LOGE("invalid name %s", name);
960 switch (GST_EVENT_TYPE(event)) {
963 /* in case of gapless, drop eos event not to send it to sink */
964 if (player->gapless.reconfigure && !player->msg_posted) {
965 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
966 ret = GST_PAD_PROBE_DROP;
970 case GST_EVENT_STREAM_START:
972 __mmplayer_gst_selector_update_start_time(player, stream_type);
975 case GST_EVENT_FLUSH_STOP:
977 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
978 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
979 player->gapless.start_time[stream_type] = 0;
982 case GST_EVENT_SEGMENT:
987 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
988 gst_event_copy_segment(event, &segment);
990 if (segment.format != GST_FORMAT_TIME)
993 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
994 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
995 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
996 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
997 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
998 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1000 /* keep the all the segment ev to cover the seeking */
1001 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1002 player->gapless.update_segment[stream_type] = TRUE;
1004 if (!player->gapless.running)
1007 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1009 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1011 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1012 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1013 gst_event_unref(event);
1014 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1020 gdouble proportion = 0.0;
1021 GstClockTimeDiff diff = 0;
1022 GstClockTime timestamp = 0;
1023 gint64 running_time_diff = -1;
1024 GstQOSType type = 0;
1025 GstEvent *tmpev = NULL;
1027 running_time_diff = player->gapless.segment[stream_type].base;
1029 if (running_time_diff <= 0) /* don't need to adjust */
1032 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1033 gst_event_unref(event);
1035 if (timestamp < running_time_diff) {
1036 LOGW("QOS event from previous group");
1037 ret = GST_PAD_PROBE_DROP;
1042 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1043 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1044 stream_type, GST_TIME_ARGS(timestamp),
1045 GST_TIME_ARGS(running_time_diff),
1046 GST_TIME_ARGS(timestamp - running_time_diff));
1049 timestamp -= running_time_diff;
1051 /* That case is invalid for QoS events */
1052 if (diff < 0 && -diff > timestamp) {
1053 LOGW("QOS event from previous group");
1054 ret = GST_PAD_PROBE_DROP;
1058 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1059 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1069 gst_caps_unref(caps);
1073 /* create fakesink for audio or video path witout audiobin or videobin */
1075 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1077 GstElement *pipeline = NULL;
1078 GstElement *fakesink = NULL;
1079 GstPad *sinkpad = NULL;
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1087 fakesink = gst_element_factory_make("fakesink", NULL);
1088 if (fakesink == NULL) {
1089 LOGE("failed to create fakesink");
1093 /* store it as it's sink element */
1094 __mmplayer_add_sink(player, fakesink);
1096 gst_bin_add(GST_BIN(pipeline), fakesink);
1099 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1101 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1103 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1104 LOGE("failed to link fakesink");
1105 gst_object_unref(GST_OBJECT(fakesink));
1109 if (strstr(name, "video")) {
1110 if (player->v_stream_caps) {
1111 gst_caps_unref(player->v_stream_caps);
1112 player->v_stream_caps = NULL;
1114 if (player->ini.set_dump_element_flag)
1115 __mmplayer_add_dump_buffer_probe(player, fakesink);
1118 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1119 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1123 gst_object_unref(GST_OBJECT(sinkpad));
1130 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1132 GstElement *pipeline = NULL;
1133 GstElement *selector = NULL;
1134 GstPad *srcpad = NULL;
1137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1139 selector = gst_element_factory_make("input-selector", NULL);
1141 LOGE("failed to create input-selector");
1144 g_object_set(selector, "sync-streams", TRUE, NULL);
1146 player->pipeline->mainbin[elem_idx].id = elem_idx;
1147 player->pipeline->mainbin[elem_idx].gst = selector;
1149 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1151 srcpad = gst_element_get_static_pad(selector, "src");
1153 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1154 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1155 __mmplayer_gst_selector_blocked, NULL, NULL);
1156 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1157 __mmplayer_gst_selector_event_probe, player, NULL);
1159 gst_element_set_state(selector, GST_STATE_PAUSED);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1162 gst_bin_add(GST_BIN(pipeline), selector);
1164 gst_object_unref(GST_OBJECT(srcpad));
1171 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1173 mmplayer_t *player = (mmplayer_t *)data;
1174 GstElement *selector = NULL;
1175 GstCaps *caps = NULL;
1176 GstStructure *str = NULL;
1177 const gchar *name = NULL;
1178 GstPad *sinkpad = NULL;
1179 gboolean first_track = FALSE;
1180 gboolean caps_ret = TRUE;
1182 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1183 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1186 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1187 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1189 LOGD("pad-added signal handling");
1191 /* get mimetype from caps */
1192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1196 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1198 LOGD("detected mimetype : %s", name);
1201 if (strstr(name, "video")) {
1203 gchar *caps_str = NULL;
1205 caps_str = gst_caps_to_string(caps);
1206 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1207 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1208 player->set_mode.video_zc = true;
1210 MMPLAYER_FREEIF(caps_str);
1212 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1213 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1215 LOGD("surface type : %d", stype);
1217 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1218 __mmplayer_gst_create_sinkbin(elem, pad, player);
1222 /* in case of exporting video frame, it requires the 360 video filter.
1223 * it will be handled in _no_more_pads(). */
1224 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1225 __mmplayer_gst_make_fakesink(player, pad, name);
1229 LOGD("video selector is required");
1230 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1232 } else if (strstr(name, "audio")) {
1233 gint samplerate = 0;
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1237 if (player->build_audio_offload)
1238 player->no_more_pad = TRUE; /* remove state holder */
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 gst_structure_get_int(str, "rate", &samplerate);
1244 gst_structure_get_int(str, "channels", &channels);
1246 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1247 __mmplayer_gst_make_fakesink(player, pad, name);
1251 LOGD("audio selector is required");
1252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1253 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1255 } else if (strstr(name, "text")) {
1256 LOGD("text selector is required");
1257 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1258 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1260 LOGE("invalid caps info");
1264 /* check selector and create it */
1265 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1266 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1271 LOGD("input-selector is already created.");
1275 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1277 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1279 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1280 LOGE("failed to link selector");
1281 gst_object_unref(GST_OBJECT(selector));
1286 LOGD("this track will be activated");
1287 g_object_set(selector, "active-pad", sinkpad, NULL);
1290 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1296 gst_caps_unref(caps);
1299 gst_object_unref(GST_OBJECT(sinkpad));
1307 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1309 GstPad *srcpad = NULL;
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1314 LOGD("type %d", type);
1317 LOGD("there is no %d track", type);
1321 srcpad = gst_element_get_static_pad(selector, "src");
1323 LOGE("failed to get srcpad from selector");
1327 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1329 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1331 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1332 if (player->selector[type].block_id) {
1333 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1334 player->selector[type].block_id = 0;
1338 gst_object_unref(GST_OBJECT(srcpad));
1347 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1349 gint active_index = 0;
1352 MMPLAYER_RETURN_IF_FAIL(player);
1354 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1356 /* change track to active pad */
1357 active_index = player->selector[type].active_pad_index;
1358 if ((active_index != DEFAULT_TRACK) &&
1359 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1360 LOGW("failed to change %d type track to %d", type, active_index);
1361 player->selector[type].active_pad_index = DEFAULT_TRACK;
1365 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1366 mm_player_set_attribute((MMHandleType)player, NULL,
1367 "content_text_track_num", player->selector[type].total_track_num,
1368 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1375 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1378 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1380 if (!audio_selector) {
1381 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1383 /* in case the source is changed, output can be changed. */
1384 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1385 LOGD("remove previous audiobin if it exist");
1387 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1388 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1390 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1391 MMPLAYER_FREEIF(player->pipeline->audiobin);
1394 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1395 __mmplayer_pipeline_complete(NULL, player);
1400 /* apply the audio track information */
1401 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1403 /* create audio sink path */
1404 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1405 LOGE("failed to create audio sink path");
1414 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1417 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1419 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1420 LOGD("text path is not supproted");
1424 /* apply the text track information */
1425 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1427 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1428 player->has_closed_caption = TRUE;
1430 /* create text decode path */
1431 player->no_more_pad = TRUE;
1433 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1434 LOGE("failed to create text sink path");
1443 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1445 gint64 dur_bytes = 0L;
1448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1449 player->pipeline->mainbin && player->streamer, FALSE);
1451 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1452 LOGE("fail to get duration.");
1454 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1455 * use file information was already set on Q2 when it was created. */
1456 _mm_player_streaming_set_queue2(player->streamer,
1457 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1458 TRUE, /* use_buffering */
1459 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1460 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1467 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1469 mmplayer_t *player = NULL;
1470 GstElement *video_selector = NULL;
1471 GstElement *audio_selector = NULL;
1472 GstElement *text_selector = NULL;
1475 player = (mmplayer_t *)data;
1477 LOGD("no-more-pad signal handling");
1479 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1480 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1481 LOGW("player is shutting down");
1485 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1486 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1487 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1488 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1489 LOGE("failed to set queue2 buffering");
1494 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1495 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1496 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1498 if (!video_selector && !audio_selector && !text_selector) {
1499 LOGW("there is no selector");
1500 player->no_more_pad = TRUE;
1504 /* create video path followed by video-select */
1505 if (video_selector && !audio_selector && !text_selector)
1506 player->no_more_pad = TRUE;
1508 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1511 /* create audio path followed by audio-select */
1512 if (audio_selector && !text_selector)
1513 player->no_more_pad = TRUE;
1515 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1518 /* create text path followed by text-select */
1519 __mmplayer_create_text_sink_path(player, text_selector);
1522 _mmplayer_set_reconfigure_state(player, FALSE);
1527 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1529 gboolean ret = FALSE;
1530 GstElement *pipeline = NULL;
1531 GstPad *sinkpad = NULL;
1534 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1537 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1539 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1541 LOGE("failed to get pad from sinkbin");
1547 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1548 LOGE("failed to link sinkbin for reusing");
1549 goto EXIT; /* exit either pass or fail */
1553 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1554 LOGE("failed to set state(READY) to sinkbin");
1559 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1560 LOGE("failed to add sinkbin to pipeline");
1565 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1566 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1571 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1572 LOGE("failed to set state(PAUSED) to sinkbin");
1581 gst_object_unref(GST_OBJECT(sinkpad));
1589 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1591 mmplayer_t *player = NULL;
1592 GstCaps *caps = NULL;
1593 gchar *caps_str = NULL;
1594 GstStructure *str = NULL;
1595 const gchar *name = NULL;
1596 GstElement *sinkbin = NULL;
1597 gboolean reusing = FALSE;
1598 gboolean caps_ret = TRUE;
1599 gchar *sink_pad_name = "sink";
1602 player = (mmplayer_t *)data;
1605 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1606 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1608 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1612 caps_str = gst_caps_to_string(caps);
1614 LOGD("detected mimetype : %s", name);
1616 if (strstr(name, "audio")) {
1617 if (player->pipeline->audiobin == NULL) {
1618 const gchar *audio_format = gst_structure_get_string(str, "format");
1620 LOGD("original audio format %s", audio_format);
1621 mm_player_set_attribute((MMHandleType)player, NULL,
1622 "content_audio_format", audio_format, strlen(audio_format), NULL);
1625 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1626 LOGE("failed to create audiobin. continuing without audio");
1630 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1631 LOGD("creating audiobin success");
1634 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1635 LOGD("reusing audiobin");
1636 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1638 } else if (strstr(name, "video")) {
1639 /* 1. zero copy is updated at _decode_pad_added()
1640 * 2. NULL surface type is handled in _decode_pad_added() */
1641 LOGD("zero copy %d", player->set_mode.video_zc);
1642 if (player->pipeline->videobin == NULL) {
1643 int surface_type = 0;
1644 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1645 LOGD("display_surface_type (%d)", surface_type);
1647 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1648 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1649 LOGE("failed to acquire video overlay resource");
1653 player->interrupted_by_resource = FALSE;
1655 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1656 LOGE("failed to create videobin. continuing without video");
1660 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1661 LOGD("creating videosink bin success");
1664 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1665 LOGD("re-using videobin");
1666 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1668 } else if (strstr(name, "text")) {
1669 if (player->pipeline->textbin == NULL) {
1670 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1671 LOGE("failed to create text sink bin. continuing without text");
1675 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1676 player->textsink_linked = 1;
1677 LOGD("creating textsink bin success");
1679 if (!player->textsink_linked) {
1680 LOGD("re-using textbin");
1682 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1683 player->textsink_linked = 1;
1685 /* linked textbin exist which means that the external subtitle path exist already */
1686 LOGW("ignoring internal subtutle since external subtitle is available");
1689 sink_pad_name = "text_sink";
1691 LOGW("unknown mime type %s, ignoring it", name);
1695 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1698 LOGD("[handle: %p] success to create and link sink bin", player);
1700 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1701 * streaming task. if the task blocked, then buffer will not flow to the next element
1702 *(autoplugging element). so this is special hack for streaming. please try to remove it
1704 /* dec stream count. we can remove fakesink if it's zero */
1705 if (player->num_dynamic_pad)
1706 player->num_dynamic_pad--;
1708 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1710 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1711 __mmplayer_pipeline_complete(NULL, player);
1715 MMPLAYER_FREEIF(caps_str);
1718 gst_caps_unref(caps);
1724 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1726 int required_angle = 0; /* Angle required for straight view */
1727 int rotation_angle = 0;
1729 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1730 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1732 /* Counter clockwise */
1733 switch (orientation) {
1738 required_angle = 270;
1741 required_angle = 180;
1744 required_angle = 90;
1748 rotation_angle = display_angle + required_angle;
1749 if (rotation_angle >= 360)
1750 rotation_angle -= 360;
1752 /* chech if supported or not */
1753 if (rotation_angle % 90) {
1754 LOGD("not supported rotation angle = %d", rotation_angle);
1758 switch (rotation_angle) {
1760 *value = MM_DISPLAY_ROTATION_NONE;
1763 *value = MM_DISPLAY_ROTATION_90;
1766 *value = MM_DISPLAY_ROTATION_180;
1769 *value = MM_DISPLAY_ROTATION_270;
1773 LOGD("setting rotation property value : %d", *value);
1779 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1781 int display_rotation = 0;
1782 gchar *org_orient = NULL;
1783 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1786 LOGE("cannot get content attribute");
1787 return MM_ERROR_PLAYER_INTERNAL;
1790 if (display_angle) {
1791 /* update user roation */
1792 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1794 /* Counter clockwise */
1795 switch (display_rotation) {
1796 case MM_DISPLAY_ROTATION_NONE:
1799 case MM_DISPLAY_ROTATION_90:
1800 *display_angle = 90;
1802 case MM_DISPLAY_ROTATION_180:
1803 *display_angle = 180;
1805 case MM_DISPLAY_ROTATION_270:
1806 *display_angle = 270;
1809 LOGW("wrong angle type : %d", display_rotation);
1812 LOGD("check user angle: %d", *display_angle);
1816 /* Counter clockwise */
1817 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1820 if (!strcmp(org_orient, "rotate-90"))
1822 else if (!strcmp(org_orient, "rotate-180"))
1824 else if (!strcmp(org_orient, "rotate-270"))
1827 LOGD("original rotation is %s", org_orient);
1829 LOGD("content_video_orientation get fail");
1832 LOGD("check orientation: %d", *orientation);
1835 return MM_ERROR_NONE;
1838 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1840 int rotation_value = 0;
1841 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1842 int display_angle = 0;
1845 /* check video sinkbin is created */
1846 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1849 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1851 /* get rotation value to set */
1852 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1853 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1854 LOGD("set video param : rotate %d", rotation_value);
1857 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1859 MMHandleType attrs = 0;
1863 /* check video sinkbin is created */
1864 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1867 attrs = MMPLAYER_GET_ATTRS(player);
1868 MMPLAYER_RETURN_IF_FAIL(attrs);
1870 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1871 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1872 LOGD("set video param : visible %d", visible);
1875 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1877 MMHandleType attrs = 0;
1878 int display_method = 0;
1881 /* check video sinkbin is created */
1882 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1885 attrs = MMPLAYER_GET_ATTRS(player);
1886 MMPLAYER_RETURN_IF_FAIL(attrs);
1888 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1889 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1890 LOGD("set video param : method %d", display_method);
1893 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1895 MMHandleType attrs = 0;
1899 /* check video sinkbin is created */
1900 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1903 attrs = MMPLAYER_GET_ATTRS(player);
1904 MMPLAYER_RETURN_IF_FAIL(attrs);
1906 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1907 MMPLAYER_RETURN_IF_FAIL(handle);
1909 gst_video_overlay_set_video_roi_area(
1910 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1912 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1913 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1916 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1918 MMHandleType attrs = 0;
1923 int win_roi_width = 0;
1924 int win_roi_height = 0;
1927 /* check video sinkbin is created */
1928 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1931 attrs = MMPLAYER_GET_ATTRS(player);
1932 MMPLAYER_RETURN_IF_FAIL(attrs);
1934 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1935 MMPLAYER_RETURN_IF_FAIL(handle);
1937 /* It should be set after setting window */
1938 mm_attrs_multiple_get(attrs, NULL,
1939 "display_win_roi_x", &win_roi_x,
1940 "display_win_roi_y", &win_roi_y,
1941 "display_win_roi_width", &win_roi_width,
1942 "display_win_roi_height", &win_roi_height, NULL);
1944 /* After setting window handle, set display roi area */
1945 gst_video_overlay_set_display_roi_area(
1946 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1948 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1949 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1952 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1954 MMHandleType attrs = 0;
1957 /* check video sinkbin is created */
1958 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1961 attrs = MMPLAYER_GET_ATTRS(player);
1962 MMPLAYER_RETURN_IF_FAIL(attrs);
1964 /* common case if using overlay surface */
1965 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1966 MMPLAYER_RETURN_IF_FAIL(handle);
1968 /* default is using wl_surface_id */
1969 LOGD("set video param : wl_surface_id %d", handle);
1970 gst_video_overlay_set_wl_window_wl_surface_id(
1971 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1976 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1978 gboolean update_all_param = FALSE;
1982 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1983 LOGW("videosink is not ready yet");
1984 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1987 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1988 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1989 return MM_ERROR_PLAYER_INTERNAL;
1992 LOGD("param_name : %s", param_name);
1993 if (!g_strcmp0(param_name, "update_all_param"))
1994 update_all_param = TRUE;
1996 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1997 __mmplayer_video_param_set_display_overlay(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1999 __mmplayer_video_param_set_display_method(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2001 __mmplayer_video_param_set_display_visible(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2003 __mmplayer_video_param_set_display_rotation(player);
2004 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2005 __mmplayer_video_param_set_roi_area(player);
2006 if (update_all_param)
2007 __mmplayer_video_param_set_video_roi_area(player);
2011 return MM_ERROR_NONE;
2015 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2017 gboolean disable_overlay = FALSE;
2018 mmplayer_t *player = (mmplayer_t *)hplayer;
2021 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2022 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2023 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2024 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2026 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2027 LOGW("Display control is not supported");
2028 return MM_ERROR_PLAYER_INTERNAL;
2031 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2033 if (audio_only == (bool)disable_overlay) {
2034 LOGE("It's the same with current setting: (%d)", audio_only);
2035 return MM_ERROR_NONE;
2039 LOGE("disable overlay");
2040 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2042 /* release overlay resource */
2043 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2044 LOGE("failed to release overlay resource");
2048 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2049 LOGE("failed to acquire video overlay resource");
2052 player->interrupted_by_resource = FALSE;
2054 LOGD("enable overlay");
2055 __mmplayer_video_param_set_display_overlay(player);
2056 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2061 return MM_ERROR_NONE;
2065 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2067 mmplayer_t *player = (mmplayer_t *)hplayer;
2068 gboolean disable_overlay = FALSE;
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2073 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2075 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2076 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2078 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2079 LOGW("Display control is not supported");
2080 return MM_ERROR_PLAYER_INTERNAL;
2083 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2085 *paudio_only = (bool)disable_overlay;
2087 LOGD("audio_only : %d", *paudio_only);
2091 return MM_ERROR_NONE;
2095 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2097 GList *bucket = element_bucket;
2098 mmplayer_gst_element_t *element = NULL;
2099 mmplayer_gst_element_t *prv_element = NULL;
2100 GstElement *tee_element = NULL;
2101 gint successful_link_count = 0;
2105 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2107 prv_element = (mmplayer_gst_element_t *)bucket->data;
2108 bucket = bucket->next;
2110 for (; bucket; bucket = bucket->next) {
2111 element = (mmplayer_gst_element_t *)bucket->data;
2113 if (element && element->gst) {
2114 if (prv_element && prv_element->gst) {
2115 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2117 prv_element->gst = tee_element;
2119 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2120 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2121 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2125 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2126 LOGD("linking [%s] to [%s] success",
2127 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2128 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2129 successful_link_count++;
2130 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2131 LOGD("keep audio-tee element for next audio pipeline branch");
2132 tee_element = prv_element->gst;
2135 LOGD("linking [%s] to [%s] failed",
2136 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2137 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2143 prv_element = element;
2148 return successful_link_count;
2152 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2154 GList *bucket = element_bucket;
2155 mmplayer_gst_element_t *element = NULL;
2156 int successful_add_count = 0;
2160 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2161 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2163 for (; bucket; bucket = bucket->next) {
2164 element = (mmplayer_gst_element_t *)bucket->data;
2166 if (element && element->gst) {
2167 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2168 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2169 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2170 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2173 successful_add_count++;
2179 return successful_add_count;
2183 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2185 mmplayer_t *player = (mmplayer_t *)data;
2186 GstCaps *caps = NULL;
2187 GstStructure *str = NULL;
2189 gboolean caps_ret = TRUE;
2193 MMPLAYER_RETURN_IF_FAIL(pad);
2194 MMPLAYER_RETURN_IF_FAIL(unused);
2195 MMPLAYER_RETURN_IF_FAIL(data);
2197 caps = gst_pad_get_current_caps(pad);
2201 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2205 LOGD("name = %s", name);
2207 if (strstr(name, "audio")) {
2208 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2210 if (player->audio_stream_changed_cb) {
2211 LOGE("call the audio stream changed cb");
2212 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2214 } else if (strstr(name, "video")) {
2215 if ((name = gst_structure_get_string(str, "format")))
2216 player->set_mode.video_zc = name[0] == 'S';
2218 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2219 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2221 LOGW("invalid caps info");
2226 gst_caps_unref(caps);
2234 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2239 MMPLAYER_RETURN_IF_FAIL(player);
2241 if (player->audio_stream_buff_list) {
2242 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2243 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2246 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2247 __mmplayer_audio_stream_send_data(player, tmp);
2249 MMPLAYER_FREEIF(tmp->pcm_data);
2250 MMPLAYER_FREEIF(tmp);
2253 g_list_free(player->audio_stream_buff_list);
2254 player->audio_stream_buff_list = NULL;
2261 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2263 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2266 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2268 audio_stream.bitrate = a_buffer->bitrate;
2269 audio_stream.channel = a_buffer->channel;
2270 audio_stream.channel_mask = a_buffer->channel_mask;
2271 audio_stream.data_size = a_buffer->data_size;
2272 audio_stream.data = a_buffer->pcm_data;
2273 audio_stream.pcm_format = a_buffer->pcm_format;
2275 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2277 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2283 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2285 mmplayer_t *player = (mmplayer_t *)data;
2286 const gchar *pcm_format = NULL;
2289 guint64 channel_mask = 0;
2290 void *a_data = NULL;
2292 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2293 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2297 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2299 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2300 a_data = mapinfo.data;
2301 a_size = mapinfo.size;
2303 GstCaps *caps = gst_pad_get_current_caps(pad);
2304 GstStructure *structure = gst_caps_get_structure(caps, 0);
2306 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2308 pcm_format = gst_structure_get_string(structure, "format");
2309 gst_structure_get_int(structure, "rate", &rate);
2310 gst_structure_get_int(structure, "channels", &channel);
2311 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2312 gst_caps_unref(GST_CAPS(caps));
2314 /* In case of the sync is false, use buffer list. *
2315 * The num of buffer list depends on the num of audio channels */
2316 if (player->audio_stream_buff_list) {
2317 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2318 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2320 if (channel_mask == tmp->channel_mask) {
2322 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2324 if (tmp->data_size + a_size < tmp->buff_size) {
2325 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2326 tmp->data_size += a_size;
2328 /* send data to client */
2329 __mmplayer_audio_stream_send_data(player, tmp);
2331 if (a_size > tmp->buff_size) {
2332 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2333 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2334 if (tmp->pcm_data == NULL) {
2335 LOGE("failed to realloc data.");
2338 tmp->buff_size = a_size;
2340 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2341 memcpy(tmp->pcm_data, a_data, a_size);
2342 tmp->data_size = a_size;
2347 LOGE("data is empty in list.");
2353 /* create new audio stream data for newly found audio channel */
2354 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2355 if (a_buffer == NULL) {
2356 LOGE("failed to alloc data.");
2359 a_buffer->bitrate = rate;
2360 a_buffer->channel = channel;
2361 a_buffer->channel_mask = channel_mask;
2362 a_buffer->data_size = a_size;
2363 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2365 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2366 /* If sync is FALSE, use buffer list to reduce the IPC. */
2367 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2368 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2369 if (a_buffer->pcm_data == NULL) {
2370 LOGE("failed to alloc data.");
2371 MMPLAYER_FREEIF(a_buffer);
2374 memcpy(a_buffer->pcm_data, a_data, a_size);
2376 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2378 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2380 /* If sync is TRUE, send data directly. */
2381 a_buffer->pcm_data = a_data;
2382 __mmplayer_audio_stream_send_data(player, a_buffer);
2383 MMPLAYER_FREEIF(a_buffer);
2387 gst_buffer_unmap(buffer, &mapinfo);
2392 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2394 mmplayer_t *player = (mmplayer_t *)data;
2395 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2396 GstPad *sinkpad = NULL;
2397 GstElement *queue = NULL, *sink = NULL;
2400 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2402 queue = gst_element_factory_make("queue", NULL);
2403 if (queue == NULL) {
2404 LOGD("fail make queue");
2408 sink = gst_element_factory_make("fakesink", NULL);
2410 LOGD("fail make fakesink");
2414 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2416 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2417 LOGW("failed to link queue & sink");
2421 sinkpad = gst_element_get_static_pad(queue, "sink");
2423 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2424 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2428 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2430 gst_object_unref(sinkpad);
2431 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2432 g_object_set(sink, "sync", TRUE, NULL);
2433 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2435 /* keep the first sink reference only */
2436 if (!audiobin[MMPLAYER_A_SINK].gst) {
2437 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2438 audiobin[MMPLAYER_A_SINK].gst = sink;
2442 _mmplayer_add_signal_connection(player,
2444 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2446 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2449 __mmplayer_add_sink(player, sink);
2451 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2452 LOGE("failed to sync state");
2456 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2457 LOGE("failed to sync state");
2465 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2467 gst_object_unref(GST_OBJECT(queue));
2471 gst_object_unref(GST_OBJECT(sink));
2475 gst_object_unref(GST_OBJECT(sinkpad));
2483 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2485 mmplayer_t *player = (mmplayer_t *)data;
2488 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2490 player->no_more_pad = TRUE;
2491 __mmplayer_pipeline_complete(NULL, player);
2498 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2500 #define MAX_PROPS_LEN 128
2501 mmplayer_gst_element_t *audiobin = NULL;
2502 gint latency_mode = 0;
2503 gchar *stream_type = NULL;
2504 gchar *latency = NULL;
2506 gchar stream_props[MAX_PROPS_LEN] = {0,};
2507 GstStructure *props = NULL;
2510 * It should be set after player creation through attribute.
2511 * But, it can not be changed during playing.
2514 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2516 audiobin = player->pipeline->audiobin;
2518 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2519 if (player->sound.mute) {
2520 LOGD("mute enabled");
2521 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2524 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2525 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2528 snprintf(stream_props, sizeof(stream_props) - 1,
2529 "props,application.process.id.origin=%d", player->client_pid);
2531 snprintf(stream_props, sizeof(stream_props) - 1,
2532 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2533 stream_type, stream_id, player->client_pid);
2535 props = gst_structure_from_string(stream_props, NULL);
2536 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2537 LOGI("props result[%s].", stream_props);
2538 gst_structure_free(props);
2540 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2542 switch (latency_mode) {
2543 case AUDIO_LATENCY_MODE_LOW:
2544 latency = g_strndup("low", 3);
2546 case AUDIO_LATENCY_MODE_MID:
2547 latency = g_strndup("mid", 3);
2549 case AUDIO_LATENCY_MODE_HIGH:
2550 latency = g_strndup("high", 4);
2554 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2556 LOGD("audiosink property - latency=%s", latency);
2558 MMPLAYER_FREEIF(latency);
2564 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2566 mmplayer_gst_element_t *audiobin = NULL;
2569 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2571 audiobin = player->pipeline->audiobin;
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2574 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2575 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2577 if (player->video360_yaw_radians <= M_PI &&
2578 player->video360_yaw_radians >= -M_PI &&
2579 player->video360_pitch_radians <= M_PI_2 &&
2580 player->video360_pitch_radians >= -M_PI_2) {
2581 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2582 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2583 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2584 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2585 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2586 "source-orientation-y", player->video360_metadata.init_view_heading,
2587 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2594 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2596 mmplayer_gst_element_t *audiobin = NULL;
2597 GstPad *sink_pad = NULL;
2598 GstCaps *acaps = NULL;
2600 int pitch_control = 0;
2601 double pitch_value = 1.0;
2604 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2605 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2607 audiobin = player->pipeline->audiobin;
2609 LOGD("make element for normal audio playback");
2611 /* audio bin structure for playback. {} means optional.
2612 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2614 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2615 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2618 /* for pitch control */
2619 mm_attrs_multiple_get(player->attrs, NULL,
2620 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2621 MM_PLAYER_PITCH_VALUE, &pitch_value,
2624 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2625 if (pitch_control && (player->videodec_linked == 0)) {
2626 GstElementFactory *factory;
2628 factory = gst_element_factory_find("pitch");
2630 gst_object_unref(factory);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2637 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2639 LOGW("there is no pitch element");
2644 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2646 /* replaygain volume */
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2648 if (player->sound.rg_enable)
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2651 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2654 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2656 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2657 /* currently, only openalsink uses volume element */
2658 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2659 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2661 if (player->sound.mute) {
2662 LOGD("mute enabled");
2663 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2667 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2669 /* audio effect element. if audio effect is enabled */
2670 if ((strcmp(player->ini.audioeffect_element, ""))
2672 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2673 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2675 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2677 if ((!player->bypass_audio_effect)
2678 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2679 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2680 if (!_mmplayer_audio_effect_custom_apply(player))
2681 LOGI("apply audio effect(custom) setting success");
2685 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2686 && (player->set_mode.rich_audio)) {
2687 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2691 /* create audio sink */
2692 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2693 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2694 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2696 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2697 if (player->is_360_feature_enabled &&
2698 player->is_content_spherical &&
2700 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2701 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2702 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2704 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2709 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2711 gst_caps_unref(acaps);
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2715 player->is_openal_plugin_used = TRUE;
2717 if (player->is_360_feature_enabled && player->is_content_spherical)
2718 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2722 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2723 (player->videodec_linked && player->ini.use_system_clock)) {
2724 LOGD("system clock will be used.");
2725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2728 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2729 __mmplayer_gst_set_pulsesink_property(player);
2730 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2731 __mmplayer_gst_set_openalsink_property(player);
2734 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2737 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2738 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2739 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2740 gst_object_unref(GST_OBJECT(sink_pad));
2742 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2745 return MM_ERROR_NONE;
2747 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2749 return MM_ERROR_PLAYER_INTERNAL;
2753 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2755 mmplayer_gst_element_t *audiobin = NULL;
2756 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2758 gchar *dst_format = NULL;
2760 int dst_samplerate = 0;
2761 int dst_channels = 0;
2762 GstCaps *caps = NULL;
2763 char *caps_str = NULL;
2766 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2767 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2769 audiobin = player->pipeline->audiobin;
2771 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2773 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2775 [case 1] extract interleave audio pcm without playback
2776 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2777 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2779 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2781 [case 2] deinterleave for each channel without playback
2782 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2783 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2785 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2786 - fakesink (sync or not)
2789 [case 3] [case 1(sync only)] + playback
2790 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2792 * src - ... - tee - queue1 - playback path
2793 - queue2 - [case1 pipeline with sync]
2795 [case 4] [case 2(sync only)] + playback
2796 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2798 * src - ... - tee - queue1 - playback path
2799 - queue2 - [case2 pipeline with sync]
2803 /* 1. create tee and playback path
2804 'tee' should be added at first to copy the decoded stream
2806 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2807 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2810 /* tee - path 1 : for playback path */
2811 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2812 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2814 /* tee - path 2 : for extract path */
2815 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2816 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2819 /* if there is tee, 'tee - path 2' is linked here */
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2824 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2826 /* 2. decide the extract pcm format */
2827 mm_attrs_multiple_get(player->attrs, NULL,
2828 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2829 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2830 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2833 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2834 dst_format, dst_len, dst_samplerate, dst_channels);
2836 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2837 mm_attrs_multiple_get(player->attrs, NULL,
2838 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2839 "content_audio_samplerate", &dst_samplerate,
2840 "content_audio_channels", &dst_channels,
2843 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2844 dst_format, dst_len, dst_samplerate, dst_channels);
2846 /* If there is no enough information, set it to platform default value. */
2847 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2848 LOGD("set platform default format");
2849 dst_format = DEFAULT_PCM_OUT_FORMAT;
2851 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2852 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2855 /* 3. create capsfilter */
2856 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2857 caps = gst_caps_new_simple("audio/x-raw",
2858 "format", G_TYPE_STRING, dst_format,
2859 "rate", G_TYPE_INT, dst_samplerate,
2860 "channels", G_TYPE_INT, dst_channels,
2863 caps_str = gst_caps_to_string(caps);
2864 LOGD("new caps : %s", caps_str);
2866 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2869 gst_caps_unref(caps);
2870 MMPLAYER_FREEIF(caps_str);
2872 /* 4-1. create deinterleave to extract pcm for each channel */
2873 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2874 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2875 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2877 /* audiosink will be added after getting signal for each channel */
2878 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2879 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2880 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2881 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2882 player->no_more_pad = FALSE;
2884 /* 4-2. create fakesink to extract interlevaed pcm */
2885 LOGD("add audio fakesink for interleaved audio");
2886 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2887 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2888 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2889 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2891 _mmplayer_add_signal_connection(player,
2892 G_OBJECT(audiobin[extract_sink_id].gst),
2893 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2895 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2898 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2902 return MM_ERROR_NONE;
2904 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2906 return MM_ERROR_PLAYER_INTERNAL;
2910 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2912 int ret = MM_ERROR_NONE;
2913 mmplayer_gst_element_t *audiobin = NULL;
2914 GList *element_bucket = NULL;
2917 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2918 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2920 audiobin = player->pipeline->audiobin;
2922 if (player->build_audio_offload) { /* skip all the audio filters */
2923 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2925 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2926 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2927 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2929 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2933 /* FIXME: need to mention the supportable condition at API reference */
2934 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2935 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2937 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2939 if (ret != MM_ERROR_NONE)
2942 LOGD("success to make audio bin element");
2943 *bucket = element_bucket;
2946 return MM_ERROR_NONE;
2949 LOGE("failed to make audio bin element");
2950 g_list_free(element_bucket);
2954 return MM_ERROR_PLAYER_INTERNAL;
2958 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2960 mmplayer_gst_element_t *first_element = NULL;
2961 mmplayer_gst_element_t *audiobin = NULL;
2963 GstPad *ghostpad = NULL;
2964 GList *element_bucket = NULL;
2968 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2971 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2973 LOGE("failed to allocate memory for audiobin");
2974 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2978 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2979 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2980 if (!audiobin[MMPLAYER_A_BIN].gst) {
2981 LOGE("failed to create audiobin");
2986 player->pipeline->audiobin = audiobin;
2988 /* create audio filters and audiosink */
2989 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2992 /* adding created elements to bin */
2993 LOGD("adding created elements to bin");
2994 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2997 /* linking elements in the bucket by added order. */
2998 LOGD("Linking elements in the bucket by added order.");
2999 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3002 /* get first element's sinkpad for creating ghostpad */
3003 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3004 if (!first_element) {
3005 LOGE("failed to get first elem");
3009 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3011 LOGE("failed to get pad from first element of audiobin");
3015 ghostpad = gst_ghost_pad_new("sink", pad);
3017 LOGE("failed to create ghostpad");
3021 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3022 LOGE("failed to add ghostpad to audiobin");
3026 gst_object_unref(pad);
3028 g_list_free(element_bucket);
3031 return MM_ERROR_NONE;
3034 LOGD("ERROR : releasing audiobin");
3037 gst_object_unref(GST_OBJECT(pad));
3040 gst_object_unref(GST_OBJECT(ghostpad));
3043 g_list_free(element_bucket);
3045 /* release element which are not added to bin */
3046 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3047 /* NOTE : skip bin */
3048 if (audiobin[i].gst) {
3049 GstObject *parent = NULL;
3050 parent = gst_element_get_parent(audiobin[i].gst);
3053 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3054 audiobin[i].gst = NULL;
3056 gst_object_unref(GST_OBJECT(parent));
3060 /* release audiobin with it's childs */
3061 if (audiobin[MMPLAYER_A_BIN].gst)
3062 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3064 MMPLAYER_FREEIF(audiobin);
3066 player->pipeline->audiobin = NULL;
3068 return MM_ERROR_PLAYER_INTERNAL;
3072 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3074 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3078 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3080 int ret = MM_ERROR_NONE;
3082 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3083 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3085 MMPLAYER_VIDEO_BO_LOCK(player);
3087 if (player->video_bo_list) {
3088 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3089 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3090 if (tmp && tmp->bo == bo) {
3092 LOGD("release bo %p", bo);
3093 tbm_bo_unref(tmp->bo);
3094 MMPLAYER_VIDEO_BO_UNLOCK(player);
3095 MMPLAYER_VIDEO_BO_SIGNAL(player);
3100 /* hw codec is running or the list was reset for DRC. */
3101 LOGW("there is no bo list.");
3103 MMPLAYER_VIDEO_BO_UNLOCK(player);
3105 LOGW("failed to find bo %p", bo);
3110 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3115 MMPLAYER_RETURN_IF_FAIL(player);
3117 MMPLAYER_VIDEO_BO_LOCK(player);
3118 if (player->video_bo_list) {
3119 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3120 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3121 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3124 tbm_bo_unref(tmp->bo);
3128 g_list_free(player->video_bo_list);
3129 player->video_bo_list = NULL;
3131 player->video_bo_size = 0;
3132 MMPLAYER_VIDEO_BO_UNLOCK(player);
3139 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3142 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3143 gboolean ret = TRUE;
3145 /* check DRC, if it is, destroy the prev bo list to create again */
3146 if (player->video_bo_size != size) {
3147 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3148 __mmplayer_video_stream_destroy_bo_list(player);
3149 player->video_bo_size = size;
3152 MMPLAYER_VIDEO_BO_LOCK(player);
3154 if ((!player->video_bo_list) ||
3155 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3157 /* create bo list */
3159 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3161 if (player->video_bo_list) {
3162 /* if bo list did not created all, try it again. */
3163 idx = g_list_length(player->video_bo_list);
3164 LOGD("bo list exist(len: %d)", idx);
3167 for (; idx < player->ini.num_of_video_bo; idx++) {
3168 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3170 LOGE("Fail to alloc bo_info.");
3173 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3175 LOGE("Fail to tbm_bo_alloc.");
3176 MMPLAYER_FREEIF(bo_info);
3179 bo_info->used = FALSE;
3180 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3183 /* update video num buffers */
3184 LOGD("video_num_buffers : %d", idx);
3185 mm_player_set_attribute((MMHandleType)player, NULL,
3186 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3187 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3191 MMPLAYER_VIDEO_BO_UNLOCK(player);
3197 /* get bo from list*/
3198 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3199 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3200 if (tmp && (tmp->used == FALSE)) {
3201 LOGD("found bo %p to use", tmp->bo);
3203 MMPLAYER_VIDEO_BO_UNLOCK(player);
3204 return tbm_bo_ref(tmp->bo);
3208 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3209 MMPLAYER_VIDEO_BO_UNLOCK(player);
3213 if (player->ini.video_bo_timeout <= 0) {
3214 MMPLAYER_VIDEO_BO_WAIT(player);
3216 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3217 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3224 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3226 mmplayer_t *player = (mmplayer_t *)data;
3228 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3230 /* send prerolled pkt */
3231 player->video_stream_prerolled = false;
3233 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3235 /* not to send prerolled pkt again */
3236 player->video_stream_prerolled = true;
3240 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3242 mmplayer_t *player = (mmplayer_t *)data;
3243 mmplayer_video_decoded_data_info_t *stream = NULL;
3244 GstMemory *mem = NULL;
3247 MMPLAYER_RETURN_IF_FAIL(player);
3248 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3250 if (player->video_stream_prerolled) {
3251 player->video_stream_prerolled = false;
3252 LOGD("skip the prerolled pkt not to send it again");
3256 /* clear stream data structure */
3257 stream = __mmplayer_create_stream_from_pad(pad);
3259 LOGE("failed to alloc stream");
3263 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3265 /* set size and timestamp */
3266 mem = gst_buffer_peek_memory(buffer, 0);
3267 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3268 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3270 /* check zero-copy */
3271 if (player->set_mode.video_zc &&
3272 player->set_mode.video_export &&
3273 gst_is_tizen_memory(mem)) {
3274 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3275 stream->internal_buffer = gst_buffer_ref(buffer);
3276 } else { /* sw codec */
3277 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3280 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3284 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3285 LOGE("failed to send video decoded data.");
3292 LOGE("release video stream resource.");
3293 if (gst_is_tizen_memory(mem)) {
3295 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3297 tbm_bo_unref(stream->bo[i]);
3300 /* unref gst buffer */
3301 if (stream->internal_buffer)
3302 gst_buffer_unref(stream->internal_buffer);
3305 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3307 MMPLAYER_FREEIF(stream);
3312 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3314 mmplayer_gst_element_t *videobin = NULL;
3317 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3319 videobin = player->pipeline->videobin;
3321 /* Set spatial media metadata and/or user settings to the element.
3323 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3324 "projection-type", player->video360_metadata.projection_type, NULL);
3326 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3327 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3329 if (player->video360_metadata.full_pano_width_pixels &&
3330 player->video360_metadata.full_pano_height_pixels &&
3331 player->video360_metadata.cropped_area_image_width &&
3332 player->video360_metadata.cropped_area_image_height) {
3333 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3334 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3335 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3336 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3337 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3338 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3339 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3343 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3344 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3345 "horizontal-fov", player->video360_horizontal_fov,
3346 "vertical-fov", player->video360_vertical_fov, NULL);
3349 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3350 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3351 "zoom", 1.0f / player->video360_zoom, NULL);
3354 if (player->video360_yaw_radians <= M_PI &&
3355 player->video360_yaw_radians >= -M_PI &&
3356 player->video360_pitch_radians <= M_PI_2 &&
3357 player->video360_pitch_radians >= -M_PI_2) {
3358 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3359 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3360 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3361 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3362 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3363 "pose-yaw", player->video360_metadata.init_view_heading,
3364 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3367 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3368 "passthrough", !player->is_video360_enabled, NULL);
3375 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3377 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3378 GList *element_bucket = NULL;
3381 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3383 /* create video360 filter */
3384 if (player->is_360_feature_enabled && player->is_content_spherical) {
3385 LOGD("create video360 element");
3386 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3387 __mmplayer_gst_set_video360_property(player);
3391 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3392 LOGD("skip creating the videoconv and rotator");
3393 return MM_ERROR_NONE;
3396 /* in case of sw codec & overlay surface type, except 360 playback.
3397 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3398 LOGD("create video converter: %s", video_csc);
3399 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3402 *bucket = element_bucket;
3404 return MM_ERROR_NONE;
3406 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3407 g_list_free(element_bucket);
3411 return MM_ERROR_PLAYER_INTERNAL;
3415 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3417 gchar *factory_name = NULL;
3419 switch (surface_type) {
3420 case MM_DISPLAY_SURFACE_OVERLAY:
3421 if (strlen(player->ini.videosink_element_overlay) > 0)
3422 factory_name = player->ini.videosink_element_overlay;
3424 case MM_DISPLAY_SURFACE_REMOTE:
3425 case MM_DISPLAY_SURFACE_NULL:
3426 if (strlen(player->ini.videosink_element_fake) > 0)
3427 factory_name = player->ini.videosink_element_fake;
3430 LOGE("unidentified surface type");
3434 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3435 return factory_name;
3439 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3441 gchar *factory_name = NULL;
3442 mmplayer_gst_element_t *videobin = NULL;
3447 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3449 videobin = player->pipeline->videobin;
3450 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3452 attrs = MMPLAYER_GET_ATTRS(player);
3454 LOGE("cannot get content attribute");
3455 return MM_ERROR_PLAYER_INTERNAL;
3458 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3459 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3460 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3461 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3462 "use-tbm", use_tbm, NULL);
3465 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3466 return MM_ERROR_PLAYER_INTERNAL;
3468 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3471 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3472 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3475 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3477 LOGD("disable last-sample");
3478 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3481 if (player->set_mode.video_export) {
3483 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3484 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3485 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3487 _mmplayer_add_signal_connection(player,
3488 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3489 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3491 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3494 _mmplayer_add_signal_connection(player,
3495 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3496 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3498 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3502 if (videobin[MMPLAYER_V_SINK].gst) {
3503 GstPad *sink_pad = NULL;
3504 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3506 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3507 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3508 gst_object_unref(GST_OBJECT(sink_pad));
3510 LOGE("failed to get sink pad from videosink");
3514 return MM_ERROR_NONE;
3519 * - video overlay surface(arm/x86) : tizenwlsink
3522 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3525 GList *element_bucket = NULL;
3526 mmplayer_gst_element_t *first_element = NULL;
3527 mmplayer_gst_element_t *videobin = NULL;
3528 gchar *videosink_factory_name = NULL;
3531 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3534 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3536 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3538 player->pipeline->videobin = videobin;
3541 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3542 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3543 if (!videobin[MMPLAYER_V_BIN].gst) {
3544 LOGE("failed to create videobin");
3548 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3551 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3552 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3554 /* additional setting for sink plug-in */
3555 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3556 LOGE("failed to set video property");
3560 /* store it as it's sink element */
3561 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3563 /* adding created elements to bin */
3564 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3565 LOGE("failed to add elements");
3569 /* Linking elements in the bucket by added order */
3570 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3571 LOGE("failed to link elements");
3575 /* get first element's sinkpad for creating ghostpad */
3576 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3577 if (!first_element) {
3578 LOGE("failed to get first element from bucket");
3582 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3584 LOGE("failed to get pad from first element");
3588 /* create ghostpad */
3589 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3590 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3591 LOGE("failed to add ghostpad to videobin");
3594 gst_object_unref(pad);
3596 /* done. free allocated variables */
3597 g_list_free(element_bucket);
3601 return MM_ERROR_NONE;
3604 LOGE("ERROR : releasing videobin");
3605 g_list_free(element_bucket);
3608 gst_object_unref(GST_OBJECT(pad));
3610 /* release videobin with it's childs */
3611 if (videobin[MMPLAYER_V_BIN].gst)
3612 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3614 MMPLAYER_FREEIF(videobin);
3615 player->pipeline->videobin = NULL;
3617 return MM_ERROR_PLAYER_INTERNAL;
3621 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3623 GList *element_bucket = NULL;
3624 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3626 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3627 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3628 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3629 "signal-handoffs", FALSE,
3632 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3633 _mmplayer_add_signal_connection(player,
3634 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3635 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3637 G_CALLBACK(__mmplayer_update_subtitle),
3640 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3641 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3643 if (!player->play_subtitle) {
3644 LOGD("add textbin sink as sink element of whole pipeline.");
3645 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3648 /* adding created elements to bin */
3649 LOGD("adding created elements to bin");
3650 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3651 LOGE("failed to add elements");
3655 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3656 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3657 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3659 /* linking elements in the bucket by added order. */
3660 LOGD("Linking elements in the bucket by added order.");
3661 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3662 LOGE("failed to link elements");
3666 /* done. free allocated variables */
3667 g_list_free(element_bucket);
3669 if (textbin[MMPLAYER_T_QUEUE].gst) {
3671 GstPad *ghostpad = NULL;
3673 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3675 LOGE("failed to get sink pad of text queue");
3679 ghostpad = gst_ghost_pad_new("text_sink", pad);
3680 gst_object_unref(pad);
3683 LOGE("failed to create ghostpad of textbin");
3687 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3688 LOGE("failed to add ghostpad to textbin");
3689 gst_object_unref(ghostpad);
3694 return MM_ERROR_NONE;
3697 g_list_free(element_bucket);
3699 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3700 LOGE("remove textbin sink from sink list");
3701 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3704 /* release element at __mmplayer_gst_create_text_sink_bin */
3705 return MM_ERROR_PLAYER_INTERNAL;
3709 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3711 mmplayer_gst_element_t *textbin = NULL;
3712 GList *element_bucket = NULL;
3713 int surface_type = 0;
3718 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3721 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3723 LOGE("failed to allocate memory for textbin");
3724 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3728 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3729 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3730 if (!textbin[MMPLAYER_T_BIN].gst) {
3731 LOGE("failed to create textbin");
3736 player->pipeline->textbin = textbin;
3739 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3740 LOGD("surface type for subtitle : %d", surface_type);
3741 switch (surface_type) {
3742 case MM_DISPLAY_SURFACE_OVERLAY:
3743 case MM_DISPLAY_SURFACE_NULL:
3744 case MM_DISPLAY_SURFACE_REMOTE:
3745 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3746 LOGE("failed to make plain text elements");
3757 return MM_ERROR_NONE;
3761 LOGD("ERROR : releasing textbin");
3763 g_list_free(element_bucket);
3765 /* release signal */
3766 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3768 /* release element which are not added to bin */
3769 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3770 /* NOTE : skip bin */
3771 if (textbin[i].gst) {
3772 GstObject *parent = NULL;
3773 parent = gst_element_get_parent(textbin[i].gst);
3776 gst_object_unref(GST_OBJECT(textbin[i].gst));
3777 textbin[i].gst = NULL;
3779 gst_object_unref(GST_OBJECT(parent));
3784 /* release textbin with it's childs */
3785 if (textbin[MMPLAYER_T_BIN].gst)
3786 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3788 MMPLAYER_FREEIF(textbin);
3789 player->pipeline->textbin = NULL;
3792 return MM_ERROR_PLAYER_INTERNAL;
3796 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3798 mmplayer_gst_element_t *mainbin = NULL;
3799 mmplayer_gst_element_t *textbin = NULL;
3800 MMHandleType attrs = 0;
3801 GstElement *subsrc = NULL;
3802 GstElement *subparse = NULL;
3803 gchar *subtitle_uri = NULL;
3804 const gchar *charset = NULL;
3810 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3812 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3814 mainbin = player->pipeline->mainbin;
3816 attrs = MMPLAYER_GET_ATTRS(player);
3818 LOGE("cannot get content attribute");
3819 return MM_ERROR_PLAYER_INTERNAL;
3822 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3823 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3824 LOGE("subtitle uri is not proper filepath.");
3825 return MM_ERROR_PLAYER_INVALID_URI;
3828 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3829 LOGE("failed to get storage info of subtitle path");
3830 return MM_ERROR_PLAYER_INVALID_URI;
3833 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3835 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3836 player->subtitle_language_list = NULL;
3837 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3839 /* create the subtitle source */
3840 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3842 LOGE("failed to create filesrc element");
3845 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3847 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3848 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3850 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3851 LOGW("failed to add queue");
3852 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3853 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3854 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3859 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3861 LOGE("failed to create subparse element");
3865 charset = _mmplayer_get_charset(subtitle_uri);
3867 LOGD("detected charset is %s", charset);
3868 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3871 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3872 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3874 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3875 LOGW("failed to add subparse");
3876 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3877 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3878 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3882 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3883 LOGW("failed to link subsrc and subparse");
3887 player->play_subtitle = TRUE;
3888 player->adjust_subtitle_pos = 0;
3890 LOGD("play subtitle using subtitle file");
3892 if (player->pipeline->textbin == NULL) {
3893 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3894 LOGE("failed to create text sink bin. continuing without text");
3898 textbin = player->pipeline->textbin;
3900 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3901 LOGW("failed to add textbin");
3903 /* release signal */
3904 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3906 /* release textbin with it's childs */
3907 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3908 MMPLAYER_FREEIF(player->pipeline->textbin);
3909 player->pipeline->textbin = textbin = NULL;
3913 LOGD("link text input selector and textbin ghost pad");
3915 player->textsink_linked = 1;
3916 player->external_text_idx = 0;
3917 LOGI("textsink is linked");
3919 textbin = player->pipeline->textbin;
3920 LOGD("text bin has been created. reuse it.");
3921 player->external_text_idx = 1;
3924 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3925 LOGW("failed to link subparse and textbin");
3929 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3931 LOGE("failed to get sink pad from textsink to probe data");
3935 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3936 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3938 gst_object_unref(pad);
3941 /* create dot. for debugging */
3942 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3945 return MM_ERROR_NONE;
3948 /* release text pipeline resource */
3949 player->textsink_linked = 0;
3951 /* release signal */
3952 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3954 if (player->pipeline->textbin) {
3955 LOGE("remove textbin");
3957 /* release textbin with it's childs */
3958 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3959 MMPLAYER_FREEIF(player->pipeline->textbin);
3960 player->pipeline->textbin = NULL;
3964 /* release subtitle elem */
3965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3966 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3968 return MM_ERROR_PLAYER_INTERNAL;
3972 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3974 mmplayer_t *player = (mmplayer_t *)data;
3975 MMMessageParamType msg = {0, };
3976 GstClockTime duration = 0;
3977 gpointer text = NULL;
3978 guint text_size = 0;
3979 gboolean ret = TRUE;
3980 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3984 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3985 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3987 if (player->is_subtitle_force_drop) {
3988 LOGW("subtitle is dropped forcedly.");
3992 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3993 text = mapinfo.data;
3994 text_size = mapinfo.size;
3996 if (player->set_mode.subtitle_off) {
3997 LOGD("subtitle is OFF.");
4001 if (!text || (text_size == 0)) {
4002 LOGD("There is no subtitle to be displayed.");
4006 msg.data = (void *)text;
4008 duration = GST_BUFFER_DURATION(buffer);
4010 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4011 if (player->duration > GST_BUFFER_PTS(buffer))
4012 duration = player->duration - GST_BUFFER_PTS(buffer);
4015 LOGI("subtitle duration is invalid, subtitle duration change "
4016 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4018 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4020 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4022 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4023 gst_buffer_unmap(buffer, &mapinfo);
4030 static GstPadProbeReturn
4031 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4033 mmplayer_t *player = (mmplayer_t *)u_data;
4034 GstClockTime cur_timestamp = 0;
4035 gint64 adjusted_timestamp = 0;
4036 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4038 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4040 if (player->set_mode.subtitle_off) {
4041 LOGD("subtitle is OFF.");
4045 if (player->adjust_subtitle_pos == 0) {
4046 LOGD("nothing to do");
4050 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4051 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4053 if (adjusted_timestamp < 0) {
4054 LOGD("adjusted_timestamp under zero");
4059 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4060 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4061 GST_TIME_ARGS(cur_timestamp),
4062 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4064 return GST_PAD_PROBE_OK;
4068 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4072 /* check player and subtitlebin are created */
4073 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4074 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4076 if (position == 0) {
4077 LOGD("nothing to do");
4079 return MM_ERROR_NONE;
4082 /* check current postion */
4083 player->adjust_subtitle_pos = position;
4085 LOGD("save adjust_subtitle_pos in player");
4089 return MM_ERROR_NONE;
4093 * This function is to create audio or video pipeline for playing.
4095 * @param player [in] handle of player
4097 * @return This function returns zero on success.
4102 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4104 int ret = MM_ERROR_NONE;
4105 mmplayer_gst_element_t *mainbin = NULL;
4106 MMHandleType attrs = 0;
4109 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4111 /* get profile attribute */
4112 attrs = MMPLAYER_GET_ATTRS(player);
4114 LOGE("failed to get content attribute");
4118 /* create pipeline handles */
4119 if (player->pipeline) {
4120 LOGE("pipeline should be released before create new one");
4124 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4126 /* create mainbin */
4127 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4128 if (mainbin == NULL)
4131 /* create pipeline */
4132 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4133 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4134 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4135 LOGE("failed to create pipeline");
4140 player->pipeline->mainbin = mainbin;
4142 /* create the source and decoder elements */
4143 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4144 ret = _mmplayer_gst_build_es_pipeline(player);
4146 ret = _mmplayer_gst_build_pipeline(player);
4148 if (ret != MM_ERROR_NONE) {
4149 LOGE("failed to create some elements");
4153 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4154 if (__mmplayer_check_subtitle(player)
4155 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4156 LOGE("failed to create text pipeline");
4159 ret = _mmplayer_gst_add_bus_watch(player);
4160 if (ret != MM_ERROR_NONE) {
4161 LOGE("failed to add bus watch");
4166 return MM_ERROR_NONE;
4169 __mmplayer_gst_destroy_pipeline(player);
4170 return MM_ERROR_PLAYER_INTERNAL;
4174 __mmplayer_reset_gapless_state(mmplayer_t *player)
4177 MMPLAYER_RETURN_IF_FAIL(player
4179 && player->pipeline->audiobin
4180 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4182 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4189 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4192 int ret = MM_ERROR_NONE;
4196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4198 /* cleanup stuffs */
4199 MMPLAYER_FREEIF(player->type);
4200 player->no_more_pad = FALSE;
4201 player->num_dynamic_pad = 0;
4202 player->demux_pad_index = 0;
4204 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4205 player->subtitle_language_list = NULL;
4206 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4208 MMPLAYER_RECONFIGURE_LOCK(player);
4209 __mmplayer_reset_gapless_state(player);
4210 MMPLAYER_RECONFIGURE_UNLOCK(player);
4212 if (player->streamer) {
4213 _mm_player_streaming_initialize(player->streamer, FALSE);
4214 _mm_player_streaming_destroy(player->streamer);
4215 player->streamer = NULL;
4218 /* cleanup unlinked mime type */
4219 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4220 MMPLAYER_FREEIF(player->unlinked_video_mime);
4221 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4223 /* cleanup running stuffs */
4224 _mmplayer_cancel_eos_timer(player);
4226 /* cleanup gst stuffs */
4227 if (player->pipeline) {
4228 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4229 GstTagList *tag_list = player->pipeline->tag_list;
4231 /* first we need to disconnect all signal hander */
4232 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4235 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4236 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4237 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4238 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4239 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4240 gst_object_unref(bus);
4242 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4243 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4244 if (ret != MM_ERROR_NONE) {
4245 LOGE("fail to change state to NULL");
4246 return MM_ERROR_PLAYER_INTERNAL;
4249 LOGW("succeeded in changing state to NULL");
4251 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4254 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4255 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4257 /* free avsysaudiosink
4258 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4259 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4261 MMPLAYER_FREEIF(audiobin);
4262 MMPLAYER_FREEIF(videobin);
4263 MMPLAYER_FREEIF(textbin);
4264 MMPLAYER_FREEIF(mainbin);
4268 gst_tag_list_unref(tag_list);
4270 MMPLAYER_FREEIF(player->pipeline);
4272 MMPLAYER_FREEIF(player->album_art);
4274 if (player->v_stream_caps) {
4275 gst_caps_unref(player->v_stream_caps);
4276 player->v_stream_caps = NULL;
4279 if (player->a_stream_caps) {
4280 gst_caps_unref(player->a_stream_caps);
4281 player->a_stream_caps = NULL;
4284 if (player->s_stream_caps) {
4285 gst_caps_unref(player->s_stream_caps);
4286 player->s_stream_caps = NULL;
4288 _mmplayer_track_destroy(player);
4290 if (player->sink_elements)
4291 g_list_free(player->sink_elements);
4292 player->sink_elements = NULL;
4294 if (player->bufmgr) {
4295 tbm_bufmgr_deinit(player->bufmgr);
4296 player->bufmgr = NULL;
4299 LOGW("finished destroy pipeline");
4307 __mmplayer_gst_realize(mmplayer_t *player)
4310 int ret = MM_ERROR_NONE;
4314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4316 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4318 ret = __mmplayer_gst_create_pipeline(player);
4320 LOGE("failed to create pipeline");
4324 /* set pipeline state to READY */
4325 /* NOTE : state change to READY must be performed sync. */
4326 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4327 ret = _mmplayer_gst_set_state(player,
4328 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4330 if (ret != MM_ERROR_NONE) {
4331 /* return error if failed to set state */
4332 LOGE("failed to set READY state");
4336 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4338 /* create dot before error-return. for debugging */
4339 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4347 __mmplayer_gst_unrealize(mmplayer_t *player)
4349 int ret = MM_ERROR_NONE;
4353 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4355 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4356 MMPLAYER_PRINT_STATE(player);
4358 /* release miscellaneous information */
4359 __mmplayer_release_misc(player);
4361 /* destroy pipeline */
4362 ret = __mmplayer_gst_destroy_pipeline(player);
4363 if (ret != MM_ERROR_NONE) {
4364 LOGE("failed to destory pipeline");
4368 /* release miscellaneous information.
4369 these info needs to be released after pipeline is destroyed. */
4370 __mmplayer_release_misc_post(player);
4372 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4380 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4385 LOGW("set_message_callback is called with invalid player handle");
4386 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4389 player->msg_cb = callback;
4390 player->msg_cb_param = user_param;
4392 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4396 return MM_ERROR_NONE;
4400 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4402 int ret = MM_ERROR_NONE;
4407 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4408 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4409 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4411 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4413 if (strstr(uri, "es_buff://")) {
4414 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4415 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4416 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4417 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4419 tmp = g_ascii_strdown(uri, strlen(uri));
4420 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4421 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4423 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4425 } else if (strstr(uri, "mms://")) {
4426 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4427 } else if ((path = strstr(uri, "mem://"))) {
4428 ret = __mmplayer_set_mem_uri(data, path, param);
4430 ret = __mmplayer_set_file_uri(data, uri);
4433 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4434 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4435 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4436 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4438 /* dump parse result */
4439 SECURE_LOGW("incoming uri : %s", uri);
4440 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4441 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4449 __mmplayer_can_do_interrupt(mmplayer_t *player)
4451 if (!player || !player->pipeline || !player->attrs) {
4452 LOGW("not initialized");
4456 if (player->audio_decoded_cb) {
4457 LOGW("not support in pcm extraction mode");
4461 /* check if seeking */
4462 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4463 MMMessageParamType msg_param;
4464 memset(&msg_param, 0, sizeof(MMMessageParamType));
4465 msg_param.code = MM_ERROR_PLAYER_SEEK;
4466 player->seek_state = MMPLAYER_SEEK_NONE;
4467 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4471 /* check other thread */
4472 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4473 LOGW("locked already, cmd state : %d", player->cmd);
4475 /* check application command */
4476 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4477 LOGW("playing.. should wait cmd lock then, will be interrupted");
4479 /* lock will be released at mrp_resource_release_cb() */
4480 MMPLAYER_CMD_LOCK(player);
4483 LOGW("nothing to do");
4486 LOGW("can interrupt immediately");
4490 FAILED: /* with CMD UNLOCKED */
4493 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4498 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4501 mmplayer_t *player = NULL;
4502 MMMessageParamType msg = {0, };
4504 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4509 LOGE("user_data is null");
4512 player = (mmplayer_t *)user_data;
4514 if (!__mmplayer_can_do_interrupt(player)) {
4515 LOGW("no need to interrupt, so leave");
4516 /* FIXME: there is no way to avoid releasing resource. */
4520 player->interrupted_by_resource = TRUE;
4522 /* get last play position */
4523 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4524 msg.union_type = MM_MSG_UNION_TIME;
4525 msg.time.elapsed = pos;
4526 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4528 LOGW("failed to get play position.");
4531 LOGD("video resource conflict so, resource will be freed by unrealizing");
4532 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4533 LOGE("failed to unrealize");
4535 /* lock is called in __mmplayer_can_do_interrupt() */
4536 MMPLAYER_CMD_UNLOCK(player);
4538 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4539 player->hw_resource[res_idx] = NULL;
4543 return TRUE; /* release all the resources */
4547 __mmplayer_initialize_video_roi(mmplayer_t *player)
4549 player->video_roi.scale_x = 0.0;
4550 player->video_roi.scale_y = 0.0;
4551 player->video_roi.scale_width = 1.0;
4552 player->video_roi.scale_height = 1.0;
4556 _mmplayer_create_player(MMHandleType handle)
4558 int ret = MM_ERROR_PLAYER_INTERNAL;
4559 bool enabled = false;
4561 mmplayer_t *player = MM_PLAYER_CAST(handle);
4565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4567 /* initialize player state */
4568 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4569 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4570 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4571 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4573 /* check current state */
4574 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4576 /* construct attributes */
4577 player->attrs = _mmplayer_construct_attribute(handle);
4579 if (!player->attrs) {
4580 LOGE("Failed to construct attributes");
4584 /* initialize gstreamer with configured parameter */
4585 if (!__mmplayer_init_gstreamer(player)) {
4586 LOGE("Initializing gstreamer failed");
4587 _mmplayer_deconstruct_attribute(handle);
4591 /* create lock. note that g_tread_init() has already called in gst_init() */
4592 g_mutex_init(&player->fsink_lock);
4594 /* create update tag lock */
4595 g_mutex_init(&player->update_tag_lock);
4597 /* create gapless play mutex */
4598 g_mutex_init(&player->gapless_play_thread_mutex);
4600 /* create gapless play cond */
4601 g_cond_init(&player->gapless_play_thread_cond);
4603 /* create gapless play thread */
4604 player->gapless_play_thread =
4605 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4606 if (!player->gapless_play_thread) {
4607 LOGE("failed to create gapless play thread");
4608 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4609 g_mutex_clear(&player->gapless_play_thread_mutex);
4610 g_cond_clear(&player->gapless_play_thread_cond);
4614 player->bus_msg_q = g_queue_new();
4615 if (!player->bus_msg_q) {
4616 LOGE("failed to create queue for bus_msg");
4617 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4621 ret = _mmplayer_initialize_video_capture(player);
4622 if (ret != MM_ERROR_NONE) {
4623 LOGE("failed to initialize video capture");
4627 /* initialize resource manager */
4628 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4629 __resource_release_cb, player, &player->resource_manager)
4630 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4631 LOGE("failed to initialize resource manager");
4632 ret = MM_ERROR_PLAYER_INTERNAL;
4636 /* create video bo lock and cond */
4637 g_mutex_init(&player->video_bo_mutex);
4638 g_cond_init(&player->video_bo_cond);
4640 /* create subtitle info lock and cond */
4641 g_mutex_init(&player->subtitle_info_mutex);
4642 g_cond_init(&player->subtitle_info_cond);
4644 player->streaming_type = STREAMING_SERVICE_NONE;
4646 /* give default value of audio effect setting */
4647 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4648 player->sound.rg_enable = false;
4649 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4651 player->play_subtitle = FALSE;
4652 player->has_closed_caption = FALSE;
4653 player->pending_resume = FALSE;
4654 if (player->ini.dump_element_keyword[0][0] == '\0')
4655 player->ini.set_dump_element_flag = FALSE;
4657 player->ini.set_dump_element_flag = TRUE;
4659 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4660 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4661 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4663 /* Set video360 settings to their defaults for just-created player.
4666 player->is_360_feature_enabled = FALSE;
4667 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4668 LOGI("spherical feature info: %d", enabled);
4670 player->is_360_feature_enabled = TRUE;
4672 LOGE("failed to get spherical feature info");
4675 player->is_content_spherical = FALSE;
4676 player->is_video360_enabled = TRUE;
4677 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4678 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4679 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4680 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4681 player->video360_zoom = 1.0f;
4682 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4683 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4685 __mmplayer_initialize_video_roi(player);
4687 /* set player state to null */
4688 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4689 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4693 return MM_ERROR_NONE;
4697 g_mutex_clear(&player->fsink_lock);
4698 /* free update tag lock */
4699 g_mutex_clear(&player->update_tag_lock);
4700 g_queue_free(player->bus_msg_q);
4701 player->bus_msg_q = NULL;
4702 /* free gapless play thread */
4703 if (player->gapless_play_thread) {
4704 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4705 player->gapless_play_thread_exit = TRUE;
4706 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4707 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4709 g_thread_join(player->gapless_play_thread);
4710 player->gapless_play_thread = NULL;
4712 g_mutex_clear(&player->gapless_play_thread_mutex);
4713 g_cond_clear(&player->gapless_play_thread_cond);
4716 /* release attributes */
4717 _mmplayer_deconstruct_attribute(handle);
4725 __mmplayer_init_gstreamer(mmplayer_t *player)
4727 static gboolean initialized = FALSE;
4728 static const int max_argc = 50;
4730 gchar **argv = NULL;
4731 gchar **argv2 = NULL;
4737 LOGD("gstreamer already initialized.");
4742 argc = malloc(sizeof(int));
4743 argv = malloc(sizeof(gchar *) * max_argc);
4744 argv2 = malloc(sizeof(gchar *) * max_argc);
4746 if (!argc || !argv || !argv2)
4749 memset(argv, 0, sizeof(gchar *) * max_argc);
4750 memset(argv2, 0, sizeof(gchar *) * max_argc);
4754 argv[0] = g_strdup("mmplayer");
4757 for (i = 0; i < 5; i++) {
4758 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4759 if (strlen(player->ini.gst_param[i]) > 0) {
4760 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4765 /* we would not do fork for scanning plugins */
4766 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4769 /* check disable registry scan */
4770 if (player->ini.skip_rescan) {
4771 argv[*argc] = g_strdup("--gst-disable-registry-update");
4775 /* check disable segtrap */
4776 if (player->ini.disable_segtrap) {
4777 argv[*argc] = g_strdup("--gst-disable-segtrap");
4781 LOGD("initializing gstreamer with following parameter");
4782 LOGD("argc : %d", *argc);
4785 for (i = 0; i < arg_count; i++) {
4787 LOGD("argv[%d] : %s", i, argv2[i]);
4790 /* initializing gstreamer */
4791 if (!gst_init_check(argc, &argv, &err)) {
4792 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4799 for (i = 0; i < arg_count; i++) {
4801 LOGD("release - argv[%d] : %s", i, argv2[i]);
4803 MMPLAYER_FREEIF(argv2[i]);
4806 MMPLAYER_FREEIF(argv);
4807 MMPLAYER_FREEIF(argv2);
4808 MMPLAYER_FREEIF(argc);
4818 for (i = 0; i < arg_count; i++) {
4819 LOGD("free[%d] : %s", i, argv2[i]);
4820 MMPLAYER_FREEIF(argv2[i]);
4823 MMPLAYER_FREEIF(argv);
4824 MMPLAYER_FREEIF(argv2);
4825 MMPLAYER_FREEIF(argc);
4831 __mmplayer_check_async_state_transition(mmplayer_t *player)
4833 GstState element_state = GST_STATE_VOID_PENDING;
4834 GstState element_pending_state = GST_STATE_VOID_PENDING;
4835 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4836 GstElement *element = NULL;
4837 gboolean async = FALSE;
4839 /* check player handle */
4840 MMPLAYER_RETURN_IF_FAIL(player &&
4842 player->pipeline->mainbin &&
4843 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4846 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4848 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4849 LOGD("don't need to check the pipeline state");
4853 MMPLAYER_PRINT_STATE(player);
4855 /* wait for state transition */
4856 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4857 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4859 if (ret == GST_STATE_CHANGE_FAILURE) {
4860 LOGE(" [%s] state : %s pending : %s",
4861 GST_ELEMENT_NAME(element),
4862 gst_element_state_get_name(element_state),
4863 gst_element_state_get_name(element_pending_state));
4865 /* dump state of all element */
4866 _mmplayer_dump_pipeline_state(player);
4871 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4876 _mmplayer_destroy(MMHandleType handle)
4878 mmplayer_t *player = MM_PLAYER_CAST(handle);
4882 /* check player handle */
4883 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4885 /* destroy can called at anytime */
4886 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4888 /* check async state transition */
4889 __mmplayer_check_async_state_transition(player);
4891 /* release gapless play thread */
4892 if (player->gapless_play_thread) {
4893 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4894 player->gapless_play_thread_exit = TRUE;
4895 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4896 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4898 LOGD("waitting for gapless play thread exit");
4899 g_thread_join(player->gapless_play_thread);
4900 g_mutex_clear(&player->gapless_play_thread_mutex);
4901 g_cond_clear(&player->gapless_play_thread_cond);
4902 LOGD("gapless play thread released");
4905 _mmplayer_release_video_capture(player);
4907 /* de-initialize resource manager */
4908 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4909 player->resource_manager))
4910 LOGE("failed to deinitialize resource manager");
4912 /* release miscellaneous information */
4913 __mmplayer_release_misc(player);
4915 /* release pipeline */
4916 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4917 LOGE("failed to destory pipeline");
4918 return MM_ERROR_PLAYER_INTERNAL;
4921 g_queue_free(player->bus_msg_q);
4923 /* release subtitle info lock and cond */
4924 g_mutex_clear(&player->subtitle_info_mutex);
4925 g_cond_clear(&player->subtitle_info_cond);
4927 __mmplayer_release_dump_list(player->dump_list);
4929 /* release miscellaneous information.
4930 these info needs to be released after pipeline is destroyed. */
4931 __mmplayer_release_misc_post(player);
4933 /* release attributes */
4934 _mmplayer_deconstruct_attribute(handle);
4936 if (player->uri_info.uri_list) {
4937 GList *uri_list = player->uri_info.uri_list;
4938 for (; uri_list; uri_list = g_list_next(uri_list)) {
4939 gchar *uri = uri_list->data;
4940 MMPLAYER_FREEIF(uri);
4942 g_list_free(player->uri_info.uri_list);
4943 player->uri_info.uri_list = NULL;
4947 g_mutex_clear(&player->fsink_lock);
4950 g_mutex_clear(&player->update_tag_lock);
4952 /* release video bo lock and cond */
4953 g_mutex_clear(&player->video_bo_mutex);
4954 g_cond_clear(&player->video_bo_cond);
4958 return MM_ERROR_NONE;
4962 _mmplayer_realize(MMHandleType hplayer)
4964 mmplayer_t *player = (mmplayer_t *)hplayer;
4965 int ret = MM_ERROR_NONE;
4968 MMHandleType attrs = 0;
4969 int video_codec_type = 0;
4970 int audio_codec_type = 0;
4971 int default_codec_type = 0;
4974 /* check player handle */
4975 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4977 /* check current state */
4978 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4980 attrs = MMPLAYER_GET_ATTRS(player);
4982 LOGE("fail to get attributes.");
4983 return MM_ERROR_PLAYER_INTERNAL;
4985 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4986 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4988 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4989 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4991 if (ret != MM_ERROR_NONE) {
4992 LOGE("failed to parse profile");
4997 if (uri && (strstr(uri, "es_buff://"))) {
4998 if (strstr(uri, "es_buff://push_mode"))
4999 player->es_player_push_mode = TRUE;
5001 player->es_player_push_mode = FALSE;
5004 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5005 LOGW("mms protocol is not supported format.");
5006 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5009 if (MMPLAYER_IS_STREAMING(player))
5010 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5012 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5014 player->smooth_streaming = FALSE;
5015 player->videodec_linked = 0;
5016 player->audiodec_linked = 0;
5017 player->textsink_linked = 0;
5018 player->is_external_subtitle_present = FALSE;
5019 player->is_external_subtitle_added_now = FALSE;
5020 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5021 player->video360_metadata.is_spherical = -1;
5022 player->is_openal_plugin_used = FALSE;
5023 player->demux_pad_index = 0;
5024 player->subtitle_language_list = NULL;
5025 player->is_subtitle_force_drop = FALSE;
5027 _mmplayer_track_initialize(player);
5028 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5030 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5031 gint prebuffer_ms = 0, rebuffer_ms = 0;
5033 player->streamer = _mm_player_streaming_create();
5034 _mm_player_streaming_initialize(player->streamer, TRUE);
5036 mm_attrs_multiple_get(player->attrs, NULL,
5037 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5038 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5040 if (prebuffer_ms > 0) {
5041 prebuffer_ms = MAX(prebuffer_ms, 1000);
5042 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5045 if (rebuffer_ms > 0) {
5046 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5047 rebuffer_ms = MAX(rebuffer_ms, 1000);
5048 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5051 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5052 player->streamer->buffering_req.rebuffer_time);
5055 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5056 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5057 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5059 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5061 if (audio_codec_type != default_codec_type) {
5062 LOGD("audio dec sorting is required");
5063 player->need_audio_dec_sorting = TRUE;
5066 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5067 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5068 LOGD("video dec sorting is required");
5069 player->need_video_dec_sorting = TRUE;
5072 /* realize pipeline */
5073 ret = __mmplayer_gst_realize(player);
5074 if (ret != MM_ERROR_NONE)
5075 LOGE("fail to realize the player.");
5077 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5085 _mmplayer_unrealize(MMHandleType hplayer)
5087 mmplayer_t *player = (mmplayer_t *)hplayer;
5088 int ret = MM_ERROR_NONE;
5092 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5094 MMPLAYER_CMD_UNLOCK(player);
5095 /* destroy the gst bus msg thread which is created during realize.
5096 this funct have to be called before getting cmd lock. */
5097 _mmplayer_bus_msg_thread_destroy(player);
5098 MMPLAYER_CMD_LOCK(player);
5100 /* check current state */
5101 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5103 /* check async state transition */
5104 __mmplayer_check_async_state_transition(player);
5106 /* unrealize pipeline */
5107 ret = __mmplayer_gst_unrealize(player);
5109 if (!player->interrupted_by_resource) {
5110 int rm_ret = MM_ERROR_NONE;
5111 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5113 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5114 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5115 if (rm_ret != MM_ERROR_NONE)
5116 LOGE("failed to release [%d] resources", res_idx);
5125 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5127 mmplayer_t *player = (mmplayer_t *)hplayer;
5129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5131 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5135 _mmplayer_get_state(MMHandleType hplayer, int *state)
5137 mmplayer_t *player = (mmplayer_t *)hplayer;
5139 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5141 *state = MMPLAYER_CURRENT_STATE(player);
5143 return MM_ERROR_NONE;
5147 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5149 GstElement *vol_element = NULL;
5150 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5153 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5154 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5156 /* check pipeline handle */
5157 if (!player->pipeline || !player->pipeline->audiobin) {
5158 LOGD("'%s' will be applied when audiobin is created", prop_name);
5160 /* NOTE : stored value will be used in create_audiobin
5161 * returning MM_ERROR_NONE here makes application to able to
5162 * set audio volume or mute at anytime.
5164 return MM_ERROR_NONE;
5167 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5168 volume_elem_id = MMPLAYER_A_SINK;
5170 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5172 LOGE("failed to get vol element %d", volume_elem_id);
5173 return MM_ERROR_PLAYER_INTERNAL;
5176 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5178 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5179 LOGE("there is no '%s' property", prop_name);
5180 return MM_ERROR_PLAYER_INTERNAL;
5183 if (!strcmp(prop_name, "volume")) {
5184 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5185 } else if (!strcmp(prop_name, "mute")) {
5186 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5188 LOGE("invalid property %s", prop_name);
5189 return MM_ERROR_PLAYER_INTERNAL;
5192 return MM_ERROR_NONE;
5196 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5198 int ret = MM_ERROR_NONE;
5199 mmplayer_t *player = (mmplayer_t *)hplayer;
5202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5204 LOGD("volume = %f", volume);
5206 /* invalid factor range or not */
5207 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5208 LOGE("Invalid volume value");
5209 return MM_ERROR_INVALID_ARGUMENT;
5212 player->sound.volume = volume;
5214 ret = __mmplayer_gst_set_volume_property(player, "volume");
5221 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5223 mmplayer_t *player = (mmplayer_t *)hplayer;
5227 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5228 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5230 *volume = player->sound.volume;
5232 LOGD("current vol = %f", *volume);
5235 return MM_ERROR_NONE;
5239 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5241 int ret = MM_ERROR_NONE;
5242 mmplayer_t *player = (mmplayer_t *)hplayer;
5245 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5247 LOGD("mute = %d", mute);
5249 player->sound.mute = mute;
5251 ret = __mmplayer_gst_set_volume_property(player, "mute");
5258 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5260 mmplayer_t *player = (mmplayer_t *)hplayer;
5264 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5265 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5267 *mute = player->sound.mute;
5269 LOGD("current mute = %d", *mute);
5273 return MM_ERROR_NONE;
5277 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5279 mmplayer_t *player = (mmplayer_t *)hplayer;
5283 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5285 player->audio_stream_changed_cb = callback;
5286 player->audio_stream_changed_cb_user_param = user_param;
5287 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5291 return MM_ERROR_NONE;
5295 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5297 mmplayer_t *player = (mmplayer_t *)hplayer;
5301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5303 player->audio_decoded_cb = callback;
5304 player->audio_decoded_cb_user_param = user_param;
5305 player->audio_extract_opt = opt;
5306 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5310 return MM_ERROR_NONE;
5314 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5316 mmplayer_t *player = (mmplayer_t *)hplayer;
5320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5322 if (callback && !player->bufmgr)
5323 player->bufmgr = tbm_bufmgr_init(-1);
5325 player->set_mode.video_export = (callback) ? true : false;
5326 player->video_decoded_cb = callback;
5327 player->video_decoded_cb_user_param = user_param;
5329 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5333 return MM_ERROR_NONE;
5337 _mmplayer_start(MMHandleType hplayer)
5339 mmplayer_t *player = (mmplayer_t *)hplayer;
5340 gint ret = MM_ERROR_NONE;
5344 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346 /* check current state */
5347 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5349 /* start pipeline */
5350 ret = _mmplayer_gst_start(player);
5351 if (ret != MM_ERROR_NONE)
5352 LOGE("failed to start player.");
5354 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5355 LOGD("force playing start even during buffering");
5356 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5364 /* NOTE: post "not supported codec message" to application
5365 * when one codec is not found during AUTOPLUGGING in MSL.
5366 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5367 * And, if any codec is not found, don't send message here.
5368 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5371 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5373 MMMessageParamType msg_param;
5374 memset(&msg_param, 0, sizeof(MMMessageParamType));
5375 gboolean post_msg_direct = FALSE;
5379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5381 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5382 player->not_supported_codec, player->can_support_codec);
5384 if (player->not_found_demuxer) {
5385 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5386 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5388 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5389 MMPLAYER_FREEIF(msg_param.data);
5391 return MM_ERROR_NONE;
5394 if (player->not_supported_codec) {
5395 if (player->can_support_codec) {
5396 // There is one codec to play
5397 post_msg_direct = TRUE;
5399 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5400 post_msg_direct = TRUE;
5403 if (post_msg_direct) {
5404 MMMessageParamType msg_param;
5405 memset(&msg_param, 0, sizeof(MMMessageParamType));
5407 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5408 LOGW("not found AUDIO codec, posting error code to application.");
5410 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5411 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5412 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5413 LOGW("not found VIDEO codec, posting error code to application.");
5415 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5416 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5419 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5421 MMPLAYER_FREEIF(msg_param.data);
5423 return MM_ERROR_NONE;
5425 // no any supported codec case
5426 LOGW("not found any codec, posting error code to application.");
5428 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5429 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5430 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5432 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5433 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5436 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5438 MMPLAYER_FREEIF(msg_param.data);
5444 return MM_ERROR_NONE;
5447 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5449 GstState element_state = GST_STATE_VOID_PENDING;
5450 GstState element_pending_state = GST_STATE_VOID_PENDING;
5451 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5452 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5454 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5456 MMPLAYER_RECONFIGURE_LOCK(player);
5457 if (!player->gapless.reconfigure) {
5458 MMPLAYER_RECONFIGURE_UNLOCK(player);
5462 LOGI("reconfigure is under process");
5463 MMPLAYER_RECONFIGURE_WAIT(player);
5464 MMPLAYER_RECONFIGURE_UNLOCK(player);
5465 LOGI("reconfigure is completed.");
5467 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5468 &element_state, &element_pending_state, timeout * GST_SECOND);
5469 if (result == GST_STATE_CHANGE_FAILURE)
5470 LOGW("failed to get pipeline state in %d sec", timeout);
5475 /* NOTE : it should be able to call 'stop' anytime*/
5477 _mmplayer_stop(MMHandleType hplayer)
5479 mmplayer_t *player = (mmplayer_t *)hplayer;
5480 int ret = MM_ERROR_NONE;
5484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5486 /* check current state */
5487 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5489 /* need to wait till the rebuilding pipeline is completed */
5490 __mmplayer_check_pipeline_reconfigure_state(player);
5491 MMPLAYER_RECONFIGURE_LOCK(player);
5492 __mmplayer_reset_gapless_state(player);
5493 MMPLAYER_RECONFIGURE_UNLOCK(player);
5495 /* NOTE : application should not wait for EOS after calling STOP */
5496 _mmplayer_cancel_eos_timer(player);
5499 player->seek_state = MMPLAYER_SEEK_NONE;
5502 ret = _mmplayer_gst_stop(player);
5504 if (ret != MM_ERROR_NONE)
5505 LOGE("failed to stop player.");
5513 _mmplayer_pause(MMHandleType hplayer)
5515 mmplayer_t *player = (mmplayer_t *)hplayer;
5516 gint64 pos_nsec = 0;
5517 gboolean async = FALSE;
5518 gint ret = MM_ERROR_NONE;
5522 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5524 /* check current state */
5525 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5527 /* check pipline reconfigure state */
5528 __mmplayer_check_pipeline_reconfigure_state(player);
5530 switch (MMPLAYER_CURRENT_STATE(player)) {
5531 case MM_PLAYER_STATE_READY:
5533 /* check prepare async or not.
5534 * In the case of streaming playback, it's recommned to avoid blocking wait.
5536 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5537 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5539 /* Changing back sync of rtspsrc to async */
5540 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5541 LOGD("async prepare working mode for rtsp");
5547 case MM_PLAYER_STATE_PLAYING:
5549 /* NOTE : store current point to overcome some bad operation
5550 *(returning zero when getting current position in paused state) of some
5553 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5554 LOGW("getting current position failed in paused");
5556 player->last_position = pos_nsec;
5558 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5559 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5560 This causes problem is position calculation during normal pause resume scenarios also.
5561 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5562 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5563 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5564 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5570 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5571 LOGD("doing async pause in case of ms buff src");
5575 /* pause pipeline */
5576 ret = _mmplayer_gst_pause(player, async);
5578 if (ret != MM_ERROR_NONE)
5579 LOGE("failed to pause player. ret : 0x%x", ret);
5581 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5582 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5583 LOGE("failed to update display_rotation");
5591 /* in case of streaming, pause could take long time.*/
5593 _mmplayer_abort_pause(MMHandleType hplayer)
5595 mmplayer_t *player = (mmplayer_t *)hplayer;
5596 int ret = MM_ERROR_NONE;
5600 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5602 player->pipeline->mainbin,
5603 MM_ERROR_PLAYER_NOT_INITIALIZED);
5605 LOGD("set the pipeline state to READY");
5607 /* set state to READY */
5608 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5609 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5610 if (ret != MM_ERROR_NONE) {
5611 LOGE("fail to change state to READY");
5612 return MM_ERROR_PLAYER_INTERNAL;
5615 LOGD("succeeded in changing state to READY");
5620 _mmplayer_resume(MMHandleType hplayer)
5622 mmplayer_t *player = (mmplayer_t *)hplayer;
5623 int ret = MM_ERROR_NONE;
5624 gboolean async = FALSE;
5628 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5630 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5631 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5632 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5636 /* Changing back sync mode rtspsrc to async */
5637 LOGD("async resume for rtsp case");
5641 /* check current state */
5642 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5644 ret = _mmplayer_gst_resume(player, async);
5645 if (ret != MM_ERROR_NONE)
5646 LOGE("failed to resume player.");
5648 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5649 LOGD("force resume even during buffering");
5650 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5659 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5661 mmplayer_t *player = (mmplayer_t *)hplayer;
5662 gint64 pos_nsec = 0;
5663 int ret = MM_ERROR_NONE;
5665 signed long long start = 0, stop = 0;
5666 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5669 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5670 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5672 /* The sound of video is not supported under 0.0 and over 2.0. */
5673 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5674 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5677 _mmplayer_set_mute(hplayer, mute);
5679 if (player->playback_rate == rate)
5680 return MM_ERROR_NONE;
5682 /* If the position is reached at start potion during fast backward, EOS is posted.
5683 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5685 player->playback_rate = rate;
5687 current_state = MMPLAYER_CURRENT_STATE(player);
5689 if (current_state != MM_PLAYER_STATE_PAUSED)
5690 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5692 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5694 if ((current_state == MM_PLAYER_STATE_PAUSED)
5695 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5696 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5697 pos_nsec = player->last_position;
5702 stop = GST_CLOCK_TIME_NONE;
5704 start = GST_CLOCK_TIME_NONE;
5708 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5709 player->playback_rate,
5711 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5712 GST_SEEK_TYPE_SET, start,
5713 GST_SEEK_TYPE_SET, stop)) {
5714 LOGE("failed to set speed playback");
5715 return MM_ERROR_PLAYER_SEEK;
5718 LOGD("succeeded to set speed playback as %0.1f", rate);
5722 return MM_ERROR_NONE;;
5726 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5728 mmplayer_t *player = (mmplayer_t *)hplayer;
5729 int ret = MM_ERROR_NONE;
5733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5735 /* check pipline reconfigure state */
5736 __mmplayer_check_pipeline_reconfigure_state(player);
5738 ret = _mmplayer_gst_set_position(player, position, FALSE);
5746 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5748 mmplayer_t *player = (mmplayer_t *)hplayer;
5749 int ret = MM_ERROR_NONE;
5751 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5752 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5754 if (g_strrstr(player->type, "video/mpegts"))
5755 __mmplayer_update_duration_value(player);
5757 *duration = player->duration;
5762 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5764 mmplayer_t *player = (mmplayer_t *)hplayer;
5765 int ret = MM_ERROR_NONE;
5767 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5769 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5775 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5777 mmplayer_t *player = (mmplayer_t *)hplayer;
5778 int ret = MM_ERROR_NONE;
5782 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5784 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5792 __mmplayer_is_midi_type(gchar *str_caps)
5794 if ((g_strrstr(str_caps, "audio/midi")) ||
5795 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5796 (g_strrstr(str_caps, "application/x-smaf")) ||
5797 (g_strrstr(str_caps, "audio/x-imelody")) ||
5798 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5799 (g_strrstr(str_caps, "audio/xmf")) ||
5800 (g_strrstr(str_caps, "audio/mxmf"))) {
5809 __mmplayer_is_only_mp3_type(gchar *str_caps)
5811 if (g_strrstr(str_caps, "application/x-id3") ||
5812 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5818 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5820 GstStructure *caps_structure = NULL;
5821 gint samplerate = 0;
5825 MMPLAYER_RETURN_IF_FAIL(player && caps);
5827 caps_structure = gst_caps_get_structure(caps, 0);
5829 /* set stream information */
5830 gst_structure_get_int(caps_structure, "rate", &samplerate);
5831 gst_structure_get_int(caps_structure, "channels", &channels);
5833 mm_player_set_attribute((MMHandleType)player, NULL,
5834 "content_audio_samplerate", samplerate,
5835 "content_audio_channels", channels, NULL);
5837 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5841 __mmplayer_update_content_type_info(mmplayer_t *player)
5844 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5846 if (__mmplayer_is_midi_type(player->type)) {
5847 player->bypass_audio_effect = TRUE;
5851 if (!player->streamer) {
5852 LOGD("no need to check streaming type");
5856 if (g_strrstr(player->type, "application/x-hls")) {
5857 /* If it can't know exact type when it parses uri because of redirection case,
5858 * it will be fixed by typefinder or when doing autoplugging.
5860 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5861 player->streamer->is_adaptive_streaming = TRUE;
5862 } else if (g_strrstr(player->type, "application/dash+xml")) {
5863 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5864 player->streamer->is_adaptive_streaming = TRUE;
5867 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5868 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5869 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5871 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5872 if (player->streamer->is_adaptive_streaming)
5873 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5875 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5879 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5884 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5885 GstCaps *caps, gpointer data)
5887 mmplayer_t *player = (mmplayer_t *)data;
5892 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5894 /* store type string */
5895 MMPLAYER_FREEIF(player->type);
5896 player->type = gst_caps_to_string(caps);
5898 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5899 player, player->type, probability, gst_caps_get_size(caps));
5901 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5902 (g_strrstr(player->type, "audio/x-raw-int"))) {
5903 LOGE("not support media format");
5905 if (player->msg_posted == FALSE) {
5906 MMMessageParamType msg_param;
5907 memset(&msg_param, 0, sizeof(MMMessageParamType));
5909 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5910 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5912 /* don't post more if one was sent already */
5913 player->msg_posted = TRUE;
5918 __mmplayer_update_content_type_info(player);
5920 pad = gst_element_get_static_pad(tf, "src");
5922 LOGE("fail to get typefind src pad.");
5926 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5927 gboolean async = FALSE;
5928 LOGE("failed to autoplug %s", player->type);
5930 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5932 if (async && player->msg_posted == FALSE)
5933 __mmplayer_handle_missed_plugin(player);
5937 gst_object_unref(GST_OBJECT(pad));
5945 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5947 GstElement *decodebin = NULL;
5951 /* create decodebin */
5952 decodebin = gst_element_factory_make("decodebin", NULL);
5955 LOGE("fail to create decodebin");
5959 /* raw pad handling signal */
5960 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5961 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5963 /* no-more-pad pad handling signal */
5964 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5965 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5967 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5968 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5970 /* This signal is emitted when a pad for which there is no further possible
5971 decoding is added to the decodebin.*/
5972 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5973 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5975 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5976 before looking for any elements that can handle that stream.*/
5977 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5978 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5980 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5981 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5982 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5984 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5985 before looking for any elements that can handle that stream.*/
5986 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5987 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5989 /* This signal is emitted once decodebin has finished decoding all the data.*/
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5991 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5993 /* This signal is emitted when a element is added to the bin.*/
5994 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5995 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6002 __mmplayer_gst_make_queue2(mmplayer_t *player)
6004 GstElement *queue2 = NULL;
6005 gint64 dur_bytes = 0L;
6006 mmplayer_gst_element_t *mainbin = NULL;
6007 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6010 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6012 mainbin = player->pipeline->mainbin;
6014 queue2 = gst_element_factory_make("queue2", "queue2");
6016 LOGE("failed to create buffering queue element");
6020 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6021 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6023 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6025 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6026 * skip the pull mode(file or ring buffering) setting. */
6027 if (dur_bytes > 0) {
6028 if (!g_strrstr(player->type, "video/mpegts")) {
6029 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6030 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6036 _mm_player_streaming_set_queue2(player->streamer,
6040 (guint64)dur_bytes); /* no meaning at the moment */
6046 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6048 mmplayer_gst_element_t *mainbin = NULL;
6049 GstElement *decodebin = NULL;
6050 GstElement *queue2 = NULL;
6051 GstPad *sinkpad = NULL;
6052 GstPad *qsrcpad = NULL;
6055 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6057 mainbin = player->pipeline->mainbin;
6059 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6061 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6062 LOGW("need to check: muxed buffer is not null");
6065 queue2 = __mmplayer_gst_make_queue2(player);
6067 LOGE("failed to make queue2");
6071 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6072 LOGE("failed to add buffering queue");
6076 sinkpad = gst_element_get_static_pad(queue2, "sink");
6077 qsrcpad = gst_element_get_static_pad(queue2, "src");
6079 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6080 LOGE("failed to link [%s:%s]-[%s:%s]",
6081 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6085 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6086 LOGE("failed to sync queue2 state with parent");
6090 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6091 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6095 gst_object_unref(GST_OBJECT(sinkpad));
6099 /* create decodebin */
6100 decodebin = _mmplayer_gst_make_decodebin(player);
6102 LOGE("failed to make decodebin");
6106 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6107 LOGE("failed to add decodebin");
6111 /* to force caps on the decodebin element and avoid reparsing stuff by
6112 * typefind. It also avoids a deadlock in the way typefind activates pads in
6113 * the state change */
6114 g_object_set(decodebin, "sink-caps", caps, NULL);
6116 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6118 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6119 LOGE("failed to link [%s:%s]-[%s:%s]",
6120 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6124 gst_object_unref(GST_OBJECT(sinkpad));
6126 gst_object_unref(GST_OBJECT(qsrcpad));
6129 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6130 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6132 /* set decodebin property about buffer in streaming playback. *
6133 * in case of HLS/DASH, it does not need to have big buffer *
6134 * because it is kind of adaptive streaming. */
6135 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6136 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6137 gint high_percent = 0;
6139 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6140 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6142 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6144 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6146 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6147 "high-percent", high_percent,
6148 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6149 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6150 "max-size-buffers", 0, NULL); // disable or automatic
6153 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6154 LOGE("failed to sync decodebin state with parent");
6165 gst_object_unref(GST_OBJECT(sinkpad));
6168 gst_object_unref(GST_OBJECT(qsrcpad));
6171 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6172 * You need to explicitly set elements to the NULL state before
6173 * dropping the final reference, to allow them to clean up.
6175 gst_element_set_state(queue2, GST_STATE_NULL);
6177 /* And, it still has a parent "player".
6178 * You need to let the parent manage the object instead of unreffing the object directly.
6180 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6181 gst_object_unref(queue2);
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(decodebin, 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.
6196 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6197 gst_object_unref(decodebin);
6205 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6209 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6210 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6212 LOGD("class : %s, mime : %s", factory_class, mime);
6214 /* add missing plugin */
6215 /* NOTE : msl should check missing plugin for image mime type.
6216 * Some motion jpeg clips can have playable audio track.
6217 * So, msl have to play audio after displaying popup written video format not supported.
6219 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6220 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6221 LOGD("not found demuxer");
6222 player->not_found_demuxer = TRUE;
6223 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6229 if (!g_strrstr(factory_class, "Demuxer")) {
6230 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6231 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6232 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6234 /* check that clip have multi tracks or not */
6235 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6236 LOGD("video plugin is already linked");
6238 LOGW("add VIDEO to missing plugin");
6239 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6240 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6242 } else if (g_str_has_prefix(mime, "audio")) {
6243 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6244 LOGD("audio plugin is already linked");
6246 LOGW("add AUDIO to missing plugin");
6247 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6248 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6256 return MM_ERROR_NONE;
6260 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6262 mmplayer_t *player = (mmplayer_t *)data;
6266 MMPLAYER_RETURN_IF_FAIL(player);
6268 /* remove fakesink. */
6269 if (!_mmplayer_gst_remove_fakesink(player,
6270 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6271 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6272 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6273 * source element are not same. To overcome this situation, this function will called
6274 * several places and several times. Therefore, this is not an error case.
6279 LOGD("[handle: %p] pipeline has completely constructed", player);
6281 if ((player->msg_posted == FALSE) &&
6282 (player->cmd >= MMPLAYER_COMMAND_START))
6283 __mmplayer_handle_missed_plugin(player);
6285 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6289 __mmplayer_check_profile(void)
6292 static int profile_tv = -1;
6294 if (__builtin_expect(profile_tv != -1, 1))
6297 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6298 switch (*profileName) {
6313 __mmplayer_get_next_uri(mmplayer_t *player)
6315 mmplayer_parse_profile_t profile;
6317 guint num_of_list = 0;
6320 num_of_list = g_list_length(player->uri_info.uri_list);
6321 uri_idx = player->uri_info.uri_idx;
6323 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6324 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6325 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6327 LOGW("next uri does not exist");
6331 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6332 LOGE("failed to parse profile");
6336 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6337 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6338 LOGW("uri type is not supported(%d)", profile.uri_type);
6342 LOGD("success to find next uri %d", uri_idx);
6346 if (!uri || uri_idx == num_of_list) {
6347 LOGE("failed to find next uri");
6351 player->uri_info.uri_idx = uri_idx;
6352 if (mm_player_set_attribute((MMHandleType)player, NULL,
6353 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6354 LOGE("failed to set attribute");
6358 SECURE_LOGD("next playback uri: %s", uri);
6363 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6365 #define REPEAT_COUNT_INFINITE -1
6366 #define REPEAT_COUNT_MIN 2
6367 #define ORIGINAL_URI_ONLY 1
6369 MMHandleType attrs = 0;
6373 guint num_of_uri = 0;
6374 int profile_tv = -1;
6378 LOGD("checking for gapless play option");
6380 if (player->build_audio_offload) {
6381 LOGE("offload path is not supportable.");
6385 if (player->pipeline->textbin) {
6386 LOGE("subtitle path is enabled. gapless play is not supported.");
6390 attrs = MMPLAYER_GET_ATTRS(player);
6392 LOGE("fail to get attributes.");
6396 mm_attrs_multiple_get(player->attrs, NULL,
6397 "content_video_found", &video,
6398 "profile_play_count", &count,
6399 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6401 /* gapless playback is not supported in case of video at TV profile. */
6402 profile_tv = __mmplayer_check_profile();
6403 if (profile_tv && video) {
6404 LOGW("not support video gapless playback");
6408 /* check repeat count in case of audio */
6410 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6411 LOGW("gapless is disabled");
6415 num_of_uri = g_list_length(player->uri_info.uri_list);
6417 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6419 if (num_of_uri == ORIGINAL_URI_ONLY) {
6420 /* audio looping path */
6421 if (count >= REPEAT_COUNT_MIN) {
6422 /* decrease play count */
6423 /* we succeeded to rewind. update play count and then wait for next EOS */
6425 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6426 } else if (count != REPEAT_COUNT_INFINITE) {
6427 LOGD("there is no next uri and no repeat");
6430 LOGD("looping cnt %d", count);
6432 /* gapless playback path */
6433 if (!__mmplayer_get_next_uri(player)) {
6434 LOGE("failed to get next uri");
6441 LOGE("unable to play gapless path. EOS will be posted soon");
6446 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6448 mmplayer_selector_t *selector = &player->selector[type];
6449 mmplayer_gst_element_t *sinkbin = NULL;
6450 main_element_id_e selectorId = MMPLAYER_M_NUM;
6451 main_element_id_e sinkId = MMPLAYER_M_NUM;
6452 GstPad *srcpad = NULL;
6453 GstPad *sinkpad = NULL;
6454 gboolean send_notice = FALSE;
6457 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6459 LOGD("type %d", type);
6462 case MM_PLAYER_TRACK_TYPE_AUDIO:
6463 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6464 sinkId = MMPLAYER_A_BIN;
6465 sinkbin = player->pipeline->audiobin;
6467 case MM_PLAYER_TRACK_TYPE_VIDEO:
6468 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6469 sinkId = MMPLAYER_V_BIN;
6470 sinkbin = player->pipeline->videobin;
6473 case MM_PLAYER_TRACK_TYPE_TEXT:
6474 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6475 sinkId = MMPLAYER_T_BIN;
6476 sinkbin = player->pipeline->textbin;
6479 LOGE("requested type is not supportable");
6484 if (player->pipeline->mainbin[selectorId].gst) {
6487 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6489 if (selector->event_probe_id != 0)
6490 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6491 selector->event_probe_id = 0;
6493 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6494 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6496 if (srcpad && sinkpad) {
6497 /* after getting drained signal there is no data flows, so no need to do pad_block */
6498 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6499 gst_pad_unlink(srcpad, sinkpad);
6501 /* send custom event to sink pad to handle it at video sink */
6503 LOGD("send custom event to sinkpad");
6504 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6505 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6506 gst_pad_send_event(sinkpad, event);
6510 gst_object_unref(sinkpad);
6513 gst_object_unref(srcpad);
6516 LOGD("selector release");
6518 /* release and unref requests pad from the selector */
6519 for (n = 0; n < selector->channels->len; n++) {
6520 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6521 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6523 g_ptr_array_set_size(selector->channels, 0);
6525 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6526 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6528 player->pipeline->mainbin[selectorId].gst = NULL;
6536 __mmplayer_deactivate_old_path(mmplayer_t *player)
6539 MMPLAYER_RETURN_IF_FAIL(player);
6541 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6542 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6543 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6544 LOGE("deactivate selector error");
6548 _mmplayer_track_destroy(player);
6549 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6551 if (player->streamer) {
6552 _mm_player_streaming_initialize(player->streamer, FALSE);
6553 _mm_player_streaming_destroy(player->streamer);
6554 player->streamer = NULL;
6557 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6563 if (!player->msg_posted) {
6564 MMMessageParamType msg = {0,};
6567 msg.code = MM_ERROR_PLAYER_INTERNAL;
6568 LOGE("gapless_uri_play> deactivate error");
6570 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6571 player->msg_posted = TRUE;
6577 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6579 int result = MM_ERROR_NONE;
6580 mmplayer_t *player = (mmplayer_t *)hplayer;
6583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6584 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6586 if (mm_player_set_attribute(hplayer, NULL,
6587 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6588 LOGE("failed to set attribute");
6589 result = MM_ERROR_PLAYER_INTERNAL;
6591 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6592 LOGE("failed to add the original uri in the uri list.");
6600 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6602 mmplayer_t *player = (mmplayer_t *)hplayer;
6603 guint num_of_list = 0;
6607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6608 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6610 if (player->pipeline && player->pipeline->textbin) {
6611 LOGE("subtitle path is enabled.");
6612 return MM_ERROR_PLAYER_INVALID_STATE;
6615 num_of_list = g_list_length(player->uri_info.uri_list);
6617 if (is_first_path) {
6618 if (num_of_list == 0) {
6619 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6620 SECURE_LOGD("add original path : %s", uri);
6622 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6623 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6625 SECURE_LOGD("change original path : %s", uri);
6628 MMHandleType attrs = 0;
6629 attrs = MMPLAYER_GET_ATTRS(player);
6631 if (num_of_list == 0) {
6632 char *original_uri = NULL;
6635 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6637 if (!original_uri) {
6638 LOGE("there is no original uri.");
6639 return MM_ERROR_PLAYER_INVALID_STATE;
6642 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6643 player->uri_info.uri_idx = 0;
6645 SECURE_LOGD("add original path at first : %s", original_uri);
6649 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6650 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6654 return MM_ERROR_NONE;
6658 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6660 mmplayer_t *player = (mmplayer_t *)hplayer;
6661 char *next_uri = NULL;
6662 guint num_of_list = 0;
6665 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6667 num_of_list = g_list_length(player->uri_info.uri_list);
6669 if (num_of_list > 0) {
6670 gint uri_idx = player->uri_info.uri_idx;
6672 if (uri_idx < num_of_list-1)
6677 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6678 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6680 *uri = g_strdup(next_uri);
6684 return MM_ERROR_NONE;
6688 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6689 GstCaps *caps, gpointer data)
6691 mmplayer_t *player = (mmplayer_t *)data;
6692 const gchar *klass = NULL;
6693 const gchar *mime = NULL;
6694 gchar *caps_str = NULL;
6696 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6697 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6698 caps_str = gst_caps_to_string(caps);
6700 LOGW("unknown type of caps : %s from %s",
6701 caps_str, GST_ELEMENT_NAME(elem));
6703 MMPLAYER_FREEIF(caps_str);
6705 /* There is no available codec. */
6706 __mmplayer_check_not_supported_codec(player, klass, mime);
6710 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6711 GstCaps *caps, gpointer data)
6713 mmplayer_t *player = (mmplayer_t *)data;
6714 const char *mime = NULL;
6715 gboolean ret = TRUE;
6717 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6718 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6720 if (g_str_has_prefix(mime, "audio")) {
6721 GstStructure *caps_structure = NULL;
6722 gint samplerate = 0;
6724 gchar *caps_str = NULL;
6726 caps_structure = gst_caps_get_structure(caps, 0);
6727 gst_structure_get_int(caps_structure, "rate", &samplerate);
6728 gst_structure_get_int(caps_structure, "channels", &channels);
6730 if ((channels > 0 && samplerate == 0)) {
6731 LOGD("exclude audio...");
6735 caps_str = gst_caps_to_string(caps);
6736 /* set it directly because not sent by TAG */
6737 if (g_strrstr(caps_str, "mobile-xmf"))
6738 mm_player_set_attribute((MMHandleType)player, NULL,
6739 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6741 MMPLAYER_FREEIF(caps_str);
6742 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6743 LOGD("already video linked");
6746 LOGD("found new stream");
6753 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6755 gboolean ret = FALSE;
6756 GDBusConnection *conn = NULL;
6758 GVariant *result = NULL;
6759 const gchar *dbus_device_type = NULL;
6760 const gchar *dbus_ret = NULL;
6763 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6765 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6770 result = g_dbus_connection_call_sync(conn,
6771 "org.pulseaudio.Server",
6772 "/org/pulseaudio/StreamManager",
6773 "org.pulseaudio.StreamManager",
6774 "GetCurrentMediaRoutingPath",
6775 g_variant_new("(s)", "out"),
6776 G_VARIANT_TYPE("(ss)"),
6777 G_DBUS_CALL_FLAGS_NONE,
6781 if (!result || err) {
6782 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6787 /* device type is listed in stream-map.json at mmfw-sysconf */
6788 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6790 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6791 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6794 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6795 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6796 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6797 LOGD("audio offload is supportable");
6803 LOGD("audio offload is not supportable");
6806 g_variant_unref(result);
6808 g_object_unref(conn);
6813 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6815 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6816 gint64 position = 0;
6818 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6819 player->pipeline && player->pipeline->mainbin);
6821 MMPLAYER_CMD_LOCK(player);
6822 current_state = MMPLAYER_CURRENT_STATE(player);
6824 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6825 LOGW("getting current position failed in paused");
6827 _mmplayer_unrealize((MMHandleType)player);
6828 _mmplayer_realize((MMHandleType)player);
6830 _mmplayer_set_position((MMHandleType)player, position);
6832 /* async not to be blocked in streaming case */
6833 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6835 _mmplayer_pause((MMHandleType)player);
6837 if (current_state == MM_PLAYER_STATE_PLAYING)
6838 _mmplayer_start((MMHandleType)player);
6839 MMPLAYER_CMD_UNLOCK(player);
6841 LOGD("rebuilding audio pipeline is completed.");
6844 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6846 mmplayer_t *player = (mmplayer_t *)user_data;
6847 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6848 gboolean is_supportable = FALSE;
6850 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6851 LOGW("failed to get device type");
6853 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6855 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6856 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6857 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6858 LOGD("ignore this dev connected info");
6862 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6863 if (player->build_audio_offload == is_supportable) {
6864 LOGD("keep current pipeline without re-building");
6868 /* rebuild pipeline */
6869 LOGD("re-build pipeline - offload: %d", is_supportable);
6870 player->build_audio_offload = FALSE;
6871 __mmplayer_rebuild_audio_pipeline(player);
6877 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6879 unsigned int id = 0;
6881 if (player->audio_device_cb_id != 0) {
6882 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6886 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6887 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6888 LOGD("added device connected cb (%u)", id);
6889 player->audio_device_cb_id = id;
6891 LOGW("failed to add device connected cb");
6898 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6900 mmplayer_t *player = (mmplayer_t *)hplayer;
6903 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6904 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6906 *activated = player->build_audio_offload;
6908 LOGD("offload activated : %d", (int)*activated);
6911 return MM_ERROR_NONE;
6915 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6918 this function need to be updated according to the supported media format
6919 @see player->ini.audio_offload_media_format */
6921 if (__mmplayer_is_only_mp3_type(player->type)) {
6922 LOGD("offload supportable media format type");
6930 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6932 gboolean ret = FALSE;
6933 GstElementFactory *factory = NULL;
6936 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6938 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6939 if (!__mmplayer_is_offload_supported_type(player))
6942 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6943 LOGD("there is no audio offload sink");
6947 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6948 LOGW("there is no audio device type to support offload");
6952 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6954 LOGW("there is no installed audio offload sink element");
6957 gst_object_unref(factory);
6959 if (__mmplayer_acquire_hw_resource(player,
6960 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6961 LOGE("failed to acquire audio offload decoder resource");
6965 if (!__mmplayer_add_audio_device_connected_cb(player))
6968 if (!__mmplayer_is_audio_offload_device_type(player))
6971 LOGD("audio offload can be built");
6976 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6982 static GstAutoplugSelectResult
6983 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6985 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6986 int audio_offload = 0;
6988 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6989 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6991 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6992 LOGD("expose audio path to build offload output path");
6993 player->build_audio_offload = TRUE;
6994 /* update codec info */
6995 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6996 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6997 player->audiodec_linked = 1;
6999 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7003 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7004 And need to consider the multi-track audio content.
7005 There is no HW audio decoder in public. */
7007 /* set stream information */
7008 if (!player->audiodec_linked)
7009 __mmplayer_set_audio_attrs(player, caps);
7011 /* update codec info */
7012 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7013 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7014 player->audiodec_linked = 1;
7016 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7018 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7019 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7021 /* mark video decoder for acquire */
7022 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7023 LOGW("video decoder resource is already acquired, skip it.");
7024 ret = GST_AUTOPLUG_SELECT_SKIP;
7028 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7029 LOGE("failed to acquire video decoder resource");
7030 ret = GST_AUTOPLUG_SELECT_SKIP;
7033 player->interrupted_by_resource = FALSE;
7036 /* update codec info */
7037 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7038 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7039 player->videodec_linked = 1;
7047 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7048 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7050 #define DEFAULT_IDX 0xFFFF
7051 #define MIN_FACTORY_NUM 2
7052 mmplayer_t *player = (mmplayer_t *)data;
7053 GValueArray *new_factories = NULL;
7054 GValue val = { 0, };
7055 GstElementFactory *factory = NULL;
7056 const gchar *klass = NULL;
7057 gchar *factory_name = NULL;
7058 guint hw_dec_idx = DEFAULT_IDX;
7059 guint first_sw_dec_idx = DEFAULT_IDX;
7060 guint last_sw_dec_idx = DEFAULT_IDX;
7061 guint new_pos = DEFAULT_IDX;
7062 guint rm_pos = DEFAULT_IDX;
7063 int audio_codec_type;
7064 int video_codec_type;
7065 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7067 if (factories->n_values < MIN_FACTORY_NUM)
7070 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7071 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7074 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7076 for (int i = 0 ; i < factories->n_values ; i++) {
7077 gchar *hw_dec_info = NULL;
7078 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7080 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7081 klass = gst_element_factory_get_klass(factory);
7082 factory_name = GST_OBJECT_NAME(factory);
7085 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7087 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7088 if (!player->need_audio_dec_sorting) {
7089 LOGD("sorting is not required");
7092 codec_type = audio_codec_type;
7093 hw_dec_info = player->ini.audiocodec_element_hw;
7094 sw_dec_info = player->ini.audiocodec_element_sw;
7095 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7096 if (!player->need_video_dec_sorting) {
7097 LOGD("sorting is not required");
7100 codec_type = video_codec_type;
7101 hw_dec_info = player->ini.videocodec_element_hw;
7102 sw_dec_info = player->ini.videocodec_element_sw;
7107 if (g_strrstr(factory_name, hw_dec_info)) {
7110 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7111 if (strstr(factory_name, sw_dec_info[j])) {
7112 last_sw_dec_idx = i;
7113 if (first_sw_dec_idx == DEFAULT_IDX) {
7114 first_sw_dec_idx = i;
7119 if (first_sw_dec_idx == DEFAULT_IDX)
7120 LOGW("unknown codec %s", factory_name);
7124 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7127 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7128 if (hw_dec_idx < first_sw_dec_idx)
7130 new_pos = first_sw_dec_idx - 1;
7131 rm_pos = hw_dec_idx + 1;
7132 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7133 if (last_sw_dec_idx < hw_dec_idx)
7135 new_pos = last_sw_dec_idx + 1;
7136 rm_pos = hw_dec_idx;
7141 /* change position - insert H/W decoder according to the new position */
7142 new_factories = g_value_array_copy(factories);
7143 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7144 g_value_init (&val, G_TYPE_OBJECT);
7145 g_value_set_object (&val, factory);
7146 g_value_array_insert(new_factories, new_pos, &val);
7147 g_value_unset (&val);
7148 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7150 for (int i = 0 ; i < new_factories->n_values ; i++) {
7151 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7153 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7154 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7157 return new_factories;
7161 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7162 GstCaps *caps, GstElementFactory *factory, gpointer data)
7164 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7165 mmplayer_t *player = (mmplayer_t *)data;
7167 gchar *factory_name = NULL;
7168 gchar *caps_str = NULL;
7169 const gchar *klass = NULL;
7172 factory_name = GST_OBJECT_NAME(factory);
7173 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7174 caps_str = gst_caps_to_string(caps);
7176 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7178 /* store type string */
7179 if (player->type == NULL) {
7180 player->type = gst_caps_to_string(caps);
7181 __mmplayer_update_content_type_info(player);
7184 /* filtering exclude keyword */
7185 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7186 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7187 LOGW("skipping [%s] by exculde keyword [%s]",
7188 factory_name, player->ini.exclude_element_keyword[idx]);
7190 result = GST_AUTOPLUG_SELECT_SKIP;
7195 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7196 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7197 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7198 factory_name, player->ini.unsupported_codec_keyword[idx]);
7199 result = GST_AUTOPLUG_SELECT_SKIP;
7204 /* exclude webm format */
7205 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7206 * because webm format is not supportable.
7207 * If webm is disabled in "autoplug-continue", there is no state change
7208 * failure or error because the decodebin will expose the pad directly.
7209 * It make MSL invoke _prepare_async_callback.
7210 * So, we need to disable webm format in "autoplug-select" */
7211 if (caps_str && strstr(caps_str, "webm")) {
7212 LOGW("webm is not supported");
7213 result = GST_AUTOPLUG_SELECT_SKIP;
7217 /* check factory class for filtering */
7218 /* NOTE : msl don't need to use image plugins.
7219 * So, those plugins should be skipped for error handling.
7221 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7222 LOGD("skipping [%s] by not required", factory_name);
7223 result = GST_AUTOPLUG_SELECT_SKIP;
7227 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7228 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7229 // TO CHECK : subtitle if needed, add subparse exception.
7230 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7231 result = GST_AUTOPLUG_SELECT_SKIP;
7235 if (g_strrstr(factory_name, "mpegpsdemux")) {
7236 LOGD("skipping PS container - not support");
7237 result = GST_AUTOPLUG_SELECT_SKIP;
7241 if (g_strrstr(factory_name, "mssdemux"))
7242 player->smooth_streaming = TRUE;
7244 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7245 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7248 GstStructure *str = NULL;
7249 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7251 /* don't make video because of not required */
7252 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7253 (!player->set_mode.video_export)) {
7254 LOGD("no need video decoding, expose pad");
7255 result = GST_AUTOPLUG_SELECT_EXPOSE;
7259 /* get w/h for omx state-tune */
7260 /* FIXME: deprecated? */
7261 str = gst_caps_get_structure(caps, 0);
7262 gst_structure_get_int(str, "width", &width);
7265 if (player->v_stream_caps) {
7266 gst_caps_unref(player->v_stream_caps);
7267 player->v_stream_caps = NULL;
7270 player->v_stream_caps = gst_caps_copy(caps);
7271 LOGD("take caps for video state tune");
7272 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7276 if (g_strrstr(klass, "Codec/Decoder")) {
7277 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7278 if (result != GST_AUTOPLUG_SELECT_TRY) {
7279 LOGW("skip add decoder");
7285 MMPLAYER_FREEIF(caps_str);
7291 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7294 //mmplayer_t *player = (mmplayer_t *)data;
7295 GstCaps *caps = NULL;
7297 LOGD("[Decodebin2] pad-removed signal");
7299 caps = gst_pad_query_caps(new_pad, NULL);
7301 LOGW("query caps is NULL");
7305 gchar *caps_str = NULL;
7306 caps_str = gst_caps_to_string(caps);
7308 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7310 MMPLAYER_FREEIF(caps_str);
7311 gst_caps_unref(caps);
7315 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7317 mmplayer_t *player = (mmplayer_t *)data;
7318 GstIterator *iter = NULL;
7319 GValue item = { 0, };
7321 gboolean done = FALSE;
7322 gboolean is_all_drained = TRUE;
7325 MMPLAYER_RETURN_IF_FAIL(player);
7327 LOGD("__mmplayer_gst_decode_drained");
7329 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7330 LOGW("Fail to get cmd lock");
7334 if (!__mmplayer_verify_gapless_play_path(player)) {
7335 LOGD("decoding is finished.");
7336 MMPLAYER_CMD_UNLOCK(player);
7340 _mmplayer_set_reconfigure_state(player, TRUE);
7341 MMPLAYER_CMD_UNLOCK(player);
7343 /* check decodebin src pads whether they received EOS or not */
7344 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7347 switch (gst_iterator_next(iter, &item)) {
7348 case GST_ITERATOR_OK:
7349 pad = g_value_get_object(&item);
7350 if (pad && !GST_PAD_IS_EOS(pad)) {
7351 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7352 is_all_drained = FALSE;
7355 g_value_reset(&item);
7357 case GST_ITERATOR_RESYNC:
7358 gst_iterator_resync(iter);
7360 case GST_ITERATOR_ERROR:
7361 case GST_ITERATOR_DONE:
7366 g_value_unset(&item);
7367 gst_iterator_free(iter);
7369 if (!is_all_drained) {
7370 LOGD("Wait util the all pads get EOS.");
7375 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7376 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7378 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7379 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7380 __mmplayer_deactivate_old_path(player);
7386 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7388 mmplayer_t *player = (mmplayer_t *)data;
7389 const gchar *klass = NULL;
7390 gchar *factory_name = NULL;
7392 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7393 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7395 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7397 if (__mmplayer_add_dump_buffer_probe(player, element))
7398 LOGD("add buffer probe");
7400 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7401 gchar *selected = NULL;
7402 selected = g_strdup(GST_ELEMENT_NAME(element));
7403 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7406 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7407 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7408 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7410 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7411 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7413 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7414 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7415 "max-video-width", player->adaptive_info.limit.width,
7416 "max-video-height", player->adaptive_info.limit.height, NULL);
7418 } else if (g_strrstr(klass, "Demuxer")) {
7420 LOGD("plugged element is demuxer. take it");
7422 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7423 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7426 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7427 int surface_type = 0;
7429 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7432 // to support trust-zone only
7433 if (g_strrstr(factory_name, "asfdemux")) {
7434 LOGD("set file-location %s", player->profile.uri);
7435 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7436 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7437 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7438 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7439 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7440 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7441 (__mmplayer_is_only_mp3_type(player->type))) {
7442 LOGD("[mpegaudioparse] set streaming pull mode.");
7443 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7445 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7446 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7449 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7450 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7451 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7453 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7454 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7456 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7457 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7458 (MMPLAYER_IS_DASH_STREAMING(player))) {
7459 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7460 _mm_player_streaming_set_multiqueue(player->streamer, element);
7461 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7470 __mmplayer_release_misc(mmplayer_t *player)
7473 bool cur_mode = player->set_mode.rich_audio;
7476 MMPLAYER_RETURN_IF_FAIL(player);
7478 player->sent_bos = FALSE;
7479 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7481 player->seek_state = MMPLAYER_SEEK_NONE;
7483 player->total_bitrate = 0;
7484 player->total_maximum_bitrate = 0;
7486 player->not_found_demuxer = 0;
7488 player->last_position = 0;
7489 player->duration = 0;
7490 player->http_content_size = 0;
7491 player->not_supported_codec = MISSING_PLUGIN_NONE;
7492 player->can_support_codec = FOUND_PLUGIN_NONE;
7493 player->pending_seek.is_pending = false;
7494 player->pending_seek.pos = 0;
7495 player->msg_posted = FALSE;
7496 player->has_many_types = FALSE;
7497 player->is_subtitle_force_drop = FALSE;
7498 player->play_subtitle = FALSE;
7499 player->adjust_subtitle_pos = 0;
7500 player->has_closed_caption = FALSE;
7501 player->set_mode.video_export = false;
7502 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7503 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7505 player->set_mode.rich_audio = cur_mode;
7507 if (player->audio_device_cb_id > 0 &&
7508 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7509 LOGW("failed to remove audio device_connected_callback");
7510 player->audio_device_cb_id = 0;
7512 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7513 player->bitrate[i] = 0;
7514 player->maximum_bitrate[i] = 0;
7517 /* free memory related to audio effect */
7518 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7520 if (player->adaptive_info.var_list) {
7521 g_list_free_full(player->adaptive_info.var_list, g_free);
7522 player->adaptive_info.var_list = NULL;
7525 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7526 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7527 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7529 /* Reset video360 settings to their defaults in case if the pipeline is to be
7532 player->video360_metadata.is_spherical = -1;
7533 player->is_openal_plugin_used = FALSE;
7535 player->is_content_spherical = FALSE;
7536 player->is_video360_enabled = TRUE;
7537 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7538 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7539 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7540 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7541 player->video360_zoom = 1.0f;
7542 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7543 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7545 player->sound.rg_enable = false;
7547 __mmplayer_initialize_video_roi(player);
7552 __mmplayer_release_misc_post(mmplayer_t *player)
7554 char *original_uri = NULL;
7557 /* player->pipeline is already released before. */
7558 MMPLAYER_RETURN_IF_FAIL(player);
7560 player->video_decoded_cb = NULL;
7561 player->video_decoded_cb_user_param = NULL;
7562 player->video_stream_prerolled = false;
7564 player->audio_decoded_cb = NULL;
7565 player->audio_decoded_cb_user_param = NULL;
7566 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7568 player->audio_stream_changed_cb = NULL;
7569 player->audio_stream_changed_cb_user_param = NULL;
7571 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7573 /* clean found audio decoders */
7574 if (player->audio_decoders) {
7575 GList *a_dec = player->audio_decoders;
7576 for (; a_dec; a_dec = g_list_next(a_dec)) {
7577 gchar *name = a_dec->data;
7578 MMPLAYER_FREEIF(name);
7580 g_list_free(player->audio_decoders);
7581 player->audio_decoders = NULL;
7584 /* clean the uri list except original uri */
7585 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7586 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7588 LOGW("failed to get original uri info");
7590 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7591 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7593 GList *uri_list = player->uri_info.uri_list;
7594 for (; uri_list; uri_list = g_list_next(uri_list)) {
7595 gchar *uri = uri_list->data;
7596 if (original_uri != uri)
7597 MMPLAYER_FREEIF(uri);
7601 /* clear the audio stream buffer list */
7602 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7604 /* clear the video stream bo list */
7605 __mmplayer_video_stream_destroy_bo_list(player);
7606 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7608 if (player->profile.input_mem.buf) {
7609 free(player->profile.input_mem.buf);
7610 player->profile.input_mem.buf = NULL;
7612 player->profile.input_mem.len = 0;
7613 player->profile.input_mem.offset = 0;
7615 player->uri_info.uri_idx = 0;
7620 __mmplayer_check_subtitle(mmplayer_t *player)
7622 MMHandleType attrs = 0;
7623 char *subtitle_uri = NULL;
7627 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7629 /* get subtitle attribute */
7630 attrs = MMPLAYER_GET_ATTRS(player);
7634 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7635 if (!subtitle_uri || !strlen(subtitle_uri))
7638 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7639 player->is_external_subtitle_present = TRUE;
7647 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7649 MMPLAYER_RETURN_IF_FAIL(player);
7651 if (player->eos_timer) {
7652 LOGD("cancel eos timer");
7653 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7654 player->eos_timer = 0;
7661 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7665 MMPLAYER_RETURN_IF_FAIL(player);
7666 MMPLAYER_RETURN_IF_FAIL(sink);
7668 player->sink_elements = g_list_append(player->sink_elements, sink);
7674 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7678 MMPLAYER_RETURN_IF_FAIL(player);
7679 MMPLAYER_RETURN_IF_FAIL(sink);
7681 player->sink_elements = g_list_remove(player->sink_elements, sink);
7687 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7688 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7690 mmplayer_signal_item_t *item = NULL;
7693 MMPLAYER_RETURN_IF_FAIL(player);
7695 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7696 LOGE("invalid signal type [%d]", type);
7700 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7702 LOGE("cannot connect signal [%s]", signal);
7707 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7708 player->signals[type] = g_list_append(player->signals[type], item);
7714 /* NOTE : be careful with calling this api. please refer to below glib comment
7715 * glib comment : Note that there is a bug in GObject that makes this function much
7716 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7717 * will no longer be called, but, the signal handler is not currently disconnected.
7718 * If the instance is itself being freed at the same time than this doesn't matter,
7719 * since the signal will automatically be removed, but if instance persists,
7720 * then the signal handler will leak. You should not remove the signal yourself
7721 * because in a future versions of GObject, the handler will automatically be
7724 * It's possible to work around this problem in a way that will continue to work
7725 * with future versions of GObject by checking that the signal handler is still
7726 * connected before disconnected it:
7728 * if (g_signal_handler_is_connected(instance, id))
7729 * g_signal_handler_disconnect(instance, id);
7732 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7734 GList *sig_list = NULL;
7735 mmplayer_signal_item_t *item = NULL;
7739 MMPLAYER_RETURN_IF_FAIL(player);
7741 LOGD("release signals type : %d", type);
7743 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7744 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7745 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7746 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7747 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7748 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7752 sig_list = player->signals[type];
7754 for (; sig_list; sig_list = sig_list->next) {
7755 item = sig_list->data;
7757 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7758 if (g_signal_handler_is_connected(item->obj, item->sig))
7759 g_signal_handler_disconnect(item->obj, item->sig);
7762 MMPLAYER_FREEIF(item);
7765 g_list_free(player->signals[type]);
7766 player->signals[type] = NULL;
7774 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7776 mmplayer_t *player = 0;
7777 int prev_display_surface_type = 0;
7781 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7783 player = MM_PLAYER_CAST(handle);
7785 /* check video sinkbin is created */
7786 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7787 LOGW("Videosink is already created");
7788 return MM_ERROR_NONE;
7791 LOGD("videosink element is not yet ready");
7793 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7794 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7796 return MM_ERROR_INVALID_ARGUMENT;
7799 /* load previous attributes */
7800 if (player->attrs) {
7801 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7802 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7803 if (prev_display_surface_type == surface_type) {
7804 LOGD("incoming display surface type is same as previous one, do nothing..");
7806 return MM_ERROR_NONE;
7809 LOGE("failed to load attributes");
7811 return MM_ERROR_PLAYER_INTERNAL;
7814 /* videobin is not created yet, so we just set attributes related to display surface */
7815 LOGD("store display attribute for given surface type(%d)", surface_type);
7816 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7817 "display_overlay", wl_surface_id, NULL);
7820 return MM_ERROR_NONE;
7823 /* Note : if silent is true, then subtitle would not be displayed. :*/
7825 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7827 mmplayer_t *player = (mmplayer_t *)hplayer;
7831 /* check player handle */
7832 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7834 player->set_mode.subtitle_off = silent;
7836 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7840 return MM_ERROR_NONE;
7844 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7846 mmplayer_gst_element_t *mainbin = NULL;
7847 mmplayer_gst_element_t *textbin = NULL;
7848 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7849 GstState current_state = GST_STATE_VOID_PENDING;
7850 GstState element_state = GST_STATE_VOID_PENDING;
7851 GstState element_pending_state = GST_STATE_VOID_PENDING;
7853 GstEvent *event = NULL;
7854 int result = MM_ERROR_NONE;
7856 GstClock *curr_clock = NULL;
7857 GstClockTime base_time, start_time, curr_time;
7862 /* check player handle */
7863 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7865 player->pipeline->mainbin &&
7866 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7868 mainbin = player->pipeline->mainbin;
7869 textbin = player->pipeline->textbin;
7871 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7873 // sync clock with current pipeline
7874 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7875 curr_time = gst_clock_get_time(curr_clock);
7877 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7878 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7880 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7881 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7883 if (current_state > GST_STATE_READY) {
7884 // sync state with current pipeline
7885 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7886 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7887 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7889 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7890 if (GST_STATE_CHANGE_FAILURE == ret) {
7891 LOGE("fail to state change.");
7892 result = MM_ERROR_PLAYER_INTERNAL;
7896 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7897 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7900 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7901 gst_object_unref(curr_clock);
7904 // seek to current position
7905 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7906 result = MM_ERROR_PLAYER_INVALID_STATE;
7907 LOGE("gst_element_query_position failed, invalid state");
7911 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7912 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);
7914 _mmplayer_gst_send_event_to_sink(player, event);
7916 result = MM_ERROR_PLAYER_INTERNAL;
7917 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7921 /* sync state with current pipeline */
7922 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7923 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7924 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7926 return MM_ERROR_NONE;
7929 /* release text pipeline resource */
7930 player->textsink_linked = 0;
7932 /* release signal */
7933 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7935 /* release textbin with it's childs */
7936 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7937 MMPLAYER_FREEIF(player->pipeline->textbin);
7938 player->pipeline->textbin = NULL;
7940 /* release subtitle elem */
7941 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7942 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7948 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7950 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7951 GstState current_state = GST_STATE_VOID_PENDING;
7953 MMHandleType attrs = 0;
7954 mmplayer_gst_element_t *mainbin = NULL;
7955 mmplayer_gst_element_t *textbin = NULL;
7957 gchar *subtitle_uri = NULL;
7958 int result = MM_ERROR_NONE;
7959 const gchar *charset = NULL;
7963 /* check player handle */
7964 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7966 player->pipeline->mainbin &&
7967 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7968 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7970 mainbin = player->pipeline->mainbin;
7971 textbin = player->pipeline->textbin;
7973 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7974 if (current_state < GST_STATE_READY) {
7975 result = MM_ERROR_PLAYER_INVALID_STATE;
7976 LOGE("Pipeline is not in proper state");
7980 attrs = MMPLAYER_GET_ATTRS(player);
7982 LOGE("cannot get content attribute");
7983 result = MM_ERROR_PLAYER_INTERNAL;
7987 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7988 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7989 LOGE("subtitle uri is not proper filepath");
7990 result = MM_ERROR_PLAYER_INVALID_URI;
7994 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7995 LOGE("failed to get storage info of subtitle path");
7996 result = MM_ERROR_PLAYER_INVALID_URI;
8000 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8001 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8003 if (!strcmp(filepath, subtitle_uri)) {
8004 LOGD("subtitle path is not changed");
8007 if (mm_player_set_attribute((MMHandleType)player, NULL,
8008 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8009 LOGE("failed to set attribute");
8014 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8015 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8016 player->subtitle_language_list = NULL;
8017 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8019 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8020 if (ret != GST_STATE_CHANGE_SUCCESS) {
8021 LOGE("failed to change state of textbin to READY");
8022 result = MM_ERROR_PLAYER_INTERNAL;
8026 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8027 if (ret != GST_STATE_CHANGE_SUCCESS) {
8028 LOGE("failed to change state of subparse to READY");
8029 result = MM_ERROR_PLAYER_INTERNAL;
8033 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8034 if (ret != GST_STATE_CHANGE_SUCCESS) {
8035 LOGE("failed to change state of filesrc to READY");
8036 result = MM_ERROR_PLAYER_INTERNAL;
8040 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8042 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8044 charset = _mmplayer_get_charset(filepath);
8046 LOGD("detected charset is %s", charset);
8047 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8050 result = _mmplayer_sync_subtitle_pipeline(player);
8057 /* API to switch between external subtitles */
8059 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8061 int result = MM_ERROR_NONE;
8062 mmplayer_t *player = (mmplayer_t *)hplayer;
8067 /* check player handle */
8068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8070 /* filepath can be null in idle state */
8072 /* check file path */
8073 if ((path = strstr(filepath, "file://")))
8074 result = _mmplayer_exist_file_path(path + 7);
8076 result = _mmplayer_exist_file_path(filepath);
8078 if (result != MM_ERROR_NONE) {
8079 LOGE("invalid subtitle path 0x%X", result);
8080 return result; /* file not found or permission denied */
8084 if (!player->pipeline) {
8086 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8087 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8088 LOGE("failed to set attribute");
8089 return MM_ERROR_PLAYER_INTERNAL;
8092 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8093 /* check filepath */
8094 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8096 if (!__mmplayer_check_subtitle(player)) {
8097 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8098 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8099 LOGE("failed to set attribute");
8100 return MM_ERROR_PLAYER_INTERNAL;
8103 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8104 LOGE("fail to create text pipeline");
8105 return MM_ERROR_PLAYER_INTERNAL;
8108 result = _mmplayer_sync_subtitle_pipeline(player);
8110 result = __mmplayer_change_external_subtitle_language(player, filepath);
8113 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8114 player->is_external_subtitle_added_now = TRUE;
8116 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8117 if (!player->subtitle_language_list) {
8118 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8119 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8120 LOGW("subtitle language list is not updated yet");
8122 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8130 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8132 int result = MM_ERROR_NONE;
8133 gchar *change_pad_name = NULL;
8134 GstPad *sinkpad = NULL;
8135 mmplayer_gst_element_t *mainbin = NULL;
8136 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8137 GstCaps *caps = NULL;
8138 gint total_track_num = 0;
8142 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8143 MM_ERROR_PLAYER_NOT_INITIALIZED);
8145 LOGD("Change Track(%d) to %d", type, index);
8147 mainbin = player->pipeline->mainbin;
8149 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8150 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8151 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8152 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8154 /* Changing Video Track is not supported. */
8155 LOGE("Track Type Error");
8159 if (mainbin[elem_idx].gst == NULL) {
8160 result = MM_ERROR_PLAYER_NO_OP;
8161 LOGD("Req track doesn't exist");
8165 total_track_num = player->selector[type].total_track_num;
8166 if (total_track_num <= 0) {
8167 result = MM_ERROR_PLAYER_NO_OP;
8168 LOGD("Language list is not available");
8172 if ((index < 0) || (index >= total_track_num)) {
8173 result = MM_ERROR_INVALID_ARGUMENT;
8174 LOGD("Not a proper index : %d", index);
8178 /*To get the new pad from the selector*/
8179 change_pad_name = g_strdup_printf("sink_%u", index);
8180 if (change_pad_name == NULL) {
8181 result = MM_ERROR_PLAYER_INTERNAL;
8182 LOGD("Pad does not exists");
8186 LOGD("new active pad name: %s", change_pad_name);
8188 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8189 if (sinkpad == NULL) {
8190 LOGD("sinkpad is NULL");
8191 result = MM_ERROR_PLAYER_INTERNAL;
8195 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8196 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8198 caps = gst_pad_get_current_caps(sinkpad);
8199 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8202 gst_object_unref(sinkpad);
8204 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8205 __mmplayer_set_audio_attrs(player, caps);
8208 MMPLAYER_FREEIF(change_pad_name);
8213 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8215 int result = MM_ERROR_NONE;
8216 mmplayer_t *player = NULL;
8217 mmplayer_gst_element_t *mainbin = NULL;
8219 gint current_active_index = 0;
8221 GstState current_state = GST_STATE_VOID_PENDING;
8222 GstEvent *event = NULL;
8227 player = (mmplayer_t *)hplayer;
8228 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8230 if (!player->pipeline) {
8231 LOGE("Track %d pre setting -> %d", type, index);
8233 player->selector[type].active_pad_index = index;
8237 mainbin = player->pipeline->mainbin;
8239 current_active_index = player->selector[type].active_pad_index;
8241 /*If index is same as running index no need to change the pad*/
8242 if (current_active_index == index)
8245 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8246 result = MM_ERROR_PLAYER_INVALID_STATE;
8250 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8251 if (current_state < GST_STATE_PAUSED) {
8252 result = MM_ERROR_PLAYER_INVALID_STATE;
8253 LOGW("Pipeline not in porper state");
8257 result = __mmplayer_change_selector_pad(player, type, index);
8258 if (result != MM_ERROR_NONE) {
8259 LOGE("change selector pad error");
8263 player->selector[type].active_pad_index = index;
8265 if (current_state == GST_STATE_PLAYING) {
8266 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8267 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8268 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8270 _mmplayer_gst_send_event_to_sink(player, event);
8272 result = MM_ERROR_PLAYER_INTERNAL;
8282 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8284 mmplayer_t *player = (mmplayer_t *)hplayer;
8288 /* check player handle */
8289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8291 *silent = player->set_mode.subtitle_off;
8293 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8297 return MM_ERROR_NONE;
8301 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8303 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8304 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8306 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8307 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8311 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8312 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8313 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8314 mmplayer_dump_t *dump_s;
8315 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8316 if (dump_s == NULL) {
8317 LOGE("malloc fail");
8321 dump_s->dump_element_file = NULL;
8322 dump_s->dump_pad = NULL;
8323 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8325 if (dump_s->dump_pad) {
8326 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8327 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]);
8328 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8329 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);
8330 /* add list for removed buffer probe and close FILE */
8331 player->dump_list = g_list_append(player->dump_list, dump_s);
8332 LOGD("%s sink pad added buffer probe for dump", factory_name);
8335 MMPLAYER_FREEIF(dump_s);
8336 LOGE("failed to get %s sink pad added", factory_name);
8343 static GstPadProbeReturn
8344 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8346 FILE *dump_data = (FILE *)u_data;
8348 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8349 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8351 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8353 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8355 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8357 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8359 gst_buffer_unmap(buffer, &probe_info);
8361 return GST_PAD_PROBE_OK;
8365 __mmplayer_release_dump_list(GList *dump_list)
8367 GList *d_list = dump_list;
8372 for (; d_list; d_list = g_list_next(d_list)) {
8373 mmplayer_dump_t *dump_s = d_list->data;
8374 if (dump_s->dump_pad) {
8375 if (dump_s->probe_handle_id)
8376 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8377 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8379 if (dump_s->dump_element_file) {
8380 fclose(dump_s->dump_element_file);
8381 dump_s->dump_element_file = NULL;
8383 MMPLAYER_FREEIF(dump_s);
8385 g_list_free(dump_list);
8390 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8392 mmplayer_t *player = (mmplayer_t *)hplayer;
8396 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8397 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8399 *exist = (bool)player->has_closed_caption;
8403 return MM_ERROR_NONE;
8407 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8412 LOGD("unref internal gst buffer %p", buffer);
8414 gst_buffer_unref((GstBuffer *)buffer);
8421 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8423 mmplayer_t *player = (mmplayer_t *)hplayer;
8427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8428 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8430 if (MMPLAYER_IS_STREAMING(player))
8431 *timeout = (int)player->ini.live_state_change_timeout;
8433 *timeout = (int)player->ini.localplayback_state_change_timeout;
8435 LOGD("timeout = %d", *timeout);
8438 return MM_ERROR_NONE;
8442 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8446 MMPLAYER_RETURN_IF_FAIL(player);
8448 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8450 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8451 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8452 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8453 player->storage_info[i].id = -1;
8454 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8456 if (path_type != MMPLAYER_PATH_MAX)
8465 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8467 int ret = MM_ERROR_NONE;
8468 mmplayer_t *player = (mmplayer_t *)hplayer;
8469 MMMessageParamType msg_param = {0, };
8472 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8474 LOGW("state changed storage %d:%d", id, state);
8476 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8477 return MM_ERROR_NONE;
8479 /* FIXME: text path should be handled seperately. */
8480 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8481 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8482 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8483 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8484 LOGW("external storage is removed");
8486 if (player->msg_posted == FALSE) {
8487 memset(&msg_param, 0, sizeof(MMMessageParamType));
8488 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8489 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8490 player->msg_posted = TRUE;
8493 /* unrealize the player */
8494 ret = _mmplayer_unrealize(hplayer);
8495 if (ret != MM_ERROR_NONE)
8496 LOGE("failed to unrealize");
8504 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8506 int ret = MM_ERROR_NONE;
8507 mmplayer_t *player = (mmplayer_t *)hplayer;
8508 int idx = 0, total = 0;
8509 gchar *result = NULL, *tmp = NULL;
8512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8513 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8515 total = *num = g_list_length(player->adaptive_info.var_list);
8517 LOGW("There is no stream variant info.");
8521 result = g_strdup("");
8522 for (idx = 0 ; idx < total ; idx++) {
8523 stream_variant_t *v_data = NULL;
8524 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8527 gchar data[64] = {0};
8528 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8530 tmp = g_strconcat(result, data, NULL);
8534 LOGW("There is no variant data in %d", idx);
8539 *var_info = (char *)result;
8541 LOGD("variant info %d:%s", *num, *var_info);
8547 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8549 int ret = MM_ERROR_NONE;
8550 mmplayer_t *player = (mmplayer_t *)hplayer;
8553 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8555 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8557 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8558 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8559 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8561 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8562 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8563 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8564 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8566 /* FIXME: seek to current position for applying new variant limitation */
8575 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8577 int ret = MM_ERROR_NONE;
8578 mmplayer_t *player = (mmplayer_t *)hplayer;
8581 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8582 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8584 *bandwidth = player->adaptive_info.limit.bandwidth;
8585 *width = player->adaptive_info.limit.width;
8586 *height = player->adaptive_info.limit.height;
8588 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8595 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8597 int ret = MM_ERROR_NONE;
8598 mmplayer_t *player = (mmplayer_t *)hplayer;
8601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8602 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8603 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8605 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8607 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8608 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8609 else /* live case */
8610 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8612 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8619 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8621 #define IDX_FIRST_SW_CODEC 0
8622 mmplayer_t *player = (mmplayer_t *)hplayer;
8623 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8626 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8628 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8629 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8630 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8632 switch (stream_type) {
8633 case MM_PLAYER_STREAM_TYPE_AUDIO:
8634 /* to support audio codec selection, codec info have to be added in ini file as below.
8635 audio codec element hw = xxxx
8636 audio codec element sw = avdec
8637 and in case of audio hw codec is supported and selected,
8638 audio filter elements should be applied depending on the hw capabilities.
8640 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8641 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8642 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8643 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8644 LOGE("There is no audio codec info for codec_type %d", codec_type);
8645 return MM_ERROR_PLAYER_NO_OP;
8648 case MM_PLAYER_STREAM_TYPE_VIDEO:
8649 /* to support video codec selection, codec info have to be added in ini file as below.
8650 video codec element hw = omx
8651 video codec element sw = avdec */
8652 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8653 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8654 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8655 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8656 LOGE("There is no video codec info for codec_type %d", codec_type);
8657 return MM_ERROR_PLAYER_NO_OP;
8661 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8662 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8666 LOGD("update %s codec_type to %d", attr_name, codec_type);
8667 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8670 return MM_ERROR_NONE;
8674 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8676 mmplayer_t *player = (mmplayer_t *)hplayer;
8677 GstElement *rg_vol_element = NULL;
8681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8683 player->sound.rg_enable = enabled;
8685 /* just hold rgvolume enable value if pipeline is not ready */
8686 if (!player->pipeline || !player->pipeline->audiobin) {
8687 LOGD("pipeline is not ready. holding rgvolume enable value");
8688 return MM_ERROR_NONE;
8691 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8693 if (!rg_vol_element) {
8694 LOGD("rgvolume element is not created");
8695 return MM_ERROR_PLAYER_INTERNAL;
8699 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8701 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8705 return MM_ERROR_NONE;
8709 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8711 mmplayer_t *player = (mmplayer_t *)hplayer;
8712 GstElement *rg_vol_element = NULL;
8713 gboolean enable = FALSE;
8717 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8718 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8720 /* just hold enable_rg value if pipeline is not ready */
8721 if (!player->pipeline || !player->pipeline->audiobin) {
8722 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8723 *enabled = player->sound.rg_enable;
8724 return MM_ERROR_NONE;
8727 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8729 if (!rg_vol_element) {
8730 LOGD("rgvolume element is not created");
8731 return MM_ERROR_PLAYER_INTERNAL;
8734 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8735 *enabled = (bool)enable;
8739 return MM_ERROR_NONE;
8743 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8745 mmplayer_t *player = (mmplayer_t *)hplayer;
8746 MMHandleType attrs = 0;
8748 int ret = MM_ERROR_NONE;
8752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8754 attrs = MMPLAYER_GET_ATTRS(player);
8755 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8757 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8759 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8760 return MM_ERROR_PLAYER_INTERNAL;
8763 player->video_roi.scale_x = scale_x;
8764 player->video_roi.scale_y = scale_y;
8765 player->video_roi.scale_width = scale_width;
8766 player->video_roi.scale_height = scale_height;
8768 /* check video sinkbin is created */
8769 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8770 return MM_ERROR_NONE;
8772 if (!gst_video_overlay_set_video_roi_area(
8773 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8774 scale_x, scale_y, scale_width, scale_height))
8775 ret = MM_ERROR_PLAYER_INTERNAL;
8777 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8778 scale_x, scale_y, scale_width, scale_height);
8786 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8788 mmplayer_t *player = (mmplayer_t *)hplayer;
8789 int ret = MM_ERROR_NONE;
8793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8794 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8796 *scale_x = player->video_roi.scale_x;
8797 *scale_y = player->video_roi.scale_y;
8798 *scale_width = player->video_roi.scale_width;
8799 *scale_height = player->video_roi.scale_height;
8801 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8802 *scale_x, *scale_y, *scale_width, *scale_height);
8808 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8810 mmplayer_t *player = (mmplayer_t *)hplayer;
8814 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8816 player->client_pid = pid;
8818 LOGD("client pid[%d] %p", pid, player);
8822 return MM_ERROR_NONE;
8826 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8828 mmplayer_t *player = (mmplayer_t *)hplayer;
8829 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8830 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8834 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8835 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8838 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8840 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8842 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8843 return MM_ERROR_NONE;
8845 /* in case of audio codec default type is HW */
8847 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8848 if (player->ini.support_audio_effect)
8849 return MM_ERROR_NONE;
8850 elem_id = MMPLAYER_A_FILTER;
8852 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8853 if (player->ini.support_replaygain_control)
8854 return MM_ERROR_NONE;
8855 elem_id = MMPLAYER_A_RGVOL;
8857 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8858 if (player->ini.support_pitch_control)
8859 return MM_ERROR_NONE;
8860 elem_id = MMPLAYER_A_PITCH;
8862 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8863 if (player->ini.support_audio_effect)
8864 return MM_ERROR_NONE;
8866 /* default case handling is not required */
8869 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8870 LOGW("audio control option [%d] is not available", opt);
8873 /* setting pcm exporting option is allowed before READY state */
8874 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8875 return MM_ERROR_PLAYER_INVALID_STATE;
8877 /* check whether the audio filter exist or not after READY state,
8878 because the sw codec could be added during auto-plugging in some cases */
8879 if (!player->pipeline ||
8880 !player->pipeline->audiobin ||
8881 !player->pipeline->audiobin[elem_id].gst) {
8882 LOGW("there is no audio elem [%d]", elem_id);
8887 LOGD("audio control opt %d, available %d", opt, *available);
8891 return MM_ERROR_NONE;
8895 __mmplayer_update_duration_value(mmplayer_t *player)
8897 gboolean ret = FALSE;
8898 gint64 dur_nsec = 0;
8899 LOGD("try to update duration");
8901 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8902 player->duration = dur_nsec;
8903 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8907 if (player->duration < 0) {
8908 LOGW("duration is Non-Initialized !!!");
8909 player->duration = 0;
8912 /* update streaming service type */
8913 player->streaming_type = _mmplayer_get_stream_service_type(player);
8915 /* check duration is OK */
8916 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8917 /* FIXIT : find another way to get duration here. */
8918 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8924 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8926 /* update audio params
8927 NOTE : We need original audio params and it can be only obtained from src pad of audio
8928 decoder. Below code only valid when we are not using 'resampler' just before
8929 'audioconverter'. */
8930 GstCaps *caps_a = NULL;
8932 gint samplerate = 0, channels = 0;
8933 GstStructure *p = NULL;
8934 GstElement *aconv = NULL;
8936 LOGD("try to update audio attrs");
8938 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8940 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8941 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8942 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8943 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8945 LOGE("there is no audio converter");
8949 pad = gst_element_get_static_pad(aconv, "sink");
8952 LOGW("failed to get pad from audio converter");
8956 caps_a = gst_pad_get_current_caps(pad);
8958 LOGW("not ready to get audio caps");
8959 gst_object_unref(pad);
8963 p = gst_caps_get_structure(caps_a, 0);
8965 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8967 gst_structure_get_int(p, "rate", &samplerate);
8968 gst_structure_get_int(p, "channels", &channels);
8970 mm_player_set_attribute((MMHandleType)player, NULL,
8971 "content_audio_samplerate", samplerate,
8972 "content_audio_channels", channels, NULL);
8974 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8976 gst_caps_unref(caps_a);
8977 gst_object_unref(pad);
8983 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8985 LOGD("try to update video attrs");
8987 GstCaps *caps_v = NULL;
8991 GstStructure *p = NULL;
8993 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8994 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8996 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8998 LOGD("no videosink sink pad");
9002 caps_v = gst_pad_get_current_caps(pad);
9003 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9004 if (!caps_v && player->v_stream_caps) {
9005 caps_v = player->v_stream_caps;
9006 gst_caps_ref(caps_v);
9010 LOGD("no negitiated caps from videosink");
9011 gst_object_unref(pad);
9015 p = gst_caps_get_structure(caps_v, 0);
9016 gst_structure_get_int(p, "width", &width);
9017 gst_structure_get_int(p, "height", &height);
9019 mm_player_set_attribute((MMHandleType)player, NULL,
9020 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9022 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9024 SECURE_LOGD("width : %d height : %d", width, height);
9026 gst_caps_unref(caps_v);
9027 gst_object_unref(pad);
9030 mm_player_set_attribute((MMHandleType)player, NULL,
9031 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9032 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9039 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9041 gboolean ret = FALSE;
9042 guint64 data_size = 0;
9046 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9047 if (!player->duration)
9050 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9051 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9052 if (stat(path, &sb) == 0)
9053 data_size = (guint64)sb.st_size;
9055 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9056 data_size = player->http_content_size;
9059 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9062 guint64 bitrate = 0;
9063 guint64 msec_dur = 0;
9065 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9067 bitrate = data_size * 8 * 1000 / msec_dur;
9068 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9069 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9070 mm_player_set_attribute((MMHandleType)player, NULL,
9071 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9074 LOGD("player duration is less than 0");
9078 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9079 if (player->total_bitrate) {
9080 mm_player_set_attribute((MMHandleType)player, NULL,
9081 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9090 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9092 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9093 data->uri_type = uri_type;
9097 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9099 int ret = MM_ERROR_PLAYER_INVALID_URI;
9101 char *buffer = NULL;
9102 char *seperator = strchr(path, ',');
9103 char ext[100] = {0,}, size[100] = {0,};
9106 if ((buffer = strstr(path, "ext="))) {
9107 buffer += strlen("ext=");
9109 if (strlen(buffer)) {
9110 strncpy(ext, buffer, 99);
9112 if ((seperator = strchr(ext, ','))
9113 || (seperator = strchr(ext, ' '))
9114 || (seperator = strchr(ext, '\0'))) {
9115 seperator[0] = '\0';
9120 if ((buffer = strstr(path, "size="))) {
9121 buffer += strlen("size=");
9123 if (strlen(buffer) > 0) {
9124 strncpy(size, buffer, 99);
9126 if ((seperator = strchr(size, ','))
9127 || (seperator = strchr(size, ' '))
9128 || (seperator = strchr(size, '\0'))) {
9129 seperator[0] = '\0';
9132 mem_size = atoi(size);
9137 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9139 if (mem_size && param) {
9140 if (data->input_mem.buf)
9141 free(data->input_mem.buf);
9142 data->input_mem.buf = malloc(mem_size);
9144 if (data->input_mem.buf) {
9145 memcpy(data->input_mem.buf, param, mem_size);
9146 data->input_mem.len = mem_size;
9147 ret = MM_ERROR_NONE;
9149 LOGE("failed to alloc mem %d", mem_size);
9150 ret = MM_ERROR_PLAYER_INTERNAL;
9153 data->input_mem.offset = 0;
9154 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9161 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9163 gchar *location = NULL;
9166 int ret = MM_ERROR_NONE;
9168 if ((path = strstr(uri, "file://"))) {
9169 location = g_filename_from_uri(uri, NULL, &err);
9170 if (!location || (err != NULL)) {
9171 LOGE("Invalid URI '%s' for filesrc: %s", path,
9172 (err != NULL) ? err->message : "unknown error");
9176 MMPLAYER_FREEIF(location);
9178 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9179 return MM_ERROR_PLAYER_INVALID_URI;
9181 LOGD("path from uri: %s", location);
9184 path = (location != NULL) ? (location) : ((char *)uri);
9187 ret = _mmplayer_exist_file_path(path);
9189 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9190 if (ret == MM_ERROR_NONE) {
9191 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9192 if (_mmplayer_is_sdp_file(path)) {
9193 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9194 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9196 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9198 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9199 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9201 LOGE("invalid uri, could not play..");
9202 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9205 MMPLAYER_FREEIF(location);
9210 static mmplayer_video_decoded_data_info_t *
9211 __mmplayer_create_stream_from_pad(GstPad *pad)
9213 GstCaps *caps = NULL;
9214 GstStructure *structure = NULL;
9215 unsigned int fourcc = 0;
9216 const gchar *string_format = NULL;
9217 mmplayer_video_decoded_data_info_t *stream = NULL;
9219 MMPixelFormatType format;
9222 caps = gst_pad_get_current_caps(pad);
9224 LOGE("Caps is NULL.");
9229 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9231 structure = gst_caps_get_structure(caps, 0);
9232 gst_structure_get_int(structure, "width", &width);
9233 gst_structure_get_int(structure, "height", &height);
9234 string_format = gst_structure_get_string(structure, "format");
9237 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9238 format = _mmplayer_get_pixtype(fourcc);
9239 gst_video_info_from_caps(&info, caps);
9240 gst_caps_unref(caps);
9243 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9244 LOGE("Wrong condition!!");
9248 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9250 LOGE("failed to alloc mem for video data");
9254 stream->width = width;
9255 stream->height = height;
9256 stream->format = format;
9257 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9263 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9265 unsigned int pitch = 0;
9266 unsigned int size = 0;
9268 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9271 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9272 bo = gst_tizen_memory_get_bos(mem, index);
9274 stream->bo[index] = tbm_bo_ref(bo);
9276 LOGE("failed to get bo for index %d", index);
9279 for (index = 0; index < stream->plane_num; index++) {
9280 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9281 stream->stride[index] = pitch;
9283 stream->elevation[index] = size / pitch;
9285 stream->elevation[index] = stream->height;
9290 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9292 if (stream->format == MM_PIXEL_FORMAT_I420) {
9293 int ret = TBM_SURFACE_ERROR_NONE;
9294 tbm_surface_h surface;
9295 tbm_surface_info_s info;
9297 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9299 ret = tbm_surface_get_info(surface, &info);
9300 if (ret != TBM_SURFACE_ERROR_NONE) {
9301 tbm_surface_destroy(surface);
9305 tbm_surface_destroy(surface);
9306 stream->stride[0] = info.planes[0].stride;
9307 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9308 stream->stride[1] = info.planes[1].stride;
9309 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9310 stream->stride[2] = info.planes[2].stride;
9311 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9312 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9313 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9314 stream->stride[0] = stream->width * 4;
9315 stream->elevation[0] = stream->height;
9316 stream->bo_size = stream->stride[0] * stream->height;
9318 LOGE("Not support format %d", stream->format);
9326 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9328 tbm_bo_handle thandle;
9330 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9331 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9332 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9336 unsigned char *src = NULL;
9337 unsigned char *dest = NULL;
9338 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9340 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9342 LOGE("fail to gst_memory_map");
9346 if (!mapinfo.data) {
9347 LOGE("data pointer is wrong");
9351 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9352 if (!stream->bo[0]) {
9353 LOGE("Fail to tbm_bo_alloc!!");
9357 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9359 LOGE("thandle pointer is wrong");
9363 if (stream->format == MM_PIXEL_FORMAT_I420) {
9364 src_stride[0] = GST_ROUND_UP_4(stream->width);
9365 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9366 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9367 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9370 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9371 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9373 for (i = 0; i < 3; i++) {
9374 src = mapinfo.data + src_offset[i];
9375 dest = thandle.ptr + dest_offset[i];
9380 for (j = 0; j < stream->height >> k; j++) {
9381 memcpy(dest, src, stream->width>>k);
9382 src += src_stride[i];
9383 dest += stream->stride[i];
9386 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9387 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9389 LOGE("Not support format %d", stream->format);
9393 tbm_bo_unmap(stream->bo[0]);
9394 gst_memory_unmap(mem, &mapinfo);
9400 tbm_bo_unmap(stream->bo[0]);
9403 gst_memory_unmap(mem, &mapinfo);
9409 __mmplayer_set_pause_state(mmplayer_t *player)
9411 if (player->sent_bos)
9414 /* rtsp case, get content attrs by GstMessage */
9415 if (MMPLAYER_IS_RTSP_STREAMING(player))
9418 /* it's first time to update all content attrs. */
9419 _mmplayer_update_content_attrs(player, ATTR_ALL);
9423 __mmplayer_set_playing_state(mmplayer_t *player)
9425 gchar *audio_codec = NULL;
9427 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9428 /* initialize because auto resume is done well. */
9429 player->resumed_by_rewind = FALSE;
9430 player->playback_rate = 1.0;
9433 if (player->sent_bos)
9436 /* try to get content metadata */
9438 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9439 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9440 * legacy mmfw-player api
9442 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9444 if ((player->cmd == MMPLAYER_COMMAND_START)
9445 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9446 __mmplayer_handle_missed_plugin(player);
9449 /* check audio codec field is set or not
9450 * we can get it from typefinder or codec's caps.
9452 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9454 /* The codec format can't be sent for audio only case like amr, mid etc.
9455 * Because, parser don't make related TAG.
9456 * So, if it's not set yet, fill it with found data.
9459 if (g_strrstr(player->type, "audio/midi"))
9460 audio_codec = "MIDI";
9461 else if (g_strrstr(player->type, "audio/x-amr"))
9462 audio_codec = "AMR";
9463 else if (g_strrstr(player->type, "audio/mpeg")
9464 && !g_strrstr(player->type, "mpegversion=(int)1"))
9465 audio_codec = "AAC";
9467 audio_codec = "unknown";
9469 if (mm_player_set_attribute((MMHandleType)player, NULL,
9470 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9471 LOGE("failed to set attribute");
9473 LOGD("set audio codec type with caps");