4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related fucntion will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
144 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
145 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
146 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
147 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
148 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
149 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
150 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
151 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
152 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
153 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
155 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static void __mmplayer_release_misc(mmplayer_t *player);
157 static void __mmplayer_release_misc_post(mmplayer_t *player);
158 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
159 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
160 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
162 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
164 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
165 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
166 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
167 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
168 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
170 static gpointer __mmplayer_gapless_play_thread(gpointer data);
171 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
172 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
173 static void __mmplayer_release_dump_list(GList *dump_list);
174 static int __mmplayer_gst_realize(mmplayer_t *player);
175 static int __mmplayer_gst_unrealize(mmplayer_t *player);
176 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
177 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
180 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
181 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
182 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
183 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
184 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
185 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
186 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
187 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
188 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
189 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
190 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
191 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
194 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
195 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
196 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
198 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
199 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
200 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
201 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
203 static void __mmplayer_set_pause_state(mmplayer_t *player);
204 static void __mmplayer_set_playing_state(mmplayer_t *player);
205 /*===========================================================================================
207 | FUNCTION DEFINITIONS |
209 ========================================================================================== */
211 /* This function should be called after the pipeline goes PAUSED or higher
214 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
216 static gboolean has_duration = FALSE;
217 static gboolean has_video_attrs = FALSE;
218 static gboolean has_audio_attrs = FALSE;
219 static gboolean has_bitrate = FALSE;
220 gboolean missing_only = FALSE;
221 gboolean all = FALSE;
222 MMHandleType attrs = 0;
226 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
228 /* check player state here */
229 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
230 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
231 /* give warning now only */
232 LOGW("be careful. content attributes may not available in this state ");
235 /* get content attribute first */
236 attrs = MMPLAYER_GET_ATTRS(player);
238 LOGE("cannot get content attribute");
242 /* get update flag */
244 if (flag & ATTR_MISSING_ONLY) {
246 LOGD("updating missed attr only");
249 if (flag & ATTR_ALL) {
251 has_duration = FALSE;
252 has_video_attrs = FALSE;
253 has_audio_attrs = FALSE;
256 LOGD("updating all attrs");
259 if (missing_only && all) {
260 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
261 missing_only = FALSE;
264 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
265 has_duration = __mmplayer_update_duration_value(player);
267 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
268 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
270 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
271 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
273 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
274 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
282 _mmplayer_get_stream_service_type(mmplayer_t *player)
284 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
288 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
290 player->pipeline->mainbin &&
291 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
292 STREAMING_SERVICE_NONE);
294 /* streaming service type if streaming */
295 if (!MMPLAYER_IS_STREAMING(player))
296 return STREAMING_SERVICE_NONE;
298 streaming_type = (player->duration == 0) ?
299 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
301 switch (streaming_type) {
302 case STREAMING_SERVICE_LIVE:
303 LOGD("it's live streaming");
305 case STREAMING_SERVICE_VOD:
306 LOGD("it's vod streaming");
309 LOGE("should not get here");
315 return streaming_type;
318 /* this function sets the player state and also report
319 * it to applicaton by calling callback function
322 _mmplayer_set_state(mmplayer_t *player, int state)
324 MMMessageParamType msg = {0, };
326 MMPLAYER_RETURN_IF_FAIL(player);
328 if (MMPLAYER_CURRENT_STATE(player) == state) {
329 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
330 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
334 /* update player states */
335 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
336 MMPLAYER_CURRENT_STATE(player) = state;
338 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
339 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
342 MMPLAYER_PRINT_STATE(player);
344 switch (MMPLAYER_CURRENT_STATE(player)) {
345 case MM_PLAYER_STATE_NULL:
346 case MM_PLAYER_STATE_READY:
348 case MM_PLAYER_STATE_PAUSED:
349 __mmplayer_set_pause_state(player);
351 case MM_PLAYER_STATE_PLAYING:
352 __mmplayer_set_playing_state(player);
354 case MM_PLAYER_STATE_NONE:
356 LOGW("invalid target state, there is nothing to do.");
361 /* post message to application */
362 if (MMPLAYER_TARGET_STATE(player) == state) {
363 /* fill the message with state of player */
364 msg.union_type = MM_MSG_UNION_STATE;
365 msg.state.previous = MMPLAYER_PREV_STATE(player);
366 msg.state.current = MMPLAYER_CURRENT_STATE(player);
368 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
370 /* state changed by resource callback */
371 if (player->interrupted_by_resource)
372 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
373 else /* state changed by usecase */
374 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
377 LOGD("intermediate state, do nothing.");
378 MMPLAYER_PRINT_STATE(player);
382 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
383 && !player->sent_bos) {
384 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
385 player->sent_bos = TRUE;
392 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
394 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
395 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
399 LOGD("incomming command : %d ", command);
401 current_state = MMPLAYER_CURRENT_STATE(player);
402 pending_state = MMPLAYER_PENDING_STATE(player);
404 MMPLAYER_PRINT_STATE(player);
407 case MMPLAYER_COMMAND_CREATE:
409 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
411 if (current_state == MM_PLAYER_STATE_NULL ||
412 current_state == MM_PLAYER_STATE_READY ||
413 current_state == MM_PLAYER_STATE_PAUSED ||
414 current_state == MM_PLAYER_STATE_PLAYING)
419 case MMPLAYER_COMMAND_DESTROY:
421 /* destroy can called anytime */
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
427 case MMPLAYER_COMMAND_REALIZE:
429 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
431 if (pending_state != MM_PLAYER_STATE_NONE) {
434 /* need ready state to realize */
435 if (current_state == MM_PLAYER_STATE_READY)
438 if (current_state != MM_PLAYER_STATE_NULL)
444 case MMPLAYER_COMMAND_UNREALIZE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL)
453 case MMPLAYER_COMMAND_START:
455 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
457 if (pending_state == MM_PLAYER_STATE_NONE) {
458 if (current_state == MM_PLAYER_STATE_PLAYING)
460 else if (current_state != MM_PLAYER_STATE_READY &&
461 current_state != MM_PLAYER_STATE_PAUSED)
463 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
465 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
466 LOGD("player is going to paused state, just change the pending state as playing");
473 case MMPLAYER_COMMAND_STOP:
475 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
477 if (current_state == MM_PLAYER_STATE_READY)
480 /* need playing/paused state to stop */
481 if (current_state != MM_PLAYER_STATE_PLAYING &&
482 current_state != MM_PLAYER_STATE_PAUSED)
487 case MMPLAYER_COMMAND_PAUSE:
489 if (MMPLAYER_IS_LIVE_STREAMING(player))
492 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
493 goto NOT_COMPLETED_SEEK;
495 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
497 if (pending_state == MM_PLAYER_STATE_NONE) {
498 if (current_state == MM_PLAYER_STATE_PAUSED)
500 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
504 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
505 if (current_state == MM_PLAYER_STATE_PAUSED)
506 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
513 case MMPLAYER_COMMAND_RESUME:
515 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
516 goto NOT_COMPLETED_SEEK;
518 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
520 if (pending_state == MM_PLAYER_STATE_NONE) {
521 if (current_state == MM_PLAYER_STATE_PLAYING)
523 else if (current_state != MM_PLAYER_STATE_PAUSED)
525 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
527 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
528 LOGD("player is going to paused state, just change the pending state as playing");
538 player->cmd = command;
540 return MM_ERROR_NONE;
543 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
544 MMPLAYER_STATE_GET_NAME(current_state), command);
545 return MM_ERROR_PLAYER_INVALID_STATE;
548 LOGW("not completed seek");
549 return MM_ERROR_PLAYER_DOING_SEEK;
552 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
553 return MM_ERROR_PLAYER_NO_OP;
556 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
557 return MM_ERROR_PLAYER_NO_OP;
560 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
562 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
563 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
566 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
569 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
570 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
572 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
573 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
576 LOGE("invalid mmplayer resource type %d", type);
577 return MM_ERROR_PLAYER_INTERNAL;
580 if (player->hw_resource[type] != NULL) {
581 LOGD("[%d type] resource was already acquired", type);
582 return MM_ERROR_NONE;
585 LOGD("mark for acquire [%d type] resource", type);
586 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
587 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
593 rm_ret = mm_resource_manager_commit(player->resource_manager);
594 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
595 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
596 return MM_ERROR_PLAYER_INTERNAL;
600 return MM_ERROR_NONE;
603 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
605 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
609 if (player->hw_resource[type] == NULL) {
610 LOGD("there is no acquired [%d type] resource", type);
611 return MM_ERROR_NONE;
614 LOGD("mark for release [%d type] resource", type);
615 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
616 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
617 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
618 return MM_ERROR_PLAYER_INTERNAL;
621 player->hw_resource[type] = NULL;
623 rm_ret = mm_resource_manager_commit(player->resource_manager);
624 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
625 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
626 return MM_ERROR_PLAYER_INTERNAL;
630 return MM_ERROR_NONE;
634 __mmplayer_initialize_gapless_play(mmplayer_t *player)
640 player->smooth_streaming = FALSE;
641 player->videodec_linked = 0;
642 player->audiodec_linked = 0;
643 player->textsink_linked = 0;
644 player->is_external_subtitle_present = FALSE;
645 player->is_external_subtitle_added_now = FALSE;
646 player->not_supported_codec = MISSING_PLUGIN_NONE;
647 player->can_support_codec = FOUND_PLUGIN_NONE;
648 player->pending_seek.is_pending = false;
649 player->pending_seek.pos = 0;
650 player->msg_posted = FALSE;
651 player->has_many_types = FALSE;
652 player->no_more_pad = FALSE;
653 player->not_found_demuxer = 0;
654 player->seek_state = MMPLAYER_SEEK_NONE;
655 player->is_subtitle_force_drop = FALSE;
656 player->play_subtitle = FALSE;
657 player->adjust_subtitle_pos = 0;
659 player->total_bitrate = 0;
660 player->total_maximum_bitrate = 0;
662 _mmplayer_track_initialize(player);
663 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
665 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
666 player->bitrate[i] = 0;
667 player->maximum_bitrate[i] = 0;
670 if (player->v_stream_caps) {
671 gst_caps_unref(player->v_stream_caps);
672 player->v_stream_caps = NULL;
675 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
677 /* clean found audio decoders */
678 if (player->audio_decoders) {
679 GList *a_dec = player->audio_decoders;
680 for (; a_dec; a_dec = g_list_next(a_dec)) {
681 gchar *name = a_dec->data;
682 MMPLAYER_FREEIF(name);
684 g_list_free(player->audio_decoders);
685 player->audio_decoders = NULL;
688 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
693 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
695 LOGI("set pipeline reconfigure state %d", state);
696 MMPLAYER_RECONFIGURE_LOCK(player);
697 player->gapless.reconfigure = state;
698 if (!state) /* wake up the waiting job */
699 MMPLAYER_RECONFIGURE_SIGNAL(player);
700 MMPLAYER_RECONFIGURE_UNLOCK(player);
704 __mmplayer_gapless_play_thread(gpointer data)
706 mmplayer_t *player = (mmplayer_t *)data;
707 mmplayer_gst_element_t *mainbin = NULL;
709 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
711 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
712 while (!player->gapless_play_thread_exit) {
713 LOGD("gapless play thread started. waiting for signal.");
714 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
716 LOGD("reconfigure pipeline for gapless play.");
718 if (player->gapless_play_thread_exit) {
719 _mmplayer_set_reconfigure_state(player, FALSE);
720 LOGD("exiting gapless play thread");
724 mainbin = player->pipeline->mainbin;
726 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
727 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
728 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
729 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
730 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
732 /* Initialize Player values */
733 __mmplayer_initialize_gapless_play(player);
735 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
737 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
743 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
745 GSource *source = NULL;
749 source = g_main_context_find_source_by_id(context, source_id);
750 if (source != NULL) {
751 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
752 g_source_destroy(source);
759 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
761 mmplayer_t *player = (mmplayer_t *)hplayer;
762 GstMessage *msg = NULL;
763 GQueue *queue = NULL;
766 MMPLAYER_RETURN_IF_FAIL(player);
768 /* disconnecting bus watch */
769 if (player->bus_watcher)
770 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
771 player->bus_watcher = 0;
773 /* destroy the gst bus msg thread */
774 if (player->bus_msg_thread) {
775 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
776 player->bus_msg_thread_exit = TRUE;
777 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
778 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
780 LOGD("gst bus msg thread exit.");
781 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
782 player->bus_msg_thread = NULL;
784 g_mutex_clear(&player->bus_msg_thread_mutex);
785 g_cond_clear(&player->bus_msg_thread_cond);
788 g_mutex_lock(&player->bus_msg_q_lock);
789 queue = player->bus_msg_q;
790 while (!g_queue_is_empty(queue)) {
791 msg = (GstMessage *)g_queue_pop_head(queue);
796 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
797 gst_message_unref(msg);
799 g_mutex_unlock(&player->bus_msg_q_lock);
805 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
807 GstElement *parent = NULL;
809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
810 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
813 MMPLAYER_FSINK_LOCK(player);
815 /* get parent of fakesink */
816 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
818 LOGD("fakesink already removed");
822 gst_element_set_locked_state(fakesink->gst, TRUE);
824 /* setting the state to NULL never returns async
825 * so no need to wait for completion of state transiton
827 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
828 LOGE("fakesink state change failure!");
829 /* FIXIT : should I return here? or try to proceed to next? */
832 /* remove fakesink from it's parent */
833 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
834 LOGE("failed to remove fakesink");
836 gst_object_unref(parent);
841 gst_object_unref(parent);
843 LOGD("state-holder removed");
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
852 gst_element_set_locked_state(fakesink->gst, FALSE);
854 MMPLAYER_FSINK_UNLOCK(player);
858 static GstPadProbeReturn
859 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
861 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
862 return GST_PAD_PROBE_OK;
866 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
868 gint64 stop_running_time = 0;
869 gint64 position_running_time = 0;
873 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
874 if ((player->gapless.update_segment[idx] == TRUE) ||
875 !(player->selector[idx].event_probe_id)) {
877 LOGW("[%d] skip", idx);
882 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
884 gst_segment_to_running_time(&player->gapless.segment[idx],
885 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
886 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
888 gst_segment_to_running_time(&player->gapless.segment[idx],
889 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
891 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
893 gst_segment_to_running_time(&player->gapless.segment[idx],
894 GST_FORMAT_TIME, player->duration);
897 position_running_time =
898 gst_segment_to_running_time(&player->gapless.segment[idx],
899 GST_FORMAT_TIME, player->gapless.segment[idx].position);
901 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
902 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
904 GST_TIME_ARGS(stop_running_time),
905 GST_TIME_ARGS(position_running_time),
906 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
907 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
909 position_running_time = MAX(position_running_time, stop_running_time);
910 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
911 GST_FORMAT_TIME, player->gapless.segment[idx].start);
912 position_running_time = MAX(0, position_running_time);
913 position = MAX(position, position_running_time);
917 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
918 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
919 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
921 player->gapless.start_time[stream_type] += position;
927 static GstPadProbeReturn
928 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
930 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
931 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
932 mmplayer_t *player = (mmplayer_t *)data;
933 GstCaps *caps = NULL;
934 GstStructure *str = NULL;
935 const gchar *name = NULL;
936 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
937 gboolean caps_ret = TRUE;
939 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
940 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
941 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
942 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
943 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
946 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
950 if (strstr(name, "audio")) {
951 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
952 } else if (strstr(name, "video")) {
953 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
955 /* text track is not supportable */
956 LOGE("invalid name %s", name);
960 switch (GST_EVENT_TYPE(event)) {
963 /* in case of gapless, drop eos event not to send it to sink */
964 if (player->gapless.reconfigure && !player->msg_posted) {
965 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
966 ret = GST_PAD_PROBE_DROP;
970 case GST_EVENT_STREAM_START:
972 __mmplayer_gst_selector_update_start_time(player, stream_type);
975 case GST_EVENT_FLUSH_STOP:
977 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
978 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
979 player->gapless.start_time[stream_type] = 0;
982 case GST_EVENT_SEGMENT:
987 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
988 gst_event_copy_segment(event, &segment);
990 if (segment.format != GST_FORMAT_TIME)
993 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
994 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
995 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
996 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
997 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
998 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1000 /* keep the all the segment ev to cover the seeking */
1001 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1002 player->gapless.update_segment[stream_type] = TRUE;
1004 if (!player->gapless.running)
1007 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1009 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1011 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1012 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1013 gst_event_unref(event);
1014 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1020 gdouble proportion = 0.0;
1021 GstClockTimeDiff diff = 0;
1022 GstClockTime timestamp = 0;
1023 gint64 running_time_diff = -1;
1024 GstQOSType type = 0;
1025 GstEvent *tmpev = NULL;
1027 running_time_diff = player->gapless.segment[stream_type].base;
1029 if (running_time_diff <= 0) /* don't need to adjust */
1032 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1033 gst_event_unref(event);
1035 if (timestamp < running_time_diff) {
1036 LOGW("QOS event from previous group");
1037 ret = GST_PAD_PROBE_DROP;
1042 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1043 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1044 stream_type, GST_TIME_ARGS(timestamp),
1045 GST_TIME_ARGS(running_time_diff),
1046 GST_TIME_ARGS(timestamp - running_time_diff));
1049 timestamp -= running_time_diff;
1051 /* That case is invalid for QoS events */
1052 if (diff < 0 && -diff > timestamp) {
1053 LOGW("QOS event from previous group");
1054 ret = GST_PAD_PROBE_DROP;
1058 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1059 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1069 gst_caps_unref(caps);
1073 /* create fakesink for audio or video path witout audiobin or videobin */
1075 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1077 GstElement *pipeline = NULL;
1078 GstElement *fakesink = NULL;
1079 GstPad *sinkpad = NULL;
1082 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1084 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1087 fakesink = gst_element_factory_make("fakesink", NULL);
1088 if (fakesink == NULL) {
1089 LOGE("failed to create fakesink");
1093 /* store it as it's sink element */
1094 __mmplayer_add_sink(player, fakesink);
1096 gst_bin_add(GST_BIN(pipeline), fakesink);
1099 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1101 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1103 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1104 LOGE("failed to link fakesink");
1105 gst_object_unref(GST_OBJECT(fakesink));
1109 if (strstr(name, "video")) {
1110 if (player->v_stream_caps) {
1111 gst_caps_unref(player->v_stream_caps);
1112 player->v_stream_caps = NULL;
1114 if (player->ini.set_dump_element_flag)
1115 __mmplayer_add_dump_buffer_probe(player, fakesink);
1118 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1119 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1123 gst_object_unref(GST_OBJECT(sinkpad));
1130 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1132 GstElement *pipeline = NULL;
1133 GstElement *selector = NULL;
1134 GstPad *srcpad = NULL;
1137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1139 selector = gst_element_factory_make("input-selector", NULL);
1141 LOGE("failed to create input-selector");
1144 g_object_set(selector, "sync-streams", TRUE, NULL);
1146 player->pipeline->mainbin[elem_idx].id = elem_idx;
1147 player->pipeline->mainbin[elem_idx].gst = selector;
1149 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1151 srcpad = gst_element_get_static_pad(selector, "src");
1153 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1154 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1155 __mmplayer_gst_selector_blocked, NULL, NULL);
1156 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1157 __mmplayer_gst_selector_event_probe, player, NULL);
1159 gst_element_set_state(selector, GST_STATE_PAUSED);
1161 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1162 gst_bin_add(GST_BIN(pipeline), selector);
1164 gst_object_unref(GST_OBJECT(srcpad));
1171 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1173 mmplayer_t *player = (mmplayer_t *)data;
1174 GstElement *selector = NULL;
1175 GstCaps *caps = NULL;
1176 GstStructure *str = NULL;
1177 const gchar *name = NULL;
1178 GstPad *sinkpad = NULL;
1179 gboolean first_track = FALSE;
1180 gboolean caps_ret = TRUE;
1182 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1183 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1186 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1187 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1189 LOGD("pad-added signal handling");
1191 /* get mimetype from caps */
1192 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1196 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1198 LOGD("detected mimetype : %s", name);
1201 if (strstr(name, "video")) {
1203 gchar *caps_str = NULL;
1205 caps_str = gst_caps_to_string(caps);
1206 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1207 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1208 player->set_mode.video_zc = true;
1210 MMPLAYER_FREEIF(caps_str);
1212 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1213 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1215 LOGD("surface type : %d", stype);
1217 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1218 __mmplayer_gst_create_sinkbin(elem, pad, player);
1222 /* in case of exporting video frame, it requires the 360 video filter.
1223 * it will be handled in _no_more_pads(). */
1224 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1225 __mmplayer_gst_make_fakesink(player, pad, name);
1229 LOGD("video selector is required");
1230 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1231 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1232 } else if (strstr(name, "audio")) {
1233 gint samplerate = 0;
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1237 if (player->build_audio_offload)
1238 player->no_more_pad = TRUE; /* remove state holder */
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 gst_structure_get_int(str, "rate", &samplerate);
1244 gst_structure_get_int(str, "channels", &channels);
1246 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1247 __mmplayer_gst_make_fakesink(player, pad, name);
1251 LOGD("audio selector is required");
1252 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1253 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1255 } else if (strstr(name, "text")) {
1256 LOGD("text selector is required");
1257 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1258 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1260 LOGE("invalid caps info");
1264 /* check selector and create it */
1265 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1266 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1271 LOGD("input-selector is already created.");
1275 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1277 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1279 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1280 LOGE("failed to link selector");
1281 gst_object_unref(GST_OBJECT(selector));
1286 LOGD("this track will be activated");
1287 g_object_set(selector, "active-pad", sinkpad, NULL);
1290 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1296 gst_caps_unref(caps);
1299 gst_object_unref(GST_OBJECT(sinkpad));
1307 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1309 GstPad *srcpad = NULL;
1312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1314 LOGD("type %d", type);
1317 LOGD("there is no %d track", type);
1321 srcpad = gst_element_get_static_pad(selector, "src");
1323 LOGE("failed to get srcpad from selector");
1327 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1329 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1331 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1332 if (player->selector[type].block_id) {
1333 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1334 player->selector[type].block_id = 0;
1338 gst_object_unref(GST_OBJECT(srcpad));
1347 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1349 gint active_index = 0;
1352 MMPLAYER_RETURN_IF_FAIL(player);
1354 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1356 /* change track to active pad */
1357 active_index = player->selector[type].active_pad_index;
1358 if ((active_index != DEFAULT_TRACK) &&
1359 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1360 LOGW("failed to change %d type track to %d", type, active_index);
1361 player->selector[type].active_pad_index = DEFAULT_TRACK;
1365 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1366 mm_player_set_attribute((MMHandleType)player, NULL,
1367 "content_text_track_num", player->selector[type].total_track_num,
1368 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1375 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1378 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1380 if (!audio_selector) {
1381 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1383 /* in case the source is changed, output can be changed. */
1384 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1385 LOGD("remove previous audiobin if it exist");
1387 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1388 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1390 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1391 MMPLAYER_FREEIF(player->pipeline->audiobin);
1394 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1395 __mmplayer_pipeline_complete(NULL, player);
1400 /* apply the audio track information */
1401 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1403 /* create audio sink path */
1404 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1405 LOGE("failed to create audio sink path");
1414 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1417 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1419 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1420 LOGD("text path is not supproted");
1424 /* apply the text track information */
1425 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1427 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1428 player->has_closed_caption = TRUE;
1430 /* create text decode path */
1431 player->no_more_pad = TRUE;
1433 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1434 LOGE("failed to create text sink path");
1443 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1445 gint64 dur_bytes = 0L;
1448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1449 player->pipeline->mainbin && player->streamer, FALSE);
1451 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1452 LOGE("fail to get duration.");
1454 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1455 * use file information was already set on Q2 when it was created. */
1456 _mm_player_streaming_set_queue2(player->streamer,
1457 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1458 TRUE, /* use_buffering */
1459 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1460 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1467 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1469 mmplayer_t *player = NULL;
1470 GstElement *video_selector = NULL;
1471 GstElement *audio_selector = NULL;
1472 GstElement *text_selector = NULL;
1475 player = (mmplayer_t *)data;
1477 LOGD("no-more-pad signal handling");
1479 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1480 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1481 LOGW("player is shutting down");
1485 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1486 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1487 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1488 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1489 LOGE("failed to set queue2 buffering");
1494 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1495 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1496 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1498 if (!video_selector && !audio_selector && !text_selector) {
1499 LOGW("there is no selector");
1500 player->no_more_pad = TRUE;
1504 /* create video path followed by video-select */
1505 if (video_selector && !audio_selector && !text_selector)
1506 player->no_more_pad = TRUE;
1508 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1511 /* create audio path followed by audio-select */
1512 if (audio_selector && !text_selector)
1513 player->no_more_pad = TRUE;
1515 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1518 /* create text path followed by text-select */
1519 __mmplayer_create_text_sink_path(player, text_selector);
1522 _mmplayer_set_reconfigure_state(player, FALSE);
1527 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1529 gboolean ret = FALSE;
1530 GstElement *pipeline = NULL;
1531 GstPad *sinkpad = NULL;
1534 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1537 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1539 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1541 LOGE("failed to get pad from sinkbin");
1547 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1548 LOGE("failed to link sinkbin for reusing");
1549 goto EXIT; /* exit either pass or fail */
1553 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1554 LOGE("failed to set state(READY) to sinkbin");
1559 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1560 LOGE("failed to add sinkbin to pipeline");
1565 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1566 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1571 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1572 LOGE("failed to set state(PAUSED) to sinkbin");
1581 gst_object_unref(GST_OBJECT(sinkpad));
1589 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1591 mmplayer_t *player = NULL;
1592 GstCaps *caps = NULL;
1593 gchar *caps_str = NULL;
1594 GstStructure *str = NULL;
1595 const gchar *name = NULL;
1596 GstElement *sinkbin = NULL;
1597 gboolean reusing = FALSE;
1598 gboolean caps_ret = TRUE;
1599 gchar *sink_pad_name = "sink";
1602 player = (mmplayer_t *)data;
1605 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1606 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1608 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1612 caps_str = gst_caps_to_string(caps);
1614 LOGD("detected mimetype : %s", name);
1616 if (strstr(name, "audio")) {
1617 if (player->pipeline->audiobin == NULL) {
1618 const gchar *audio_format = gst_structure_get_string(str, "format");
1620 LOGD("original audio format %s", audio_format);
1621 mm_player_set_attribute((MMHandleType)player, NULL,
1622 "content_audio_format", audio_format, strlen(audio_format), NULL);
1625 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1626 LOGE("failed to create audiobin. continuing without audio");
1630 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1631 LOGD("creating audiobin success");
1634 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1635 LOGD("reusing audiobin");
1636 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1638 } else if (strstr(name, "video")) {
1639 /* 1. zero copy is updated at _decode_pad_added()
1640 * 2. NULL surface type is handled in _decode_pad_added() */
1641 LOGD("zero copy %d", player->set_mode.video_zc);
1642 if (player->pipeline->videobin == NULL) {
1643 int surface_type = 0;
1644 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1645 LOGD("display_surface_type (%d)", surface_type);
1647 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1648 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1649 LOGE("failed to acquire video overlay resource");
1653 player->interrupted_by_resource = FALSE;
1655 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1656 LOGE("failed to create videobin. continuing without video");
1660 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1661 LOGD("creating videosink bin success");
1664 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1665 LOGD("re-using videobin");
1666 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1668 } else if (strstr(name, "text")) {
1669 if (player->pipeline->textbin == NULL) {
1670 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1671 LOGE("failed to create text sink bin. continuing without text");
1675 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1676 player->textsink_linked = 1;
1677 LOGD("creating textsink bin success");
1679 if (!player->textsink_linked) {
1680 LOGD("re-using textbin");
1682 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1683 player->textsink_linked = 1;
1685 /* linked textbin exist which means that the external subtitle path exist already */
1686 LOGW("ignoring internal subtutle since external subtitle is available");
1689 sink_pad_name = "text_sink";
1691 LOGW("unknown mime type %s, ignoring it", name);
1695 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1698 LOGD("[handle: %p] success to create and link sink bin", player);
1700 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1701 * streaming task. if the task blocked, then buffer will not flow to the next element
1702 *(autoplugging element). so this is special hack for streaming. please try to remove it
1704 /* dec stream count. we can remove fakesink if it's zero */
1705 if (player->num_dynamic_pad)
1706 player->num_dynamic_pad--;
1708 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1710 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1711 __mmplayer_pipeline_complete(NULL, player);
1715 MMPLAYER_FREEIF(caps_str);
1718 gst_caps_unref(caps);
1724 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1726 int required_angle = 0; /* Angle required for straight view */
1727 int rotation_angle = 0;
1729 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1730 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1732 /* Counter clockwise */
1733 switch (orientation) {
1738 required_angle = 270;
1741 required_angle = 180;
1744 required_angle = 90;
1748 rotation_angle = display_angle + required_angle;
1749 if (rotation_angle >= 360)
1750 rotation_angle -= 360;
1752 /* chech if supported or not */
1753 if (rotation_angle % 90) {
1754 LOGD("not supported rotation angle = %d", rotation_angle);
1758 switch (rotation_angle) {
1760 *value = MM_DISPLAY_ROTATION_NONE;
1763 *value = MM_DISPLAY_ROTATION_90;
1766 *value = MM_DISPLAY_ROTATION_180;
1769 *value = MM_DISPLAY_ROTATION_270;
1773 LOGD("setting rotation property value : %d", *value);
1779 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1781 int display_rotation = 0;
1782 gchar *org_orient = NULL;
1783 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1786 LOGE("cannot get content attribute");
1787 return MM_ERROR_PLAYER_INTERNAL;
1790 if (display_angle) {
1791 /* update user roation */
1792 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1794 /* Counter clockwise */
1795 switch (display_rotation) {
1796 case MM_DISPLAY_ROTATION_NONE:
1799 case MM_DISPLAY_ROTATION_90:
1800 *display_angle = 90;
1802 case MM_DISPLAY_ROTATION_180:
1803 *display_angle = 180;
1805 case MM_DISPLAY_ROTATION_270:
1806 *display_angle = 270;
1809 LOGW("wrong angle type : %d", display_rotation);
1812 LOGD("check user angle: %d", *display_angle);
1816 /* Counter clockwise */
1817 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1820 if (!strcmp(org_orient, "rotate-90"))
1822 else if (!strcmp(org_orient, "rotate-180"))
1824 else if (!strcmp(org_orient, "rotate-270"))
1827 LOGD("original rotation is %s", org_orient);
1829 LOGD("content_video_orientation get fail");
1832 LOGD("check orientation: %d", *orientation);
1835 return MM_ERROR_NONE;
1838 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1840 int rotation_value = 0;
1841 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1842 int display_angle = 0;
1845 /* check video sinkbin is created */
1846 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1849 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1851 /* get rotation value to set */
1852 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1853 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1854 LOGD("set video param : rotate %d", rotation_value);
1857 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1859 MMHandleType attrs = 0;
1863 /* check video sinkbin is created */
1864 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1867 attrs = MMPLAYER_GET_ATTRS(player);
1868 MMPLAYER_RETURN_IF_FAIL(attrs);
1870 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1871 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1872 LOGD("set video param : visible %d", visible);
1875 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1877 MMHandleType attrs = 0;
1878 int display_method = 0;
1881 /* check video sinkbin is created */
1882 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1885 attrs = MMPLAYER_GET_ATTRS(player);
1886 MMPLAYER_RETURN_IF_FAIL(attrs);
1888 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1889 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1890 LOGD("set video param : method %d", display_method);
1893 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1895 MMHandleType attrs = 0;
1899 /* check video sinkbin is created */
1900 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1903 attrs = MMPLAYER_GET_ATTRS(player);
1904 MMPLAYER_RETURN_IF_FAIL(attrs);
1906 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1907 MMPLAYER_RETURN_IF_FAIL(handle);
1909 gst_video_overlay_set_video_roi_area(
1910 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1912 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1913 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1916 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1918 MMHandleType attrs = 0;
1923 int win_roi_width = 0;
1924 int win_roi_height = 0;
1927 /* check video sinkbin is created */
1928 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1931 attrs = MMPLAYER_GET_ATTRS(player);
1932 MMPLAYER_RETURN_IF_FAIL(attrs);
1934 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1935 MMPLAYER_RETURN_IF_FAIL(handle);
1937 /* It should be set after setting window */
1938 mm_attrs_multiple_get(attrs, NULL,
1939 "display_win_roi_x", &win_roi_x,
1940 "display_win_roi_y", &win_roi_y,
1941 "display_win_roi_width", &win_roi_width,
1942 "display_win_roi_height", &win_roi_height, NULL);
1944 /* After setting window handle, set display roi area */
1945 gst_video_overlay_set_display_roi_area(
1946 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1948 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1949 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1952 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1954 MMHandleType attrs = 0;
1957 /* check video sinkbin is created */
1958 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1961 attrs = MMPLAYER_GET_ATTRS(player);
1962 MMPLAYER_RETURN_IF_FAIL(attrs);
1964 /* common case if using overlay surface */
1965 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1966 MMPLAYER_RETURN_IF_FAIL(handle);
1968 /* default is using wl_surface_id */
1969 LOGD("set video param : wl_surface_id %d", handle);
1970 gst_video_overlay_set_wl_window_wl_surface_id(
1971 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1976 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1978 gboolean update_all_param = FALSE;
1982 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1983 LOGW("videosink is not ready yet");
1984 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1987 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1988 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1989 return MM_ERROR_PLAYER_INTERNAL;
1992 LOGD("param_name : %s", param_name);
1993 if (!g_strcmp0(param_name, "update_all_param"))
1994 update_all_param = TRUE;
1996 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1997 __mmplayer_video_param_set_display_overlay(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1999 __mmplayer_video_param_set_display_method(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2001 __mmplayer_video_param_set_display_visible(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2003 __mmplayer_video_param_set_display_rotation(player);
2004 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2005 __mmplayer_video_param_set_roi_area(player);
2006 if (update_all_param)
2007 __mmplayer_video_param_set_video_roi_area(player);
2011 return MM_ERROR_NONE;
2015 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2017 gboolean disable_overlay = FALSE;
2018 mmplayer_t *player = (mmplayer_t *)hplayer;
2021 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2022 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2023 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2024 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2026 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2027 LOGW("Display control is not supported");
2028 return MM_ERROR_PLAYER_INTERNAL;
2031 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2033 if (audio_only == (bool)disable_overlay) {
2034 LOGE("It's the same with current setting: (%d)", audio_only);
2035 return MM_ERROR_NONE;
2039 LOGE("disable overlay");
2040 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2042 /* release overlay resource */
2043 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2044 LOGE("failed to release overlay resource");
2048 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2049 LOGE("failed to acquire video overlay resource");
2052 player->interrupted_by_resource = FALSE;
2054 LOGD("enable overlay");
2055 __mmplayer_video_param_set_display_overlay(player);
2056 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2061 return MM_ERROR_NONE;
2065 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2067 mmplayer_t *player = (mmplayer_t *)hplayer;
2068 gboolean disable_overlay = FALSE;
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2073 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2074 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2075 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2076 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2078 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2079 LOGW("Display control is not supported");
2080 return MM_ERROR_PLAYER_INTERNAL;
2083 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2085 *paudio_only = (bool)disable_overlay;
2087 LOGD("audio_only : %d", *paudio_only);
2091 return MM_ERROR_NONE;
2095 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2097 GList *bucket = element_bucket;
2098 mmplayer_gst_element_t *element = NULL;
2099 mmplayer_gst_element_t *prv_element = NULL;
2100 GstElement *tee_element = NULL;
2101 gint successful_link_count = 0;
2105 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2107 prv_element = (mmplayer_gst_element_t *)bucket->data;
2108 bucket = bucket->next;
2110 for (; bucket; bucket = bucket->next) {
2111 element = (mmplayer_gst_element_t *)bucket->data;
2113 if (element && element->gst) {
2114 if (prv_element && prv_element->gst) {
2115 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2117 prv_element->gst = tee_element;
2119 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2120 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2121 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2125 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2126 LOGD("linking [%s] to [%s] success",
2127 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2128 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2129 successful_link_count++;
2130 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2131 LOGD("keep audio-tee element for next audio pipeline branch");
2132 tee_element = prv_element->gst;
2135 LOGD("linking [%s] to [%s] failed",
2136 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2137 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2143 prv_element = element;
2148 return successful_link_count;
2152 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2154 GList *bucket = element_bucket;
2155 mmplayer_gst_element_t *element = NULL;
2156 int successful_add_count = 0;
2160 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2161 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2163 for (; bucket; bucket = bucket->next) {
2164 element = (mmplayer_gst_element_t *)bucket->data;
2166 if (element && element->gst) {
2167 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2168 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2169 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2170 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2173 successful_add_count++;
2179 return successful_add_count;
2183 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2185 mmplayer_t *player = (mmplayer_t *)data;
2186 GstCaps *caps = NULL;
2187 GstStructure *str = NULL;
2189 gboolean caps_ret = TRUE;
2193 MMPLAYER_RETURN_IF_FAIL(pad);
2194 MMPLAYER_RETURN_IF_FAIL(unused);
2195 MMPLAYER_RETURN_IF_FAIL(data);
2197 caps = gst_pad_get_current_caps(pad);
2201 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2205 LOGD("name = %s", name);
2207 if (strstr(name, "audio")) {
2208 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2210 if (player->audio_stream_changed_cb) {
2211 LOGE("call the audio stream changed cb");
2212 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2214 } else if (strstr(name, "video")) {
2215 if ((name = gst_structure_get_string(str, "format")))
2216 player->set_mode.video_zc = name[0] == 'S';
2218 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2219 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2221 LOGW("invalid caps info");
2226 gst_caps_unref(caps);
2234 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2239 MMPLAYER_RETURN_IF_FAIL(player);
2241 if (player->audio_stream_buff_list) {
2242 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2243 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2246 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2247 __mmplayer_audio_stream_send_data(player, tmp);
2249 MMPLAYER_FREEIF(tmp->pcm_data);
2250 MMPLAYER_FREEIF(tmp);
2253 g_list_free(player->audio_stream_buff_list);
2254 player->audio_stream_buff_list = NULL;
2261 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2263 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2266 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2268 audio_stream.bitrate = a_buffer->bitrate;
2269 audio_stream.channel = a_buffer->channel;
2270 audio_stream.channel_mask = a_buffer->channel_mask;
2271 audio_stream.data_size = a_buffer->data_size;
2272 audio_stream.data = a_buffer->pcm_data;
2273 audio_stream.pcm_format = a_buffer->pcm_format;
2275 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2277 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2283 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2285 mmplayer_t *player = (mmplayer_t *)data;
2286 const gchar *pcm_format = NULL;
2289 guint64 channel_mask = 0;
2290 void *a_data = NULL;
2292 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2293 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2297 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2299 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2300 a_data = mapinfo.data;
2301 a_size = mapinfo.size;
2303 GstCaps *caps = gst_pad_get_current_caps(pad);
2304 GstStructure *structure = gst_caps_get_structure(caps, 0);
2306 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2308 pcm_format = gst_structure_get_string(structure, "format");
2309 gst_structure_get_int(structure, "rate", &rate);
2310 gst_structure_get_int(structure, "channels", &channel);
2311 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2312 gst_caps_unref(GST_CAPS(caps));
2314 /* In case of the sync is false, use buffer list. *
2315 * The num of buffer list depends on the num of audio channels */
2316 if (player->audio_stream_buff_list) {
2317 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2318 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2320 if (channel_mask == tmp->channel_mask) {
2322 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2324 if (tmp->data_size + a_size < tmp->buff_size) {
2325 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2326 tmp->data_size += a_size;
2328 /* send data to client */
2329 __mmplayer_audio_stream_send_data(player, tmp);
2331 if (a_size > tmp->buff_size) {
2332 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2333 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2334 if (tmp->pcm_data == NULL) {
2335 LOGE("failed to realloc data.");
2338 tmp->buff_size = a_size;
2340 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2341 memcpy(tmp->pcm_data, a_data, a_size);
2342 tmp->data_size = a_size;
2347 LOGE("data is empty in list.");
2353 /* create new audio stream data for newly found audio channel */
2354 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2355 if (a_buffer == NULL) {
2356 LOGE("failed to alloc data.");
2359 a_buffer->bitrate = rate;
2360 a_buffer->channel = channel;
2361 a_buffer->channel_mask = channel_mask;
2362 a_buffer->data_size = a_size;
2363 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2365 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2366 /* If sync is FALSE, use buffer list to reduce the IPC. */
2367 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2368 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2369 if (a_buffer->pcm_data == NULL) {
2370 LOGE("failed to alloc data.");
2371 MMPLAYER_FREEIF(a_buffer);
2374 memcpy(a_buffer->pcm_data, a_data, a_size);
2376 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2378 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2380 /* If sync is TRUE, send data directly. */
2381 a_buffer->pcm_data = a_data;
2382 __mmplayer_audio_stream_send_data(player, a_buffer);
2383 MMPLAYER_FREEIF(a_buffer);
2387 gst_buffer_unmap(buffer, &mapinfo);
2392 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2394 mmplayer_t *player = (mmplayer_t *)data;
2395 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2396 GstPad *sinkpad = NULL;
2397 GstElement *queue = NULL, *sink = NULL;
2400 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2402 queue = gst_element_factory_make("queue", NULL);
2403 if (queue == NULL) {
2404 LOGD("fail make queue");
2408 sink = gst_element_factory_make("fakesink", NULL);
2410 LOGD("fail make fakesink");
2414 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2416 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2417 LOGW("failed to link queue & sink");
2421 sinkpad = gst_element_get_static_pad(queue, "sink");
2423 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2424 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2428 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2430 gst_object_unref(sinkpad);
2431 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2432 g_object_set(sink, "sync", TRUE, NULL);
2433 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2435 /* keep the first sink reference only */
2436 if (!audiobin[MMPLAYER_A_SINK].gst) {
2437 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2438 audiobin[MMPLAYER_A_SINK].gst = sink;
2442 _mmplayer_add_signal_connection(player,
2444 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2446 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2449 __mmplayer_add_sink(player, sink);
2451 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2452 LOGE("failed to sync state");
2456 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2457 LOGE("failed to sync state");
2465 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2467 gst_object_unref(GST_OBJECT(queue));
2471 gst_object_unref(GST_OBJECT(sink));
2475 gst_object_unref(GST_OBJECT(sinkpad));
2483 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2485 mmplayer_t *player = (mmplayer_t *)data;
2488 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2490 player->no_more_pad = TRUE;
2491 __mmplayer_pipeline_complete(NULL, player);
2498 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2500 #define MAX_PROPS_LEN 128
2501 mmplayer_gst_element_t *audiobin = NULL;
2502 gint latency_mode = 0;
2503 gchar *stream_type = NULL;
2504 gchar *latency = NULL;
2506 gchar stream_props[MAX_PROPS_LEN] = {0,};
2507 GstStructure *props = NULL;
2510 * It should be set after player creation through attribute.
2511 * But, it can not be changed during playing.
2514 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2516 audiobin = player->pipeline->audiobin;
2518 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2519 if (player->sound.mute) {
2520 LOGD("mute enabled");
2521 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2524 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2525 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2528 snprintf(stream_props, sizeof(stream_props) - 1,
2529 "props,application.process.id.origin=%d", player->client_pid);
2531 snprintf(stream_props, sizeof(stream_props) - 1,
2532 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2533 stream_type, stream_id, player->client_pid);
2535 props = gst_structure_from_string(stream_props, NULL);
2536 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2537 LOGI("props result[%s].", stream_props);
2538 gst_structure_free(props);
2540 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2542 switch (latency_mode) {
2543 case AUDIO_LATENCY_MODE_LOW:
2544 latency = g_strdup("low");
2546 case AUDIO_LATENCY_MODE_MID:
2547 latency = g_strdup("mid");
2549 case AUDIO_LATENCY_MODE_HIGH:
2550 latency = g_strdup("high");
2553 latency = g_strdup("mid");
2557 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2559 LOGD("audiosink property - latency=%s", latency);
2561 MMPLAYER_FREEIF(latency);
2567 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2569 mmplayer_gst_element_t *audiobin = NULL;
2572 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2574 audiobin = player->pipeline->audiobin;
2576 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2577 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2578 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2580 if (player->video360_yaw_radians <= M_PI &&
2581 player->video360_yaw_radians >= -M_PI &&
2582 player->video360_pitch_radians <= M_PI_2 &&
2583 player->video360_pitch_radians >= -M_PI_2) {
2584 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2585 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2586 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2587 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2588 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2589 "source-orientation-y", player->video360_metadata.init_view_heading,
2590 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2597 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2599 mmplayer_gst_element_t *audiobin = NULL;
2600 GstPad *sink_pad = NULL;
2601 GstCaps *acaps = NULL;
2603 int pitch_control = 0;
2604 double pitch_value = 1.0;
2607 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2608 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2610 audiobin = player->pipeline->audiobin;
2612 LOGD("make element for normal audio playback");
2614 /* audio bin structure for playback. {} means optional.
2615 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2617 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2618 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2621 /* for pitch control */
2622 mm_attrs_multiple_get(player->attrs, NULL,
2623 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2624 MM_PLAYER_PITCH_VALUE, &pitch_value,
2627 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2628 if (pitch_control && (player->videodec_linked == 0)) {
2629 GstElementFactory *factory;
2631 factory = gst_element_factory_find("pitch");
2633 gst_object_unref(factory);
2636 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2639 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2640 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2642 LOGW("there is no pitch element");
2647 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2649 /* replaygain volume */
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2651 if (player->sound.rg_enable)
2652 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2654 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2657 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2659 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2660 /* currently, only openalsink uses volume element */
2661 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2664 if (player->sound.mute) {
2665 LOGD("mute enabled");
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2670 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2672 /* audio effect element. if audio effect is enabled */
2673 if ((strcmp(player->ini.audioeffect_element, ""))
2675 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2676 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2678 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2680 if ((!player->bypass_audio_effect)
2681 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2682 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2683 if (!_mmplayer_audio_effect_custom_apply(player))
2684 LOGI("apply audio effect(custom) setting success");
2688 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2689 && (player->set_mode.rich_audio)) {
2690 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2694 /* create audio sink */
2695 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2696 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2697 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2699 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2700 if (player->is_360_feature_enabled &&
2701 player->is_content_spherical &&
2703 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2704 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2705 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2707 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2709 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2712 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2713 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2714 gst_caps_unref(acaps);
2716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2718 player->is_openal_plugin_used = TRUE;
2720 if (player->is_360_feature_enabled && player->is_content_spherical)
2721 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2725 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2726 (player->videodec_linked && player->ini.use_system_clock)) {
2727 LOGD("system clock will be used.");
2728 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2731 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2732 __mmplayer_gst_set_pulsesink_property(player);
2733 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2734 __mmplayer_gst_set_openalsink_property(player);
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2738 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2740 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2741 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2742 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2743 gst_object_unref(GST_OBJECT(sink_pad));
2745 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2748 return MM_ERROR_NONE;
2750 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2752 return MM_ERROR_PLAYER_INTERNAL;
2756 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2758 mmplayer_gst_element_t *audiobin = NULL;
2759 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2761 gchar *dst_format = NULL;
2763 int dst_samplerate = 0;
2764 int dst_channels = 0;
2765 GstCaps *caps = NULL;
2766 char *caps_str = NULL;
2769 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2770 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2772 audiobin = player->pipeline->audiobin;
2774 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2776 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2778 [case 1] extract interleave audio pcm without playback
2779 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2780 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2782 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2784 [case 2] deinterleave for each channel without playback
2785 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2786 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2788 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2789 - fakesink (sync or not)
2792 [case 3] [case 1(sync only)] + playback
2793 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2795 * src - ... - tee - queue1 - playback path
2796 - queue2 - [case1 pipeline with sync]
2798 [case 4] [case 2(sync only)] + playback
2799 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2801 * src - ... - tee - queue1 - playback path
2802 - queue2 - [case2 pipeline with sync]
2806 /* 1. create tee and playback path
2807 'tee' should be added at first to copy the decoded stream
2809 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2810 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2811 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2813 /* tee - path 1 : for playback path */
2814 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2815 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2817 /* tee - path 2 : for extract path */
2818 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2819 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2822 /* if there is tee, 'tee - path 2' is linked here */
2824 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2827 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2829 /* 2. decide the extract pcm format */
2830 mm_attrs_multiple_get(player->attrs, NULL,
2831 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2832 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2833 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2836 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2837 dst_format, dst_len, dst_samplerate, dst_channels);
2839 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2840 mm_attrs_multiple_get(player->attrs, NULL,
2841 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2842 "content_audio_samplerate", &dst_samplerate,
2843 "content_audio_channels", &dst_channels,
2846 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2847 dst_format, dst_len, dst_samplerate, dst_channels);
2849 /* If there is no enough information, set it to platform default value. */
2850 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2851 LOGD("set platform default format");
2852 dst_format = DEFAULT_PCM_OUT_FORMAT;
2854 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2855 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2858 /* 3. create capsfilter */
2859 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2860 caps = gst_caps_new_simple("audio/x-raw",
2861 "format", G_TYPE_STRING, dst_format,
2862 "rate", G_TYPE_INT, dst_samplerate,
2863 "channels", G_TYPE_INT, dst_channels,
2866 caps_str = gst_caps_to_string(caps);
2867 LOGD("new caps : %s", caps_str);
2869 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2872 gst_caps_unref(caps);
2873 MMPLAYER_FREEIF(caps_str);
2875 /* 4-1. create deinterleave to extract pcm for each channel */
2876 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2877 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2878 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2880 /* audiosink will be added after getting signal for each channel */
2881 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2882 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2883 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2884 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2885 player->no_more_pad = FALSE;
2887 /* 4-2. create fakesink to extract interlevaed pcm */
2888 LOGD("add audio fakesink for interleaved audio");
2889 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2890 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2891 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2892 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2894 _mmplayer_add_signal_connection(player,
2895 G_OBJECT(audiobin[extract_sink_id].gst),
2896 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2898 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2901 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2905 return MM_ERROR_NONE;
2907 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2909 return MM_ERROR_PLAYER_INTERNAL;
2913 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2915 int ret = MM_ERROR_NONE;
2916 mmplayer_gst_element_t *audiobin = NULL;
2917 GList *element_bucket = NULL;
2920 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2921 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2923 audiobin = player->pipeline->audiobin;
2925 if (player->build_audio_offload) { /* skip all the audio filters */
2926 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2928 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2929 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2930 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2932 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2936 /* FIXME: need to mention the supportable condition at API reference */
2937 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2938 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2940 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2942 if (ret != MM_ERROR_NONE)
2945 LOGD("success to make audio bin element");
2946 *bucket = element_bucket;
2949 return MM_ERROR_NONE;
2952 LOGE("failed to make audio bin element");
2953 g_list_free(element_bucket);
2957 return MM_ERROR_PLAYER_INTERNAL;
2961 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2963 mmplayer_gst_element_t *first_element = NULL;
2964 mmplayer_gst_element_t *audiobin = NULL;
2966 GstPad *ghostpad = NULL;
2967 GList *element_bucket = NULL;
2971 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2974 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2976 LOGE("failed to allocate memory for audiobin");
2977 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2981 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2982 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2983 if (!audiobin[MMPLAYER_A_BIN].gst) {
2984 LOGE("failed to create audiobin");
2989 player->pipeline->audiobin = audiobin;
2991 /* create audio filters and audiosink */
2992 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2995 /* adding created elements to bin */
2996 LOGD("adding created elements to bin");
2997 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3000 /* linking elements in the bucket by added order. */
3001 LOGD("Linking elements in the bucket by added order.");
3002 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3005 /* get first element's sinkpad for creating ghostpad */
3006 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3007 if (!first_element) {
3008 LOGE("failed to get first elem");
3012 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3014 LOGE("failed to get pad from first element of audiobin");
3018 ghostpad = gst_ghost_pad_new("sink", pad);
3020 LOGE("failed to create ghostpad");
3024 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3025 LOGE("failed to add ghostpad to audiobin");
3029 gst_object_unref(pad);
3031 g_list_free(element_bucket);
3034 return MM_ERROR_NONE;
3037 LOGD("ERROR : releasing audiobin");
3040 gst_object_unref(GST_OBJECT(pad));
3043 gst_object_unref(GST_OBJECT(ghostpad));
3046 g_list_free(element_bucket);
3048 /* release element which are not added to bin */
3049 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3050 /* NOTE : skip bin */
3051 if (audiobin[i].gst) {
3052 GstObject *parent = NULL;
3053 parent = gst_element_get_parent(audiobin[i].gst);
3056 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3057 audiobin[i].gst = NULL;
3059 gst_object_unref(GST_OBJECT(parent));
3063 /* release audiobin with it's childs */
3064 if (audiobin[MMPLAYER_A_BIN].gst)
3065 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3067 MMPLAYER_FREEIF(audiobin);
3069 player->pipeline->audiobin = NULL;
3071 return MM_ERROR_PLAYER_INTERNAL;
3075 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3077 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3081 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3083 int ret = MM_ERROR_NONE;
3085 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3086 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3088 MMPLAYER_VIDEO_BO_LOCK(player);
3090 if (player->video_bo_list) {
3091 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3092 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3093 if (tmp && tmp->bo == bo) {
3095 LOGD("release bo %p", bo);
3096 tbm_bo_unref(tmp->bo);
3097 MMPLAYER_VIDEO_BO_UNLOCK(player);
3098 MMPLAYER_VIDEO_BO_SIGNAL(player);
3103 /* hw codec is running or the list was reset for DRC. */
3104 LOGW("there is no bo list.");
3106 MMPLAYER_VIDEO_BO_UNLOCK(player);
3108 LOGW("failed to find bo %p", bo);
3113 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3118 MMPLAYER_RETURN_IF_FAIL(player);
3120 MMPLAYER_VIDEO_BO_LOCK(player);
3121 if (player->video_bo_list) {
3122 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3123 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3124 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3127 tbm_bo_unref(tmp->bo);
3131 g_list_free(player->video_bo_list);
3132 player->video_bo_list = NULL;
3134 player->video_bo_size = 0;
3135 MMPLAYER_VIDEO_BO_UNLOCK(player);
3142 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3145 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3146 gboolean ret = TRUE;
3148 /* check DRC, if it is, destroy the prev bo list to create again */
3149 if (player->video_bo_size != size) {
3150 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3151 __mmplayer_video_stream_destroy_bo_list(player);
3152 player->video_bo_size = size;
3155 MMPLAYER_VIDEO_BO_LOCK(player);
3157 if ((!player->video_bo_list) ||
3158 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3160 /* create bo list */
3162 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3164 if (player->video_bo_list) {
3165 /* if bo list did not created all, try it again. */
3166 idx = g_list_length(player->video_bo_list);
3167 LOGD("bo list exist(len: %d)", idx);
3170 for (; idx < player->ini.num_of_video_bo; idx++) {
3171 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3173 LOGE("Fail to alloc bo_info.");
3176 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3178 LOGE("Fail to tbm_bo_alloc.");
3179 MMPLAYER_FREEIF(bo_info);
3182 bo_info->used = FALSE;
3183 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3186 /* update video num buffers */
3187 LOGD("video_num_buffers : %d", idx);
3188 mm_player_set_attribute((MMHandleType)player, NULL,
3189 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3190 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3194 MMPLAYER_VIDEO_BO_UNLOCK(player);
3200 /* get bo from list*/
3201 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3202 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3203 if (tmp && (tmp->used == FALSE)) {
3204 LOGD("found bo %p to use", tmp->bo);
3206 MMPLAYER_VIDEO_BO_UNLOCK(player);
3207 return tbm_bo_ref(tmp->bo);
3211 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3212 MMPLAYER_VIDEO_BO_UNLOCK(player);
3216 if (player->ini.video_bo_timeout <= 0) {
3217 MMPLAYER_VIDEO_BO_WAIT(player);
3219 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3220 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3227 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3229 mmplayer_t *player = (mmplayer_t *)data;
3231 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3233 /* send prerolled pkt */
3234 player->video_stream_prerolled = false;
3236 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3238 /* not to send prerolled pkt again */
3239 player->video_stream_prerolled = true;
3243 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3245 mmplayer_t *player = (mmplayer_t *)data;
3246 mmplayer_video_decoded_data_info_t *stream = NULL;
3247 GstMemory *mem = NULL;
3250 MMPLAYER_RETURN_IF_FAIL(player);
3251 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3253 if (player->video_stream_prerolled) {
3254 player->video_stream_prerolled = false;
3255 LOGD("skip the prerolled pkt not to send it again");
3259 /* clear stream data structure */
3260 stream = __mmplayer_create_stream_from_pad(pad);
3262 LOGE("failed to alloc stream");
3266 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3268 /* set size and timestamp */
3269 mem = gst_buffer_peek_memory(buffer, 0);
3270 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3271 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3273 /* check zero-copy */
3274 if (player->set_mode.video_zc &&
3275 player->set_mode.video_export &&
3276 gst_is_tizen_memory(mem)) {
3277 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3278 stream->internal_buffer = gst_buffer_ref(buffer);
3279 } else { /* sw codec */
3280 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3283 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3287 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3288 LOGE("failed to send video decoded data.");
3295 LOGE("release video stream resource.");
3296 if (gst_is_tizen_memory(mem)) {
3298 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3300 tbm_bo_unref(stream->bo[i]);
3303 /* unref gst buffer */
3304 if (stream->internal_buffer)
3305 gst_buffer_unref(stream->internal_buffer);
3308 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3310 MMPLAYER_FREEIF(stream);
3315 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3317 mmplayer_gst_element_t *videobin = NULL;
3320 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3322 videobin = player->pipeline->videobin;
3324 /* Set spatial media metadata and/or user settings to the element.
3326 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3327 "projection-type", player->video360_metadata.projection_type, NULL);
3329 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3330 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3332 if (player->video360_metadata.full_pano_width_pixels &&
3333 player->video360_metadata.full_pano_height_pixels &&
3334 player->video360_metadata.cropped_area_image_width &&
3335 player->video360_metadata.cropped_area_image_height) {
3336 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3337 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3338 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3339 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3340 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3341 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3342 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3346 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3347 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3348 "horizontal-fov", player->video360_horizontal_fov,
3349 "vertical-fov", player->video360_vertical_fov, NULL);
3352 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3353 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3354 "zoom", 1.0f / player->video360_zoom, NULL);
3357 if (player->video360_yaw_radians <= M_PI &&
3358 player->video360_yaw_radians >= -M_PI &&
3359 player->video360_pitch_radians <= M_PI_2 &&
3360 player->video360_pitch_radians >= -M_PI_2) {
3361 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3362 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3363 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3364 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "pose-yaw", player->video360_metadata.init_view_heading,
3367 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3370 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3371 "passthrough", !player->is_video360_enabled, NULL);
3378 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3380 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3381 GList *element_bucket = NULL;
3384 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3386 /* create video360 filter */
3387 if (player->is_360_feature_enabled && player->is_content_spherical) {
3388 LOGD("create video360 element");
3389 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3390 __mmplayer_gst_set_video360_property(player);
3394 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3395 LOGD("skip creating the videoconv and rotator");
3396 return MM_ERROR_NONE;
3399 /* in case of sw codec & overlay surface type, except 360 playback.
3400 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3401 LOGD("create video converter: %s", video_csc);
3402 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3405 *bucket = element_bucket;
3407 return MM_ERROR_NONE;
3409 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3410 g_list_free(element_bucket);
3414 return MM_ERROR_PLAYER_INTERNAL;
3418 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3420 gchar *factory_name = NULL;
3422 switch (surface_type) {
3423 case MM_DISPLAY_SURFACE_OVERLAY:
3424 if (strlen(player->ini.videosink_element_overlay) > 0)
3425 factory_name = player->ini.videosink_element_overlay;
3427 case MM_DISPLAY_SURFACE_REMOTE:
3428 case MM_DISPLAY_SURFACE_NULL:
3429 if (strlen(player->ini.videosink_element_fake) > 0)
3430 factory_name = player->ini.videosink_element_fake;
3433 LOGE("unidentified surface type");
3437 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3438 return factory_name;
3442 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3444 gchar *factory_name = NULL;
3445 mmplayer_gst_element_t *videobin = NULL;
3450 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3452 videobin = player->pipeline->videobin;
3453 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3455 attrs = MMPLAYER_GET_ATTRS(player);
3457 LOGE("cannot get content attribute");
3458 return MM_ERROR_PLAYER_INTERNAL;
3461 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3462 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3463 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3464 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3465 "use-tbm", use_tbm, NULL);
3468 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3469 return MM_ERROR_PLAYER_INTERNAL;
3471 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3474 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3475 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3478 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3480 LOGD("disable last-sample");
3481 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3484 if (player->set_mode.video_export) {
3486 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3487 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3488 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3490 _mmplayer_add_signal_connection(player,
3491 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3492 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3494 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3497 _mmplayer_add_signal_connection(player,
3498 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3499 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3501 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3505 if (videobin[MMPLAYER_V_SINK].gst) {
3506 GstPad *sink_pad = NULL;
3507 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3509 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3510 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3511 gst_object_unref(GST_OBJECT(sink_pad));
3513 LOGE("failed to get sink pad from videosink");
3517 return MM_ERROR_NONE;
3522 * - video overlay surface(arm/x86) : tizenwlsink
3525 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3528 GList *element_bucket = NULL;
3529 mmplayer_gst_element_t *first_element = NULL;
3530 mmplayer_gst_element_t *videobin = NULL;
3531 gchar *videosink_factory_name = NULL;
3534 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3537 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3539 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3541 player->pipeline->videobin = videobin;
3544 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3545 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3546 if (!videobin[MMPLAYER_V_BIN].gst) {
3547 LOGE("failed to create videobin");
3551 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3554 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3555 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3557 /* additional setting for sink plug-in */
3558 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3559 LOGE("failed to set video property");
3563 /* store it as it's sink element */
3564 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3566 /* adding created elements to bin */
3567 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3568 LOGE("failed to add elements");
3572 /* Linking elements in the bucket by added order */
3573 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3574 LOGE("failed to link elements");
3578 /* get first element's sinkpad for creating ghostpad */
3579 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3580 if (!first_element) {
3581 LOGE("failed to get first element from bucket");
3585 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3587 LOGE("failed to get pad from first element");
3591 /* create ghostpad */
3592 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3593 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3594 LOGE("failed to add ghostpad to videobin");
3597 gst_object_unref(pad);
3599 /* done. free allocated variables */
3600 g_list_free(element_bucket);
3604 return MM_ERROR_NONE;
3607 LOGE("ERROR : releasing videobin");
3608 g_list_free(element_bucket);
3611 gst_object_unref(GST_OBJECT(pad));
3613 /* release videobin with it's childs */
3614 if (videobin[MMPLAYER_V_BIN].gst)
3615 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3617 MMPLAYER_FREEIF(videobin);
3618 player->pipeline->videobin = NULL;
3620 return MM_ERROR_PLAYER_INTERNAL;
3624 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3626 GList *element_bucket = NULL;
3627 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3629 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3630 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3631 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3632 "signal-handoffs", FALSE,
3635 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3636 _mmplayer_add_signal_connection(player,
3637 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3638 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3640 G_CALLBACK(__mmplayer_update_subtitle),
3643 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3644 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3646 if (!player->play_subtitle) {
3647 LOGD("add textbin sink as sink element of whole pipeline.");
3648 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3651 /* adding created elements to bin */
3652 LOGD("adding created elements to bin");
3653 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3654 LOGE("failed to add elements");
3658 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3659 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3660 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3662 /* linking elements in the bucket by added order. */
3663 LOGD("Linking elements in the bucket by added order.");
3664 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3665 LOGE("failed to link elements");
3669 /* done. free allocated variables */
3670 g_list_free(element_bucket);
3672 if (textbin[MMPLAYER_T_QUEUE].gst) {
3674 GstPad *ghostpad = NULL;
3676 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3678 LOGE("failed to get sink pad of text queue");
3682 ghostpad = gst_ghost_pad_new("text_sink", pad);
3683 gst_object_unref(pad);
3686 LOGE("failed to create ghostpad of textbin");
3690 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3691 LOGE("failed to add ghostpad to textbin");
3692 gst_object_unref(ghostpad);
3697 return MM_ERROR_NONE;
3700 g_list_free(element_bucket);
3702 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3703 LOGE("remove textbin sink from sink list");
3704 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3707 /* release element at __mmplayer_gst_create_text_sink_bin */
3708 return MM_ERROR_PLAYER_INTERNAL;
3712 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3714 mmplayer_gst_element_t *textbin = NULL;
3715 GList *element_bucket = NULL;
3716 int surface_type = 0;
3721 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3724 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3726 LOGE("failed to allocate memory for textbin");
3727 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3731 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3732 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3733 if (!textbin[MMPLAYER_T_BIN].gst) {
3734 LOGE("failed to create textbin");
3739 player->pipeline->textbin = textbin;
3742 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3743 LOGD("surface type for subtitle : %d", surface_type);
3744 switch (surface_type) {
3745 case MM_DISPLAY_SURFACE_OVERLAY:
3746 case MM_DISPLAY_SURFACE_NULL:
3747 case MM_DISPLAY_SURFACE_REMOTE:
3748 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3749 LOGE("failed to make plain text elements");
3760 return MM_ERROR_NONE;
3764 LOGD("ERROR : releasing textbin");
3766 g_list_free(element_bucket);
3768 /* release signal */
3769 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3771 /* release element which are not added to bin */
3772 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3773 /* NOTE : skip bin */
3774 if (textbin[i].gst) {
3775 GstObject *parent = NULL;
3776 parent = gst_element_get_parent(textbin[i].gst);
3779 gst_object_unref(GST_OBJECT(textbin[i].gst));
3780 textbin[i].gst = NULL;
3782 gst_object_unref(GST_OBJECT(parent));
3787 /* release textbin with it's childs */
3788 if (textbin[MMPLAYER_T_BIN].gst)
3789 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3791 MMPLAYER_FREEIF(textbin);
3792 player->pipeline->textbin = NULL;
3795 return MM_ERROR_PLAYER_INTERNAL;
3799 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3801 mmplayer_gst_element_t *mainbin = NULL;
3802 mmplayer_gst_element_t *textbin = NULL;
3803 MMHandleType attrs = 0;
3804 GstElement *subsrc = NULL;
3805 GstElement *subparse = NULL;
3806 gchar *subtitle_uri = NULL;
3807 const gchar *charset = NULL;
3813 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3815 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3817 mainbin = player->pipeline->mainbin;
3819 attrs = MMPLAYER_GET_ATTRS(player);
3821 LOGE("cannot get content attribute");
3822 return MM_ERROR_PLAYER_INTERNAL;
3825 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3826 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3827 LOGE("subtitle uri is not proper filepath.");
3828 return MM_ERROR_PLAYER_INVALID_URI;
3831 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3832 LOGE("failed to get storage info of subtitle path");
3833 return MM_ERROR_PLAYER_INVALID_URI;
3836 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3838 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3839 player->subtitle_language_list = NULL;
3840 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3842 /* create the subtitle source */
3843 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3845 LOGE("failed to create filesrc element");
3848 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3850 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3851 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3853 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3854 LOGW("failed to add queue");
3855 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3856 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3857 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3862 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3864 LOGE("failed to create subparse element");
3868 charset = _mmplayer_get_charset(subtitle_uri);
3870 LOGD("detected charset is %s", charset);
3871 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3874 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3875 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3877 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3878 LOGW("failed to add subparse");
3879 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3880 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3881 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3885 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3886 LOGW("failed to link subsrc and subparse");
3890 player->play_subtitle = TRUE;
3891 player->adjust_subtitle_pos = 0;
3893 LOGD("play subtitle using subtitle file");
3895 if (player->pipeline->textbin == NULL) {
3896 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3897 LOGE("failed to create text sink bin. continuing without text");
3901 textbin = player->pipeline->textbin;
3903 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3904 LOGW("failed to add textbin");
3906 /* release signal */
3907 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3909 /* release textbin with it's childs */
3910 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3911 MMPLAYER_FREEIF(player->pipeline->textbin);
3912 player->pipeline->textbin = textbin = NULL;
3916 LOGD("link text input selector and textbin ghost pad");
3918 player->textsink_linked = 1;
3919 player->external_text_idx = 0;
3920 LOGI("textsink is linked");
3922 textbin = player->pipeline->textbin;
3923 LOGD("text bin has been created. reuse it.");
3924 player->external_text_idx = 1;
3927 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3928 LOGW("failed to link subparse and textbin");
3932 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3934 LOGE("failed to get sink pad from textsink to probe data");
3938 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3939 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3941 gst_object_unref(pad);
3944 /* create dot. for debugging */
3945 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3948 return MM_ERROR_NONE;
3951 /* release text pipeline resource */
3952 player->textsink_linked = 0;
3954 /* release signal */
3955 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3957 if (player->pipeline->textbin) {
3958 LOGE("remove textbin");
3960 /* release textbin with it's childs */
3961 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3962 MMPLAYER_FREEIF(player->pipeline->textbin);
3963 player->pipeline->textbin = NULL;
3967 /* release subtitle elem */
3968 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3969 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3971 return MM_ERROR_PLAYER_INTERNAL;
3975 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3977 mmplayer_t *player = (mmplayer_t *)data;
3978 MMMessageParamType msg = {0, };
3979 GstClockTime duration = 0;
3980 gpointer text = NULL;
3981 guint text_size = 0;
3982 gboolean ret = TRUE;
3983 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3987 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3988 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3990 if (player->is_subtitle_force_drop) {
3991 LOGW("subtitle is dropped forcedly.");
3995 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3996 text = mapinfo.data;
3997 text_size = mapinfo.size;
3999 if (player->set_mode.subtitle_off) {
4000 LOGD("subtitle is OFF.");
4004 if (!text || (text_size == 0)) {
4005 LOGD("There is no subtitle to be displayed.");
4009 msg.data = (void *)text;
4011 duration = GST_BUFFER_DURATION(buffer);
4013 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4014 if (player->duration > GST_BUFFER_PTS(buffer))
4015 duration = player->duration - GST_BUFFER_PTS(buffer);
4018 LOGI("subtitle duration is invalid, subtitle duration change "
4019 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4021 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4023 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4025 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4026 gst_buffer_unmap(buffer, &mapinfo);
4033 static GstPadProbeReturn
4034 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4036 mmplayer_t *player = (mmplayer_t *)u_data;
4037 GstClockTime cur_timestamp = 0;
4038 gint64 adjusted_timestamp = 0;
4039 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4041 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4043 if (player->set_mode.subtitle_off) {
4044 LOGD("subtitle is OFF.");
4048 if (player->adjust_subtitle_pos == 0) {
4049 LOGD("nothing to do");
4053 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4054 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4056 if (adjusted_timestamp < 0) {
4057 LOGD("adjusted_timestamp under zero");
4062 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4063 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4064 GST_TIME_ARGS(cur_timestamp),
4065 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4067 return GST_PAD_PROBE_OK;
4071 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4075 /* check player and subtitlebin are created */
4076 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4077 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4079 if (position == 0) {
4080 LOGD("nothing to do");
4082 return MM_ERROR_NONE;
4085 /* check current postion */
4086 player->adjust_subtitle_pos = position;
4088 LOGD("save adjust_subtitle_pos in player");
4092 return MM_ERROR_NONE;
4096 * This function is to create audio or video pipeline for playing.
4098 * @param player [in] handle of player
4100 * @return This function returns zero on success.
4105 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4107 int ret = MM_ERROR_NONE;
4108 mmplayer_gst_element_t *mainbin = NULL;
4109 MMHandleType attrs = 0;
4112 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4114 /* get profile attribute */
4115 attrs = MMPLAYER_GET_ATTRS(player);
4117 LOGE("failed to get content attribute");
4121 /* create pipeline handles */
4122 if (player->pipeline) {
4123 LOGE("pipeline should be released before create new one");
4127 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4129 /* create mainbin */
4130 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4131 if (mainbin == NULL)
4134 /* create pipeline */
4135 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4136 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4137 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4138 LOGE("failed to create pipeline");
4143 player->pipeline->mainbin = mainbin;
4145 /* create the source and decoder elements */
4146 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4147 ret = _mmplayer_gst_build_es_pipeline(player);
4149 ret = _mmplayer_gst_build_pipeline(player);
4151 if (ret != MM_ERROR_NONE) {
4152 LOGE("failed to create some elements");
4156 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4157 if (__mmplayer_check_subtitle(player)
4158 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4159 LOGE("failed to create text pipeline");
4162 ret = _mmplayer_gst_add_bus_watch(player);
4163 if (ret != MM_ERROR_NONE) {
4164 LOGE("failed to add bus watch");
4169 return MM_ERROR_NONE;
4172 __mmplayer_gst_destroy_pipeline(player);
4173 return MM_ERROR_PLAYER_INTERNAL;
4177 __mmplayer_reset_gapless_state(mmplayer_t *player)
4180 MMPLAYER_RETURN_IF_FAIL(player
4182 && player->pipeline->audiobin
4183 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4185 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4192 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4195 int ret = MM_ERROR_NONE;
4199 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4201 /* cleanup stuffs */
4202 MMPLAYER_FREEIF(player->type);
4203 player->no_more_pad = FALSE;
4204 player->num_dynamic_pad = 0;
4205 player->demux_pad_index = 0;
4207 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4208 player->subtitle_language_list = NULL;
4209 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4211 MMPLAYER_RECONFIGURE_LOCK(player);
4212 __mmplayer_reset_gapless_state(player);
4213 MMPLAYER_RECONFIGURE_UNLOCK(player);
4215 if (player->streamer) {
4216 _mm_player_streaming_initialize(player->streamer, FALSE);
4217 _mm_player_streaming_destroy(player->streamer);
4218 player->streamer = NULL;
4221 /* cleanup unlinked mime type */
4222 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4223 MMPLAYER_FREEIF(player->unlinked_video_mime);
4224 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4226 /* cleanup running stuffs */
4227 _mmplayer_cancel_eos_timer(player);
4229 /* cleanup gst stuffs */
4230 if (player->pipeline) {
4231 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4232 GstTagList *tag_list = player->pipeline->tag_list;
4234 /* first we need to disconnect all signal hander */
4235 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4238 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4239 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4240 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4241 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4242 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4243 gst_object_unref(bus);
4245 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4246 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4247 if (ret != MM_ERROR_NONE) {
4248 LOGE("fail to change state to NULL");
4249 return MM_ERROR_PLAYER_INTERNAL;
4252 LOGW("succeeded in changing state to NULL");
4254 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4257 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4258 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4260 /* free avsysaudiosink
4261 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4262 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4264 MMPLAYER_FREEIF(audiobin);
4265 MMPLAYER_FREEIF(videobin);
4266 MMPLAYER_FREEIF(textbin);
4267 MMPLAYER_FREEIF(mainbin);
4271 gst_tag_list_unref(tag_list);
4273 MMPLAYER_FREEIF(player->pipeline);
4275 MMPLAYER_FREEIF(player->album_art);
4277 if (player->v_stream_caps) {
4278 gst_caps_unref(player->v_stream_caps);
4279 player->v_stream_caps = NULL;
4282 if (player->a_stream_caps) {
4283 gst_caps_unref(player->a_stream_caps);
4284 player->a_stream_caps = NULL;
4287 if (player->s_stream_caps) {
4288 gst_caps_unref(player->s_stream_caps);
4289 player->s_stream_caps = NULL;
4291 _mmplayer_track_destroy(player);
4293 if (player->sink_elements)
4294 g_list_free(player->sink_elements);
4295 player->sink_elements = NULL;
4297 if (player->bufmgr) {
4298 tbm_bufmgr_deinit(player->bufmgr);
4299 player->bufmgr = NULL;
4302 LOGW("finished destroy pipeline");
4310 __mmplayer_gst_realize(mmplayer_t *player)
4313 int ret = MM_ERROR_NONE;
4317 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4319 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4321 ret = __mmplayer_gst_create_pipeline(player);
4323 LOGE("failed to create pipeline");
4327 /* set pipeline state to READY */
4328 /* NOTE : state change to READY must be performed sync. */
4329 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4330 ret = _mmplayer_gst_set_state(player,
4331 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4333 if (ret != MM_ERROR_NONE) {
4334 /* return error if failed to set state */
4335 LOGE("failed to set READY state");
4339 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4341 /* create dot before error-return. for debugging */
4342 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4350 __mmplayer_gst_unrealize(mmplayer_t *player)
4352 int ret = MM_ERROR_NONE;
4356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4358 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4359 MMPLAYER_PRINT_STATE(player);
4361 /* release miscellaneous information */
4362 __mmplayer_release_misc(player);
4364 /* destroy pipeline */
4365 ret = __mmplayer_gst_destroy_pipeline(player);
4366 if (ret != MM_ERROR_NONE) {
4367 LOGE("failed to destory pipeline");
4371 /* release miscellaneous information.
4372 these info needs to be released after pipeline is destroyed. */
4373 __mmplayer_release_misc_post(player);
4375 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4383 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4388 LOGW("set_message_callback is called with invalid player handle");
4389 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4392 player->msg_cb = callback;
4393 player->msg_cb_param = user_param;
4395 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4399 return MM_ERROR_NONE;
4403 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4405 int ret = MM_ERROR_NONE;
4410 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4411 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4412 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4414 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4416 if (strstr(uri, "es_buff://")) {
4417 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4418 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4419 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4420 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4422 tmp = g_ascii_strdown(uri, strlen(uri));
4423 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4424 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4426 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4428 } else if (strstr(uri, "mms://")) {
4429 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4430 } else if ((path = strstr(uri, "mem://"))) {
4431 ret = __mmplayer_set_mem_uri(data, path, param);
4433 ret = __mmplayer_set_file_uri(data, uri);
4436 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4437 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4438 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4439 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4441 /* dump parse result */
4442 SECURE_LOGW("incoming uri : %s", uri);
4443 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4444 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4452 __mmplayer_can_do_interrupt(mmplayer_t *player)
4454 if (!player || !player->pipeline || !player->attrs) {
4455 LOGW("not initialized");
4459 if (player->audio_decoded_cb) {
4460 LOGW("not support in pcm extraction mode");
4464 /* check if seeking */
4465 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4466 MMMessageParamType msg_param;
4467 memset(&msg_param, 0, sizeof(MMMessageParamType));
4468 msg_param.code = MM_ERROR_PLAYER_SEEK;
4469 player->seek_state = MMPLAYER_SEEK_NONE;
4470 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4474 /* check other thread */
4475 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4476 LOGW("locked already, cmd state : %d", player->cmd);
4478 /* check application command */
4479 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4480 LOGW("playing.. should wait cmd lock then, will be interrupted");
4482 /* lock will be released at mrp_resource_release_cb() */
4483 MMPLAYER_CMD_LOCK(player);
4486 LOGW("nothing to do");
4489 LOGW("can interrupt immediately");
4493 FAILED: /* with CMD UNLOCKED */
4496 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4501 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4504 mmplayer_t *player = NULL;
4505 MMMessageParamType msg = {0, };
4507 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4512 LOGE("user_data is null");
4515 player = (mmplayer_t *)user_data;
4517 if (!__mmplayer_can_do_interrupt(player)) {
4518 LOGW("no need to interrupt, so leave");
4519 /* FIXME: there is no way to avoid releasing resource. */
4523 player->interrupted_by_resource = TRUE;
4525 /* get last play position */
4526 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4527 msg.union_type = MM_MSG_UNION_TIME;
4528 msg.time.elapsed = pos;
4529 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4531 LOGW("failed to get play position.");
4534 LOGD("video resource conflict so, resource will be freed by unrealizing");
4535 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4536 LOGE("failed to unrealize");
4538 /* lock is called in __mmplayer_can_do_interrupt() */
4539 MMPLAYER_CMD_UNLOCK(player);
4541 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4542 player->hw_resource[res_idx] = NULL;
4546 return TRUE; /* release all the resources */
4550 __mmplayer_initialize_video_roi(mmplayer_t *player)
4552 player->video_roi.scale_x = 0.0;
4553 player->video_roi.scale_y = 0.0;
4554 player->video_roi.scale_width = 1.0;
4555 player->video_roi.scale_height = 1.0;
4559 _mmplayer_create_player(MMHandleType handle)
4561 int ret = MM_ERROR_PLAYER_INTERNAL;
4562 bool enabled = false;
4564 mmplayer_t *player = MM_PLAYER_CAST(handle);
4568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4570 /* initialize player state */
4571 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4572 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4573 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4574 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4576 /* check current state */
4577 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4579 /* construct attributes */
4580 player->attrs = _mmplayer_construct_attribute(handle);
4582 if (!player->attrs) {
4583 LOGE("Failed to construct attributes");
4587 /* initialize gstreamer with configured parameter */
4588 if (!__mmplayer_init_gstreamer(player)) {
4589 LOGE("Initializing gstreamer failed");
4590 _mmplayer_deconstruct_attribute(handle);
4594 /* create lock. note that g_tread_init() has already called in gst_init() */
4595 g_mutex_init(&player->fsink_lock);
4597 /* create update tag lock */
4598 g_mutex_init(&player->update_tag_lock);
4600 /* create gapless play mutex */
4601 g_mutex_init(&player->gapless_play_thread_mutex);
4603 /* create gapless play cond */
4604 g_cond_init(&player->gapless_play_thread_cond);
4606 /* create gapless play thread */
4607 player->gapless_play_thread =
4608 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4609 if (!player->gapless_play_thread) {
4610 LOGE("failed to create gapless play thread");
4611 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4612 g_mutex_clear(&player->gapless_play_thread_mutex);
4613 g_cond_clear(&player->gapless_play_thread_cond);
4617 player->bus_msg_q = g_queue_new();
4618 if (!player->bus_msg_q) {
4619 LOGE("failed to create queue for bus_msg");
4620 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4624 ret = _mmplayer_initialize_video_capture(player);
4625 if (ret != MM_ERROR_NONE) {
4626 LOGE("failed to initialize video capture");
4630 /* initialize resource manager */
4631 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4632 __resource_release_cb, player, &player->resource_manager)
4633 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4634 LOGE("failed to initialize resource manager");
4635 ret = MM_ERROR_PLAYER_INTERNAL;
4639 /* create video bo lock and cond */
4640 g_mutex_init(&player->video_bo_mutex);
4641 g_cond_init(&player->video_bo_cond);
4643 /* create subtitle info lock and cond */
4644 g_mutex_init(&player->subtitle_info_mutex);
4645 g_cond_init(&player->subtitle_info_cond);
4647 player->streaming_type = STREAMING_SERVICE_NONE;
4649 /* give default value of audio effect setting */
4650 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4651 player->sound.rg_enable = false;
4652 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4654 player->play_subtitle = FALSE;
4655 player->has_closed_caption = FALSE;
4656 player->pending_resume = FALSE;
4657 if (player->ini.dump_element_keyword[0][0] == '\0')
4658 player->ini.set_dump_element_flag = FALSE;
4660 player->ini.set_dump_element_flag = TRUE;
4662 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4663 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4664 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4666 /* Set video360 settings to their defaults for just-created player.
4669 player->is_360_feature_enabled = FALSE;
4670 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4671 LOGI("spherical feature info: %d", enabled);
4673 player->is_360_feature_enabled = TRUE;
4675 LOGE("failed to get spherical feature info");
4678 player->is_content_spherical = FALSE;
4679 player->is_video360_enabled = TRUE;
4680 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4681 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4682 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4683 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4684 player->video360_zoom = 1.0f;
4685 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4686 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4688 __mmplayer_initialize_video_roi(player);
4690 /* set player state to null */
4691 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4692 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4696 return MM_ERROR_NONE;
4700 g_mutex_clear(&player->fsink_lock);
4701 /* free update tag lock */
4702 g_mutex_clear(&player->update_tag_lock);
4703 g_queue_free(player->bus_msg_q);
4704 player->bus_msg_q = NULL;
4705 /* free gapless play thread */
4706 if (player->gapless_play_thread) {
4707 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4708 player->gapless_play_thread_exit = TRUE;
4709 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4710 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4712 g_thread_join(player->gapless_play_thread);
4713 player->gapless_play_thread = NULL;
4715 g_mutex_clear(&player->gapless_play_thread_mutex);
4716 g_cond_clear(&player->gapless_play_thread_cond);
4719 /* release attributes */
4720 _mmplayer_deconstruct_attribute(handle);
4728 __mmplayer_init_gstreamer(mmplayer_t *player)
4730 static gboolean initialized = FALSE;
4731 static const int max_argc = 50;
4733 gchar **argv = NULL;
4734 gchar **argv2 = NULL;
4740 LOGD("gstreamer already initialized.");
4745 argc = malloc(sizeof(int));
4746 argv = malloc(sizeof(gchar *) * max_argc);
4747 argv2 = malloc(sizeof(gchar *) * max_argc);
4749 if (!argc || !argv || !argv2)
4752 memset(argv, 0, sizeof(gchar *) * max_argc);
4753 memset(argv2, 0, sizeof(gchar *) * max_argc);
4757 argv[0] = g_strdup("mmplayer");
4760 for (i = 0; i < 5; i++) {
4761 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4762 if (strlen(player->ini.gst_param[i]) > 0) {
4763 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4768 /* we would not do fork for scanning plugins */
4769 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4772 /* check disable registry scan */
4773 if (player->ini.skip_rescan) {
4774 argv[*argc] = g_strdup("--gst-disable-registry-update");
4778 /* check disable segtrap */
4779 if (player->ini.disable_segtrap) {
4780 argv[*argc] = g_strdup("--gst-disable-segtrap");
4784 LOGD("initializing gstreamer with following parameter");
4785 LOGD("argc : %d", *argc);
4788 for (i = 0; i < arg_count; i++) {
4790 LOGD("argv[%d] : %s", i, argv2[i]);
4793 /* initializing gstreamer */
4794 if (!gst_init_check(argc, &argv, &err)) {
4795 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4802 for (i = 0; i < arg_count; i++) {
4804 LOGD("release - argv[%d] : %s", i, argv2[i]);
4806 MMPLAYER_FREEIF(argv2[i]);
4809 MMPLAYER_FREEIF(argv);
4810 MMPLAYER_FREEIF(argv2);
4811 MMPLAYER_FREEIF(argc);
4821 for (i = 0; i < arg_count; i++) {
4822 LOGD("free[%d] : %s", i, argv2[i]);
4823 MMPLAYER_FREEIF(argv2[i]);
4826 MMPLAYER_FREEIF(argv);
4827 MMPLAYER_FREEIF(argv2);
4828 MMPLAYER_FREEIF(argc);
4834 __mmplayer_check_async_state_transition(mmplayer_t *player)
4836 GstState element_state = GST_STATE_VOID_PENDING;
4837 GstState element_pending_state = GST_STATE_VOID_PENDING;
4838 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4839 GstElement *element = NULL;
4840 gboolean async = FALSE;
4842 /* check player handle */
4843 MMPLAYER_RETURN_IF_FAIL(player &&
4845 player->pipeline->mainbin &&
4846 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4849 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4851 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4852 LOGD("don't need to check the pipeline state");
4856 MMPLAYER_PRINT_STATE(player);
4858 /* wait for state transition */
4859 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4860 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4862 if (ret == GST_STATE_CHANGE_FAILURE) {
4863 LOGE(" [%s] state : %s pending : %s",
4864 GST_ELEMENT_NAME(element),
4865 gst_element_state_get_name(element_state),
4866 gst_element_state_get_name(element_pending_state));
4868 /* dump state of all element */
4869 _mmplayer_dump_pipeline_state(player);
4874 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4879 _mmplayer_destroy(MMHandleType handle)
4881 mmplayer_t *player = MM_PLAYER_CAST(handle);
4885 /* check player handle */
4886 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4888 /* destroy can called at anytime */
4889 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4891 /* check async state transition */
4892 __mmplayer_check_async_state_transition(player);
4894 /* release gapless play thread */
4895 if (player->gapless_play_thread) {
4896 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4897 player->gapless_play_thread_exit = TRUE;
4898 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4899 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4901 LOGD("waitting for gapless play thread exit");
4902 g_thread_join(player->gapless_play_thread);
4903 g_mutex_clear(&player->gapless_play_thread_mutex);
4904 g_cond_clear(&player->gapless_play_thread_cond);
4905 LOGD("gapless play thread released");
4908 _mmplayer_release_video_capture(player);
4910 /* de-initialize resource manager */
4911 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4912 player->resource_manager))
4913 LOGE("failed to deinitialize resource manager");
4915 /* release miscellaneous information */
4916 __mmplayer_release_misc(player);
4918 /* release pipeline */
4919 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4920 LOGE("failed to destory pipeline");
4921 return MM_ERROR_PLAYER_INTERNAL;
4924 g_queue_free(player->bus_msg_q);
4926 /* release subtitle info lock and cond */
4927 g_mutex_clear(&player->subtitle_info_mutex);
4928 g_cond_clear(&player->subtitle_info_cond);
4930 __mmplayer_release_dump_list(player->dump_list);
4932 /* release miscellaneous information.
4933 these info needs to be released after pipeline is destroyed. */
4934 __mmplayer_release_misc_post(player);
4936 /* release attributes */
4937 _mmplayer_deconstruct_attribute(handle);
4939 if (player->uri_info.uri_list) {
4940 GList *uri_list = player->uri_info.uri_list;
4941 for (; uri_list; uri_list = g_list_next(uri_list)) {
4942 gchar *uri = uri_list->data;
4943 MMPLAYER_FREEIF(uri);
4945 g_list_free(player->uri_info.uri_list);
4946 player->uri_info.uri_list = NULL;
4950 g_mutex_clear(&player->fsink_lock);
4953 g_mutex_clear(&player->update_tag_lock);
4955 /* release video bo lock and cond */
4956 g_mutex_clear(&player->video_bo_mutex);
4957 g_cond_clear(&player->video_bo_cond);
4961 return MM_ERROR_NONE;
4965 _mmplayer_realize(MMHandleType hplayer)
4967 mmplayer_t *player = (mmplayer_t *)hplayer;
4968 int ret = MM_ERROR_NONE;
4971 MMHandleType attrs = 0;
4972 int video_codec_type = 0;
4973 int audio_codec_type = 0;
4974 int default_codec_type = 0;
4977 /* check player handle */
4978 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4980 /* check current state */
4981 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4983 attrs = MMPLAYER_GET_ATTRS(player);
4985 LOGE("fail to get attributes.");
4986 return MM_ERROR_PLAYER_INTERNAL;
4988 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4989 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4991 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4992 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4994 if (ret != MM_ERROR_NONE) {
4995 LOGE("failed to parse profile");
5000 if (uri && (strstr(uri, "es_buff://"))) {
5001 if (strstr(uri, "es_buff://push_mode"))
5002 player->es_player_push_mode = TRUE;
5004 player->es_player_push_mode = FALSE;
5007 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5008 LOGW("mms protocol is not supported format.");
5009 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5012 if (MMPLAYER_IS_STREAMING(player))
5013 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5015 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5017 player->smooth_streaming = FALSE;
5018 player->videodec_linked = 0;
5019 player->audiodec_linked = 0;
5020 player->textsink_linked = 0;
5021 player->is_external_subtitle_present = FALSE;
5022 player->is_external_subtitle_added_now = FALSE;
5023 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5024 player->video360_metadata.is_spherical = -1;
5025 player->is_openal_plugin_used = FALSE;
5026 player->demux_pad_index = 0;
5027 player->subtitle_language_list = NULL;
5028 player->is_subtitle_force_drop = FALSE;
5030 _mmplayer_track_initialize(player);
5031 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5033 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5034 gint prebuffer_ms = 0, rebuffer_ms = 0;
5036 player->streamer = _mm_player_streaming_create();
5037 _mm_player_streaming_initialize(player->streamer, TRUE);
5039 mm_attrs_multiple_get(player->attrs, NULL,
5040 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5041 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5043 if (prebuffer_ms > 0) {
5044 prebuffer_ms = MAX(prebuffer_ms, 1000);
5045 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5048 if (rebuffer_ms > 0) {
5049 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5050 rebuffer_ms = MAX(rebuffer_ms, 1000);
5051 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5054 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5055 player->streamer->buffering_req.rebuffer_time);
5058 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5059 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5060 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5062 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5064 if (audio_codec_type != default_codec_type) {
5065 LOGD("audio dec sorting is required");
5066 player->need_audio_dec_sorting = TRUE;
5069 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5070 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5071 LOGD("video dec sorting is required");
5072 player->need_video_dec_sorting = TRUE;
5075 /* realize pipeline */
5076 ret = __mmplayer_gst_realize(player);
5077 if (ret != MM_ERROR_NONE)
5078 LOGE("fail to realize the player.");
5080 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5088 _mmplayer_unrealize(MMHandleType hplayer)
5090 mmplayer_t *player = (mmplayer_t *)hplayer;
5091 int ret = MM_ERROR_NONE;
5095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5097 MMPLAYER_CMD_UNLOCK(player);
5098 /* destroy the gst bus msg thread which is created during realize.
5099 this funct have to be called before getting cmd lock. */
5100 _mmplayer_bus_msg_thread_destroy(player);
5101 MMPLAYER_CMD_LOCK(player);
5103 /* check current state */
5104 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5106 /* check async state transition */
5107 __mmplayer_check_async_state_transition(player);
5109 /* unrealize pipeline */
5110 ret = __mmplayer_gst_unrealize(player);
5112 if (!player->interrupted_by_resource) {
5113 int rm_ret = MM_ERROR_NONE;
5114 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5116 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5117 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5118 if (rm_ret != MM_ERROR_NONE)
5119 LOGE("failed to release [%d] resources", res_idx);
5128 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5130 mmplayer_t *player = (mmplayer_t *)hplayer;
5132 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5134 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5138 _mmplayer_get_state(MMHandleType hplayer, int *state)
5140 mmplayer_t *player = (mmplayer_t *)hplayer;
5142 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5144 *state = MMPLAYER_CURRENT_STATE(player);
5146 return MM_ERROR_NONE;
5150 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5152 GstElement *vol_element = NULL;
5153 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5157 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5159 /* check pipeline handle */
5160 if (!player->pipeline || !player->pipeline->audiobin) {
5161 LOGD("'%s' will be applied when audiobin is created", prop_name);
5163 /* NOTE : stored value will be used in create_audiobin
5164 * returning MM_ERROR_NONE here makes application to able to
5165 * set audio volume or mute at anytime.
5167 return MM_ERROR_NONE;
5170 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5171 volume_elem_id = MMPLAYER_A_SINK;
5173 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5175 LOGE("failed to get vol element %d", volume_elem_id);
5176 return MM_ERROR_PLAYER_INTERNAL;
5179 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5181 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5182 LOGE("there is no '%s' property", prop_name);
5183 return MM_ERROR_PLAYER_INTERNAL;
5186 if (!strcmp(prop_name, "volume")) {
5187 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5188 } else if (!strcmp(prop_name, "mute")) {
5189 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5191 LOGE("invalid property %s", prop_name);
5192 return MM_ERROR_PLAYER_INTERNAL;
5195 return MM_ERROR_NONE;
5199 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5201 int ret = MM_ERROR_NONE;
5202 mmplayer_t *player = (mmplayer_t *)hplayer;
5205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5207 LOGD("volume = %f", volume);
5209 /* invalid factor range or not */
5210 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5211 LOGE("Invalid volume value");
5212 return MM_ERROR_INVALID_ARGUMENT;
5215 player->sound.volume = volume;
5217 ret = __mmplayer_gst_set_volume_property(player, "volume");
5224 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5226 mmplayer_t *player = (mmplayer_t *)hplayer;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5233 *volume = player->sound.volume;
5235 LOGD("current vol = %f", *volume);
5238 return MM_ERROR_NONE;
5242 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5244 int ret = MM_ERROR_NONE;
5245 mmplayer_t *player = (mmplayer_t *)hplayer;
5248 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5250 LOGD("mute = %d", mute);
5252 player->sound.mute = mute;
5254 ret = __mmplayer_gst_set_volume_property(player, "mute");
5261 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5268 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5270 *mute = player->sound.mute;
5272 LOGD("current mute = %d", *mute);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 player->audio_stream_changed_cb = callback;
5289 player->audio_stream_changed_cb_user_param = user_param;
5290 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5294 return MM_ERROR_NONE;
5298 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5300 mmplayer_t *player = (mmplayer_t *)hplayer;
5304 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5306 player->audio_decoded_cb = callback;
5307 player->audio_decoded_cb_user_param = user_param;
5308 player->audio_extract_opt = opt;
5309 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5313 return MM_ERROR_NONE;
5317 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5319 mmplayer_t *player = (mmplayer_t *)hplayer;
5323 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5325 if (callback && !player->bufmgr)
5326 player->bufmgr = tbm_bufmgr_init(-1);
5328 player->set_mode.video_export = (callback) ? true : false;
5329 player->video_decoded_cb = callback;
5330 player->video_decoded_cb_user_param = user_param;
5332 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5336 return MM_ERROR_NONE;
5340 _mmplayer_start(MMHandleType hplayer)
5342 mmplayer_t *player = (mmplayer_t *)hplayer;
5343 gint ret = MM_ERROR_NONE;
5347 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5349 /* check current state */
5350 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5352 /* start pipeline */
5353 ret = _mmplayer_gst_start(player);
5354 if (ret != MM_ERROR_NONE)
5355 LOGE("failed to start player.");
5357 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5358 LOGD("force playing start even during buffering");
5359 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5367 /* NOTE: post "not supported codec message" to application
5368 * when one codec is not found during AUTOPLUGGING in MSL.
5369 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5370 * And, if any codec is not found, don't send message here.
5371 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5374 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5376 MMMessageParamType msg_param;
5377 memset(&msg_param, 0, sizeof(MMMessageParamType));
5378 gboolean post_msg_direct = FALSE;
5382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5384 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5385 player->not_supported_codec, player->can_support_codec);
5387 if (player->not_found_demuxer) {
5388 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5389 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5391 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5392 MMPLAYER_FREEIF(msg_param.data);
5394 return MM_ERROR_NONE;
5397 if (player->not_supported_codec) {
5398 if (player->can_support_codec) {
5399 // There is one codec to play
5400 post_msg_direct = TRUE;
5402 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5403 post_msg_direct = TRUE;
5406 if (post_msg_direct) {
5407 MMMessageParamType msg_param;
5408 memset(&msg_param, 0, sizeof(MMMessageParamType));
5410 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5411 LOGW("not found AUDIO codec, posting error code to application.");
5413 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5414 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5415 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5416 LOGW("not found VIDEO codec, posting error code to application.");
5418 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5419 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5422 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5424 MMPLAYER_FREEIF(msg_param.data);
5426 return MM_ERROR_NONE;
5428 // no any supported codec case
5429 LOGW("not found any codec, posting error code to application.");
5431 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5432 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5433 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5435 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5436 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5439 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5441 MMPLAYER_FREEIF(msg_param.data);
5447 return MM_ERROR_NONE;
5450 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5452 GstState element_state = GST_STATE_VOID_PENDING;
5453 GstState element_pending_state = GST_STATE_VOID_PENDING;
5454 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5455 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5457 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5459 MMPLAYER_RECONFIGURE_LOCK(player);
5460 if (!player->gapless.reconfigure) {
5461 MMPLAYER_RECONFIGURE_UNLOCK(player);
5465 LOGI("reconfigure is under process");
5466 MMPLAYER_RECONFIGURE_WAIT(player);
5467 MMPLAYER_RECONFIGURE_UNLOCK(player);
5468 LOGI("reconfigure is completed.");
5470 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5471 &element_state, &element_pending_state, timeout * GST_SECOND);
5472 if (result == GST_STATE_CHANGE_FAILURE)
5473 LOGW("failed to get pipeline state in %d sec", timeout);
5478 /* NOTE : it should be able to call 'stop' anytime*/
5480 _mmplayer_stop(MMHandleType hplayer)
5482 mmplayer_t *player = (mmplayer_t *)hplayer;
5483 int ret = MM_ERROR_NONE;
5487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5489 /* check current state */
5490 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5492 /* need to wait till the rebuilding pipeline is completed */
5493 __mmplayer_check_pipeline_reconfigure_state(player);
5494 MMPLAYER_RECONFIGURE_LOCK(player);
5495 __mmplayer_reset_gapless_state(player);
5496 MMPLAYER_RECONFIGURE_UNLOCK(player);
5498 /* NOTE : application should not wait for EOS after calling STOP */
5499 _mmplayer_cancel_eos_timer(player);
5502 player->seek_state = MMPLAYER_SEEK_NONE;
5505 ret = _mmplayer_gst_stop(player);
5507 if (ret != MM_ERROR_NONE)
5508 LOGE("failed to stop player.");
5516 _mmplayer_pause(MMHandleType hplayer)
5518 mmplayer_t *player = (mmplayer_t *)hplayer;
5519 gint64 pos_nsec = 0;
5520 gboolean async = FALSE;
5521 gint ret = MM_ERROR_NONE;
5525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5527 /* check current state */
5528 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5530 /* check pipline reconfigure state */
5531 __mmplayer_check_pipeline_reconfigure_state(player);
5533 switch (MMPLAYER_CURRENT_STATE(player)) {
5534 case MM_PLAYER_STATE_READY:
5536 /* check prepare async or not.
5537 * In the case of streaming playback, it's recommned to avoid blocking wait.
5539 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5540 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5542 /* Changing back sync of rtspsrc to async */
5543 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5544 LOGD("async prepare working mode for rtsp");
5550 case MM_PLAYER_STATE_PLAYING:
5552 /* NOTE : store current point to overcome some bad operation
5553 *(returning zero when getting current position in paused state) of some
5556 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5557 LOGW("getting current position failed in paused");
5559 player->last_position = pos_nsec;
5561 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5562 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5563 This causes problem is position calculation during normal pause resume scenarios also.
5564 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5565 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5566 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5567 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5573 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5574 LOGD("doing async pause in case of ms buff src");
5578 /* pause pipeline */
5579 ret = _mmplayer_gst_pause(player, async);
5581 if (ret != MM_ERROR_NONE)
5582 LOGE("failed to pause player. ret : 0x%x", ret);
5584 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5585 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5586 LOGE("failed to update display_rotation");
5594 /* in case of streaming, pause could take long time.*/
5596 _mmplayer_abort_pause(MMHandleType hplayer)
5598 mmplayer_t *player = (mmplayer_t *)hplayer;
5599 int ret = MM_ERROR_NONE;
5603 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5605 player->pipeline->mainbin,
5606 MM_ERROR_PLAYER_NOT_INITIALIZED);
5608 LOGD("set the pipeline state to READY");
5610 /* set state to READY */
5611 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5612 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5613 if (ret != MM_ERROR_NONE) {
5614 LOGE("fail to change state to READY");
5615 return MM_ERROR_PLAYER_INTERNAL;
5618 LOGD("succeeded in changing state to READY");
5623 _mmplayer_resume(MMHandleType hplayer)
5625 mmplayer_t *player = (mmplayer_t *)hplayer;
5626 int ret = MM_ERROR_NONE;
5627 gboolean async = FALSE;
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5633 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5634 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5635 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5639 /* Changing back sync mode rtspsrc to async */
5640 LOGD("async resume for rtsp case");
5644 /* check current state */
5645 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5647 ret = _mmplayer_gst_resume(player, async);
5648 if (ret != MM_ERROR_NONE)
5649 LOGE("failed to resume player.");
5651 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5652 LOGD("force resume even during buffering");
5653 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5662 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5664 mmplayer_t *player = (mmplayer_t *)hplayer;
5665 gint64 pos_nsec = 0;
5666 int ret = MM_ERROR_NONE;
5668 signed long long start = 0, stop = 0;
5669 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5672 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5673 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5675 /* The sound of video is not supported under 0.0 and over 2.0. */
5676 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5677 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5680 _mmplayer_set_mute(hplayer, mute);
5682 if (player->playback_rate == rate)
5683 return MM_ERROR_NONE;
5685 /* If the position is reached at start potion during fast backward, EOS is posted.
5686 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5688 player->playback_rate = rate;
5690 current_state = MMPLAYER_CURRENT_STATE(player);
5692 if (current_state != MM_PLAYER_STATE_PAUSED)
5693 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5695 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5697 if ((current_state == MM_PLAYER_STATE_PAUSED)
5698 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5699 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5700 pos_nsec = player->last_position;
5705 stop = GST_CLOCK_TIME_NONE;
5707 start = GST_CLOCK_TIME_NONE;
5711 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5712 player->playback_rate,
5714 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5715 GST_SEEK_TYPE_SET, start,
5716 GST_SEEK_TYPE_SET, stop)) {
5717 LOGE("failed to set speed playback");
5718 return MM_ERROR_PLAYER_SEEK;
5721 LOGD("succeeded to set speed playback as %0.1f", rate);
5725 return MM_ERROR_NONE;;
5729 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5731 mmplayer_t *player = (mmplayer_t *)hplayer;
5732 int ret = MM_ERROR_NONE;
5736 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5738 /* check pipline reconfigure state */
5739 __mmplayer_check_pipeline_reconfigure_state(player);
5741 ret = _mmplayer_gst_set_position(player, position, FALSE);
5749 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5751 mmplayer_t *player = (mmplayer_t *)hplayer;
5752 int ret = MM_ERROR_NONE;
5754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5755 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5757 if (g_strrstr(player->type, "video/mpegts"))
5758 __mmplayer_update_duration_value(player);
5760 *duration = player->duration;
5765 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5767 mmplayer_t *player = (mmplayer_t *)hplayer;
5768 int ret = MM_ERROR_NONE;
5770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5772 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5778 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5780 mmplayer_t *player = (mmplayer_t *)hplayer;
5781 int ret = MM_ERROR_NONE;
5785 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5787 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5795 __mmplayer_is_midi_type(gchar *str_caps)
5797 if ((g_strrstr(str_caps, "audio/midi")) ||
5798 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5799 (g_strrstr(str_caps, "application/x-smaf")) ||
5800 (g_strrstr(str_caps, "audio/x-imelody")) ||
5801 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5802 (g_strrstr(str_caps, "audio/xmf")) ||
5803 (g_strrstr(str_caps, "audio/mxmf"))) {
5812 __mmplayer_is_only_mp3_type(gchar *str_caps)
5814 if (g_strrstr(str_caps, "application/x-id3") ||
5815 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5821 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5823 GstStructure *caps_structure = NULL;
5824 gint samplerate = 0;
5828 MMPLAYER_RETURN_IF_FAIL(player && caps);
5830 caps_structure = gst_caps_get_structure(caps, 0);
5832 /* set stream information */
5833 gst_structure_get_int(caps_structure, "rate", &samplerate);
5834 gst_structure_get_int(caps_structure, "channels", &channels);
5836 mm_player_set_attribute((MMHandleType)player, NULL,
5837 "content_audio_samplerate", samplerate,
5838 "content_audio_channels", channels, NULL);
5840 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5844 __mmplayer_update_content_type_info(mmplayer_t *player)
5847 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5849 if (__mmplayer_is_midi_type(player->type)) {
5850 player->bypass_audio_effect = TRUE;
5854 if (!player->streamer) {
5855 LOGD("no need to check streaming type");
5859 if (g_strrstr(player->type, "application/x-hls")) {
5860 /* If it can't know exact type when it parses uri because of redirection case,
5861 * it will be fixed by typefinder or when doing autoplugging.
5863 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5864 player->streamer->is_adaptive_streaming = TRUE;
5865 } else if (g_strrstr(player->type, "application/dash+xml")) {
5866 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5867 player->streamer->is_adaptive_streaming = TRUE;
5870 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5871 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5872 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5874 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5875 if (player->streamer->is_adaptive_streaming)
5876 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5878 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5882 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5887 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5888 GstCaps *caps, gpointer data)
5890 mmplayer_t *player = (mmplayer_t *)data;
5895 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5897 /* store type string */
5898 MMPLAYER_FREEIF(player->type);
5899 player->type = gst_caps_to_string(caps);
5901 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5902 player, player->type, probability, gst_caps_get_size(caps));
5904 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5905 (g_strrstr(player->type, "audio/x-raw-int"))) {
5906 LOGE("not support media format");
5908 if (player->msg_posted == FALSE) {
5909 MMMessageParamType msg_param;
5910 memset(&msg_param, 0, sizeof(MMMessageParamType));
5912 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5913 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5915 /* don't post more if one was sent already */
5916 player->msg_posted = TRUE;
5921 __mmplayer_update_content_type_info(player);
5923 pad = gst_element_get_static_pad(tf, "src");
5925 LOGE("fail to get typefind src pad.");
5929 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5930 gboolean async = FALSE;
5931 LOGE("failed to autoplug %s", player->type);
5933 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5935 if (async && player->msg_posted == FALSE)
5936 __mmplayer_handle_missed_plugin(player);
5940 gst_object_unref(GST_OBJECT(pad));
5948 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5950 GstElement *decodebin = NULL;
5954 /* create decodebin */
5955 decodebin = gst_element_factory_make("decodebin", NULL);
5958 LOGE("fail to create decodebin");
5962 /* raw pad handling signal */
5963 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5964 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5966 /* no-more-pad pad handling signal */
5967 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5968 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5970 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5971 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5973 /* This signal is emitted when a pad for which there is no further possible
5974 decoding is added to the decodebin.*/
5975 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5976 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5978 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5979 before looking for any elements that can handle that stream.*/
5980 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5981 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5983 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5984 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5985 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5987 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5988 before looking for any elements that can handle that stream.*/
5989 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5990 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5992 /* This signal is emitted once decodebin has finished decoding all the data.*/
5993 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5994 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5996 /* This signal is emitted when a element is added to the bin.*/
5997 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5998 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6005 __mmplayer_gst_make_queue2(mmplayer_t *player)
6007 GstElement *queue2 = NULL;
6008 gint64 dur_bytes = 0L;
6009 mmplayer_gst_element_t *mainbin = NULL;
6010 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6013 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6015 mainbin = player->pipeline->mainbin;
6017 queue2 = gst_element_factory_make("queue2", "queue2");
6019 LOGE("failed to create buffering queue element");
6023 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6024 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6026 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6028 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6029 * skip the pull mode(file or ring buffering) setting. */
6030 if (dur_bytes > 0) {
6031 if (!g_strrstr(player->type, "video/mpegts")) {
6032 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6033 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6039 _mm_player_streaming_set_queue2(player->streamer,
6043 (guint64)dur_bytes); /* no meaning at the moment */
6049 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6051 mmplayer_gst_element_t *mainbin = NULL;
6052 GstElement *decodebin = NULL;
6053 GstElement *queue2 = NULL;
6054 GstPad *sinkpad = NULL;
6055 GstPad *qsrcpad = NULL;
6058 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6060 mainbin = player->pipeline->mainbin;
6062 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6064 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6065 LOGW("need to check: muxed buffer is not null");
6068 queue2 = __mmplayer_gst_make_queue2(player);
6070 LOGE("failed to make queue2");
6074 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6075 LOGE("failed to add buffering queue");
6079 sinkpad = gst_element_get_static_pad(queue2, "sink");
6080 qsrcpad = gst_element_get_static_pad(queue2, "src");
6082 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6083 LOGE("failed to link [%s:%s]-[%s:%s]",
6084 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6088 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6089 LOGE("failed to sync queue2 state with parent");
6093 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6094 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6098 gst_object_unref(GST_OBJECT(sinkpad));
6102 /* create decodebin */
6103 decodebin = _mmplayer_gst_make_decodebin(player);
6105 LOGE("failed to make decodebin");
6109 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6110 LOGE("failed to add decodebin");
6114 /* to force caps on the decodebin element and avoid reparsing stuff by
6115 * typefind. It also avoids a deadlock in the way typefind activates pads in
6116 * the state change */
6117 g_object_set(decodebin, "sink-caps", caps, NULL);
6119 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6121 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6122 LOGE("failed to link [%s:%s]-[%s:%s]",
6123 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6127 gst_object_unref(GST_OBJECT(sinkpad));
6129 gst_object_unref(GST_OBJECT(qsrcpad));
6132 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6133 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6135 /* set decodebin property about buffer in streaming playback. *
6136 * in case of HLS/DASH, it does not need to have big buffer *
6137 * because it is kind of adaptive streaming. */
6138 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6139 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6140 gint high_percent = 0;
6142 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6143 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6145 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6147 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6149 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6150 "high-percent", high_percent,
6151 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6152 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6153 "max-size-buffers", 0, NULL); // disable or automatic
6156 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6157 LOGE("failed to sync decodebin state with parent");
6168 gst_object_unref(GST_OBJECT(sinkpad));
6171 gst_object_unref(GST_OBJECT(qsrcpad));
6174 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6175 * You need to explicitly set elements to the NULL state before
6176 * dropping the final reference, to allow them to clean up.
6178 gst_element_set_state(queue2, GST_STATE_NULL);
6180 /* And, it still has a parent "player".
6181 * You need to let the parent manage the object instead of unreffing the object directly.
6183 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6184 gst_object_unref(queue2);
6189 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6190 * You need to explicitly set elements to the NULL state before
6191 * dropping the final reference, to allow them to clean up.
6193 gst_element_set_state(decodebin, GST_STATE_NULL);
6195 /* And, it still has a parent "player".
6196 * You need to let the parent manage the object instead of unreffing the object directly.
6199 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6200 gst_object_unref(decodebin);
6208 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6212 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6213 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6215 LOGD("class : %s, mime : %s", factory_class, mime);
6217 /* add missing plugin */
6218 /* NOTE : msl should check missing plugin for image mime type.
6219 * Some motion jpeg clips can have playable audio track.
6220 * So, msl have to play audio after displaying popup written video format not supported.
6222 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6223 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6224 LOGD("not found demuxer");
6225 player->not_found_demuxer = TRUE;
6226 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6232 if (!g_strrstr(factory_class, "Demuxer")) {
6233 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6234 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6235 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6237 /* check that clip have multi tracks or not */
6238 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6239 LOGD("video plugin is already linked");
6241 LOGW("add VIDEO to missing plugin");
6242 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6243 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6245 } else if (g_str_has_prefix(mime, "audio")) {
6246 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6247 LOGD("audio plugin is already linked");
6249 LOGW("add AUDIO to missing plugin");
6250 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6251 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6259 return MM_ERROR_NONE;
6263 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6265 mmplayer_t *player = (mmplayer_t *)data;
6269 MMPLAYER_RETURN_IF_FAIL(player);
6271 /* remove fakesink. */
6272 if (!_mmplayer_gst_remove_fakesink(player,
6273 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6274 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6275 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6276 * source element are not same. To overcome this situation, this function will called
6277 * several places and several times. Therefore, this is not an error case.
6282 LOGD("[handle: %p] pipeline has completely constructed", player);
6284 if ((player->msg_posted == FALSE) &&
6285 (player->cmd >= MMPLAYER_COMMAND_START))
6286 __mmplayer_handle_missed_plugin(player);
6288 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6292 __mmplayer_check_profile(void)
6295 static int profile_tv = -1;
6297 if (__builtin_expect(profile_tv != -1, 1))
6300 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6301 switch (*profileName) {
6316 __mmplayer_get_next_uri(mmplayer_t *player)
6318 mmplayer_parse_profile_t profile;
6320 guint num_of_list = 0;
6323 num_of_list = g_list_length(player->uri_info.uri_list);
6324 uri_idx = player->uri_info.uri_idx;
6326 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6327 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6328 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6330 LOGW("next uri does not exist");
6334 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6335 LOGE("failed to parse profile");
6339 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6340 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6341 LOGW("uri type is not supported(%d)", profile.uri_type);
6345 LOGD("success to find next uri %d", uri_idx);
6349 if (!uri || uri_idx == num_of_list) {
6350 LOGE("failed to find next uri");
6354 player->uri_info.uri_idx = uri_idx;
6355 if (mm_player_set_attribute((MMHandleType)player, NULL,
6356 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6357 LOGE("failed to set attribute");
6361 SECURE_LOGD("next playback uri: %s", uri);
6366 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6368 #define REPEAT_COUNT_INFINITE -1
6369 #define REPEAT_COUNT_MIN 2
6370 #define ORIGINAL_URI_ONLY 1
6372 MMHandleType attrs = 0;
6376 guint num_of_uri = 0;
6377 int profile_tv = -1;
6381 LOGD("checking for gapless play option");
6383 if (player->build_audio_offload) {
6384 LOGE("offload path is not supportable.");
6388 if (player->pipeline->textbin) {
6389 LOGE("subtitle path is enabled. gapless play is not supported.");
6393 attrs = MMPLAYER_GET_ATTRS(player);
6395 LOGE("fail to get attributes.");
6399 mm_attrs_multiple_get(player->attrs, NULL,
6400 "content_video_found", &video,
6401 "profile_play_count", &count,
6402 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6404 /* gapless playback is not supported in case of video at TV profile. */
6405 profile_tv = __mmplayer_check_profile();
6406 if (profile_tv && video) {
6407 LOGW("not support video gapless playback");
6411 /* check repeat count in case of audio */
6413 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6414 LOGW("gapless is disabled");
6418 num_of_uri = g_list_length(player->uri_info.uri_list);
6420 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6422 if (num_of_uri == ORIGINAL_URI_ONLY) {
6423 /* audio looping path */
6424 if (count >= REPEAT_COUNT_MIN) {
6425 /* decrease play count */
6426 /* we succeeded to rewind. update play count and then wait for next EOS */
6428 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6429 } else if (count != REPEAT_COUNT_INFINITE) {
6430 LOGD("there is no next uri and no repeat");
6433 LOGD("looping cnt %d", count);
6435 /* gapless playback path */
6436 if (!__mmplayer_get_next_uri(player)) {
6437 LOGE("failed to get next uri");
6444 LOGE("unable to play gapless path. EOS will be posted soon");
6449 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6451 mmplayer_selector_t *selector = &player->selector[type];
6452 mmplayer_gst_element_t *sinkbin = NULL;
6453 main_element_id_e selectorId = MMPLAYER_M_NUM;
6454 main_element_id_e sinkId = MMPLAYER_M_NUM;
6455 GstPad *srcpad = NULL;
6456 GstPad *sinkpad = NULL;
6457 gboolean send_notice = FALSE;
6460 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6462 LOGD("type %d", type);
6465 case MM_PLAYER_TRACK_TYPE_AUDIO:
6466 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6467 sinkId = MMPLAYER_A_BIN;
6468 sinkbin = player->pipeline->audiobin;
6470 case MM_PLAYER_TRACK_TYPE_VIDEO:
6471 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6472 sinkId = MMPLAYER_V_BIN;
6473 sinkbin = player->pipeline->videobin;
6476 case MM_PLAYER_TRACK_TYPE_TEXT:
6477 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6478 sinkId = MMPLAYER_T_BIN;
6479 sinkbin = player->pipeline->textbin;
6482 LOGE("requested type is not supportable");
6487 if (player->pipeline->mainbin[selectorId].gst) {
6490 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6492 if (selector->event_probe_id != 0)
6493 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6494 selector->event_probe_id = 0;
6496 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6497 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6499 if (srcpad && sinkpad) {
6500 /* after getting drained signal there is no data flows, so no need to do pad_block */
6501 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6502 gst_pad_unlink(srcpad, sinkpad);
6504 /* send custom event to sink pad to handle it at video sink */
6506 LOGD("send custom event to sinkpad");
6507 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6508 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6509 gst_pad_send_event(sinkpad, event);
6513 gst_object_unref(sinkpad);
6516 gst_object_unref(srcpad);
6519 LOGD("selector release");
6521 /* release and unref requests pad from the selector */
6522 for (n = 0; n < selector->channels->len; n++) {
6523 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6524 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6526 g_ptr_array_set_size(selector->channels, 0);
6528 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6529 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6531 player->pipeline->mainbin[selectorId].gst = NULL;
6539 __mmplayer_deactivate_old_path(mmplayer_t *player)
6542 MMPLAYER_RETURN_IF_FAIL(player);
6544 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6545 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6546 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6547 LOGE("deactivate selector error");
6551 _mmplayer_track_destroy(player);
6552 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6554 if (player->streamer) {
6555 _mm_player_streaming_initialize(player->streamer, FALSE);
6556 _mm_player_streaming_destroy(player->streamer);
6557 player->streamer = NULL;
6560 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6566 if (!player->msg_posted) {
6567 MMMessageParamType msg = {0,};
6570 msg.code = MM_ERROR_PLAYER_INTERNAL;
6571 LOGE("gapless_uri_play> deactivate error");
6573 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6574 player->msg_posted = TRUE;
6580 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6582 int result = MM_ERROR_NONE;
6583 mmplayer_t *player = (mmplayer_t *)hplayer;
6586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6587 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6589 if (mm_player_set_attribute(hplayer, NULL,
6590 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6591 LOGE("failed to set attribute");
6592 result = MM_ERROR_PLAYER_INTERNAL;
6594 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6595 LOGE("failed to add the original uri in the uri list.");
6603 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6605 mmplayer_t *player = (mmplayer_t *)hplayer;
6606 guint num_of_list = 0;
6610 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6611 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6613 if (player->pipeline && player->pipeline->textbin) {
6614 LOGE("subtitle path is enabled.");
6615 return MM_ERROR_PLAYER_INVALID_STATE;
6618 num_of_list = g_list_length(player->uri_info.uri_list);
6620 if (is_first_path) {
6621 if (num_of_list == 0) {
6622 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6623 SECURE_LOGD("add original path : %s", uri);
6625 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6626 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6628 SECURE_LOGD("change original path : %s", uri);
6631 MMHandleType attrs = 0;
6632 attrs = MMPLAYER_GET_ATTRS(player);
6634 if (num_of_list == 0) {
6635 char *original_uri = NULL;
6638 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6640 if (!original_uri) {
6641 LOGE("there is no original uri.");
6642 return MM_ERROR_PLAYER_INVALID_STATE;
6645 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6646 player->uri_info.uri_idx = 0;
6648 SECURE_LOGD("add original path at first : %s", original_uri);
6652 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6653 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6657 return MM_ERROR_NONE;
6661 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6663 mmplayer_t *player = (mmplayer_t *)hplayer;
6664 char *next_uri = NULL;
6665 guint num_of_list = 0;
6668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6670 num_of_list = g_list_length(player->uri_info.uri_list);
6672 if (num_of_list > 0) {
6673 gint uri_idx = player->uri_info.uri_idx;
6675 if (uri_idx < num_of_list-1)
6680 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6681 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6683 *uri = g_strdup(next_uri);
6687 return MM_ERROR_NONE;
6691 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6692 GstCaps *caps, gpointer data)
6694 mmplayer_t *player = (mmplayer_t *)data;
6695 const gchar *klass = NULL;
6696 const gchar *mime = NULL;
6697 gchar *caps_str = NULL;
6699 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6700 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6701 caps_str = gst_caps_to_string(caps);
6703 LOGW("unknown type of caps : %s from %s",
6704 caps_str, GST_ELEMENT_NAME(elem));
6706 MMPLAYER_FREEIF(caps_str);
6708 /* There is no available codec. */
6709 __mmplayer_check_not_supported_codec(player, klass, mime);
6713 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6714 GstCaps *caps, gpointer data)
6716 mmplayer_t *player = (mmplayer_t *)data;
6717 const char *mime = NULL;
6718 gboolean ret = TRUE;
6720 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6721 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6723 if (g_str_has_prefix(mime, "audio")) {
6724 GstStructure *caps_structure = NULL;
6725 gint samplerate = 0;
6727 gchar *caps_str = NULL;
6729 caps_structure = gst_caps_get_structure(caps, 0);
6730 gst_structure_get_int(caps_structure, "rate", &samplerate);
6731 gst_structure_get_int(caps_structure, "channels", &channels);
6733 if ((channels > 0 && samplerate == 0)) {
6734 LOGD("exclude audio...");
6738 caps_str = gst_caps_to_string(caps);
6739 /* set it directly because not sent by TAG */
6740 if (g_strrstr(caps_str, "mobile-xmf"))
6741 mm_player_set_attribute((MMHandleType)player, NULL,
6742 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6744 MMPLAYER_FREEIF(caps_str);
6745 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6746 LOGD("already video linked");
6749 LOGD("found new stream");
6756 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6758 gboolean ret = FALSE;
6759 GDBusConnection *conn = NULL;
6761 GVariant *result = NULL;
6762 const gchar *dbus_device_type = NULL;
6763 const gchar *dbus_ret = NULL;
6766 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6768 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6773 result = g_dbus_connection_call_sync(conn,
6774 "org.pulseaudio.Server",
6775 "/org/pulseaudio/StreamManager",
6776 "org.pulseaudio.StreamManager",
6777 "GetCurrentMediaRoutingPath",
6778 g_variant_new("(s)", "out"),
6779 G_VARIANT_TYPE("(ss)"),
6780 G_DBUS_CALL_FLAGS_NONE,
6784 if (!result || err) {
6785 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6790 /* device type is listed in stream-map.json at mmfw-sysconf */
6791 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6793 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6794 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6797 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6798 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6799 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6800 LOGD("audio offload is supportable");
6806 LOGD("audio offload is not supportable");
6809 g_variant_unref(result);
6811 g_object_unref(conn);
6816 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6818 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6819 gint64 position = 0;
6821 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6822 player->pipeline && player->pipeline->mainbin);
6824 MMPLAYER_CMD_LOCK(player);
6825 current_state = MMPLAYER_CURRENT_STATE(player);
6827 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6828 LOGW("getting current position failed in paused");
6830 _mmplayer_unrealize((MMHandleType)player);
6831 _mmplayer_realize((MMHandleType)player);
6833 _mmplayer_set_position((MMHandleType)player, position);
6835 /* async not to be blocked in streaming case */
6836 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6838 _mmplayer_pause((MMHandleType)player);
6840 if (current_state == MM_PLAYER_STATE_PLAYING)
6841 _mmplayer_start((MMHandleType)player);
6842 MMPLAYER_CMD_UNLOCK(player);
6844 LOGD("rebuilding audio pipeline is completed.");
6847 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6849 mmplayer_t *player = (mmplayer_t *)user_data;
6850 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6851 gboolean is_supportable = FALSE;
6853 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6854 LOGW("failed to get device type");
6856 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6858 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6859 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6860 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6861 LOGD("ignore this dev connected info");
6865 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6866 if (player->build_audio_offload == is_supportable) {
6867 LOGD("keep current pipeline without re-building");
6871 /* rebuild pipeline */
6872 LOGD("re-build pipeline - offload: %d", is_supportable);
6873 player->build_audio_offload = FALSE;
6874 __mmplayer_rebuild_audio_pipeline(player);
6880 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6882 unsigned int id = 0;
6884 if (player->audio_device_cb_id != 0) {
6885 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6889 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6890 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6891 LOGD("added device connected cb (%u)", id);
6892 player->audio_device_cb_id = id;
6894 LOGW("failed to add device connected cb");
6901 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6903 mmplayer_t *player = (mmplayer_t *)hplayer;
6906 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6907 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6909 *activated = player->build_audio_offload;
6911 LOGD("offload activated : %d", (int)*activated);
6914 return MM_ERROR_NONE;
6918 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6921 this function need to be updated according to the supported media format
6922 @see player->ini.audio_offload_media_format */
6924 if (__mmplayer_is_only_mp3_type(player->type)) {
6925 LOGD("offload supportable media format type");
6933 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6935 gboolean ret = FALSE;
6936 GstElementFactory *factory = NULL;
6939 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6941 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6942 if (!__mmplayer_is_offload_supported_type(player))
6945 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6946 LOGD("there is no audio offload sink");
6950 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6951 LOGW("there is no audio device type to support offload");
6955 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6957 LOGW("there is no installed audio offload sink element");
6960 gst_object_unref(factory);
6962 if (__mmplayer_acquire_hw_resource(player,
6963 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6964 LOGE("failed to acquire audio offload decoder resource");
6968 if (!__mmplayer_add_audio_device_connected_cb(player))
6971 if (!__mmplayer_is_audio_offload_device_type(player))
6974 LOGD("audio offload can be built");
6979 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6985 static GstAutoplugSelectResult
6986 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6988 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6989 int audio_offload = 0;
6991 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6992 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6994 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6995 LOGD("expose audio path to build offload output path");
6996 player->build_audio_offload = TRUE;
6997 /* update codec info */
6998 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6999 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7000 player->audiodec_linked = 1;
7002 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7006 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7007 And need to consider the multi-track audio content.
7008 There is no HW audio decoder in public. */
7010 /* set stream information */
7011 if (!player->audiodec_linked)
7012 __mmplayer_set_audio_attrs(player, caps);
7014 /* update codec info */
7015 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7016 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7017 player->audiodec_linked = 1;
7019 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7021 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7022 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7024 /* mark video decoder for acquire */
7025 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7026 LOGW("video decoder resource is already acquired, skip it.");
7027 ret = GST_AUTOPLUG_SELECT_SKIP;
7031 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7032 LOGE("failed to acquire video decoder resource");
7033 ret = GST_AUTOPLUG_SELECT_SKIP;
7036 player->interrupted_by_resource = FALSE;
7039 /* update codec info */
7040 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7041 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7042 player->videodec_linked = 1;
7050 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7051 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7053 #define DEFAULT_IDX 0xFFFF
7054 #define MIN_FACTORY_NUM 2
7055 mmplayer_t *player = (mmplayer_t *)data;
7056 GValueArray *new_factories = NULL;
7057 GValue val = { 0, };
7058 GstElementFactory *factory = NULL;
7059 const gchar *klass = NULL;
7060 gchar *factory_name = NULL;
7061 guint hw_dec_idx = DEFAULT_IDX;
7062 guint first_sw_dec_idx = DEFAULT_IDX;
7063 guint last_sw_dec_idx = DEFAULT_IDX;
7064 guint new_pos = DEFAULT_IDX;
7065 guint rm_pos = DEFAULT_IDX;
7066 int audio_codec_type;
7067 int video_codec_type;
7068 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7070 if (factories->n_values < MIN_FACTORY_NUM)
7073 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7074 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7077 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7079 for (int i = 0 ; i < factories->n_values ; i++) {
7080 gchar *hw_dec_info = NULL;
7081 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7083 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7084 klass = gst_element_factory_get_klass(factory);
7085 factory_name = GST_OBJECT_NAME(factory);
7088 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7090 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7091 if (!player->need_audio_dec_sorting) {
7092 LOGD("sorting is not required");
7095 codec_type = audio_codec_type;
7096 hw_dec_info = player->ini.audiocodec_element_hw;
7097 sw_dec_info = player->ini.audiocodec_element_sw;
7098 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7099 if (!player->need_video_dec_sorting) {
7100 LOGD("sorting is not required");
7103 codec_type = video_codec_type;
7104 hw_dec_info = player->ini.videocodec_element_hw;
7105 sw_dec_info = player->ini.videocodec_element_sw;
7110 if (g_strrstr(factory_name, hw_dec_info)) {
7113 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7114 if (strstr(factory_name, sw_dec_info[j])) {
7115 last_sw_dec_idx = i;
7116 if (first_sw_dec_idx == DEFAULT_IDX) {
7117 first_sw_dec_idx = i;
7122 if (first_sw_dec_idx == DEFAULT_IDX)
7123 LOGW("unknown codec %s", factory_name);
7127 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7130 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7131 if (hw_dec_idx < first_sw_dec_idx)
7133 new_pos = first_sw_dec_idx - 1;
7134 rm_pos = hw_dec_idx + 1;
7135 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7136 if (last_sw_dec_idx < hw_dec_idx)
7138 new_pos = last_sw_dec_idx + 1;
7139 rm_pos = hw_dec_idx;
7144 /* change position - insert H/W decoder according to the new position */
7145 new_factories = g_value_array_copy(factories);
7146 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7147 g_value_init (&val, G_TYPE_OBJECT);
7148 g_value_set_object (&val, factory);
7149 g_value_array_insert(new_factories, new_pos, &val);
7150 g_value_unset (&val);
7151 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7153 for (int i = 0 ; i < new_factories->n_values ; i++) {
7154 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7156 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7157 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7160 return new_factories;
7164 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7165 GstCaps *caps, GstElementFactory *factory, gpointer data)
7167 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7168 mmplayer_t *player = (mmplayer_t *)data;
7170 gchar *factory_name = NULL;
7171 gchar *caps_str = NULL;
7172 const gchar *klass = NULL;
7175 factory_name = GST_OBJECT_NAME(factory);
7176 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7177 caps_str = gst_caps_to_string(caps);
7179 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7181 /* store type string */
7182 if (player->type == NULL) {
7183 player->type = gst_caps_to_string(caps);
7184 __mmplayer_update_content_type_info(player);
7187 /* filtering exclude keyword */
7188 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7189 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7190 LOGW("skipping [%s] by exculde keyword [%s]",
7191 factory_name, player->ini.exclude_element_keyword[idx]);
7193 result = GST_AUTOPLUG_SELECT_SKIP;
7198 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7199 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7200 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7201 factory_name, player->ini.unsupported_codec_keyword[idx]);
7202 result = GST_AUTOPLUG_SELECT_SKIP;
7207 /* exclude webm format */
7208 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7209 * because webm format is not supportable.
7210 * If webm is disabled in "autoplug-continue", there is no state change
7211 * failure or error because the decodebin will expose the pad directly.
7212 * It make MSL invoke _prepare_async_callback.
7213 * So, we need to disable webm format in "autoplug-select" */
7214 if (caps_str && strstr(caps_str, "webm")) {
7215 LOGW("webm is not supported");
7216 result = GST_AUTOPLUG_SELECT_SKIP;
7220 /* check factory class for filtering */
7221 /* NOTE : msl don't need to use image plugins.
7222 * So, those plugins should be skipped for error handling.
7224 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7225 LOGD("skipping [%s] by not required", factory_name);
7226 result = GST_AUTOPLUG_SELECT_SKIP;
7230 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7231 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7232 // TO CHECK : subtitle if needed, add subparse exception.
7233 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7234 result = GST_AUTOPLUG_SELECT_SKIP;
7238 if (g_strrstr(factory_name, "mpegpsdemux")) {
7239 LOGD("skipping PS container - not support");
7240 result = GST_AUTOPLUG_SELECT_SKIP;
7244 if (g_strrstr(factory_name, "mssdemux"))
7245 player->smooth_streaming = TRUE;
7247 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7248 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7251 GstStructure *str = NULL;
7252 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7254 /* don't make video because of not required */
7255 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7256 (!player->set_mode.video_export)) {
7257 LOGD("no need video decoding, expose pad");
7258 result = GST_AUTOPLUG_SELECT_EXPOSE;
7262 /* get w/h for omx state-tune */
7263 /* FIXME: deprecated? */
7264 str = gst_caps_get_structure(caps, 0);
7265 gst_structure_get_int(str, "width", &width);
7268 if (player->v_stream_caps) {
7269 gst_caps_unref(player->v_stream_caps);
7270 player->v_stream_caps = NULL;
7273 player->v_stream_caps = gst_caps_copy(caps);
7274 LOGD("take caps for video state tune");
7275 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7279 if (g_strrstr(klass, "Codec/Decoder")) {
7280 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7281 if (result != GST_AUTOPLUG_SELECT_TRY) {
7282 LOGW("skip add decoder");
7288 MMPLAYER_FREEIF(caps_str);
7294 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7297 //mmplayer_t *player = (mmplayer_t *)data;
7298 GstCaps *caps = NULL;
7300 LOGD("[Decodebin2] pad-removed signal");
7302 caps = gst_pad_query_caps(new_pad, NULL);
7304 LOGW("query caps is NULL");
7308 gchar *caps_str = NULL;
7309 caps_str = gst_caps_to_string(caps);
7311 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7313 MMPLAYER_FREEIF(caps_str);
7314 gst_caps_unref(caps);
7318 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7320 mmplayer_t *player = (mmplayer_t *)data;
7321 GstIterator *iter = NULL;
7322 GValue item = { 0, };
7324 gboolean done = FALSE;
7325 gboolean is_all_drained = TRUE;
7328 MMPLAYER_RETURN_IF_FAIL(player);
7330 LOGD("__mmplayer_gst_decode_drained");
7332 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7333 LOGW("Fail to get cmd lock");
7337 if (!__mmplayer_verify_gapless_play_path(player)) {
7338 LOGD("decoding is finished.");
7339 MMPLAYER_CMD_UNLOCK(player);
7343 _mmplayer_set_reconfigure_state(player, TRUE);
7344 MMPLAYER_CMD_UNLOCK(player);
7346 /* check decodebin src pads whether they received EOS or not */
7347 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7350 switch (gst_iterator_next(iter, &item)) {
7351 case GST_ITERATOR_OK:
7352 pad = g_value_get_object(&item);
7353 if (pad && !GST_PAD_IS_EOS(pad)) {
7354 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7355 is_all_drained = FALSE;
7358 g_value_reset(&item);
7360 case GST_ITERATOR_RESYNC:
7361 gst_iterator_resync(iter);
7363 case GST_ITERATOR_ERROR:
7364 case GST_ITERATOR_DONE:
7369 g_value_unset(&item);
7370 gst_iterator_free(iter);
7372 if (!is_all_drained) {
7373 LOGD("Wait util the all pads get EOS.");
7378 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7379 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7381 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7382 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7383 __mmplayer_deactivate_old_path(player);
7389 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7391 mmplayer_t *player = (mmplayer_t *)data;
7392 const gchar *klass = NULL;
7393 gchar *factory_name = NULL;
7395 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7396 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7398 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7400 if (__mmplayer_add_dump_buffer_probe(player, element))
7401 LOGD("add buffer probe");
7403 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7404 gchar *selected = NULL;
7405 selected = g_strdup(GST_ELEMENT_NAME(element));
7406 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7409 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7410 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7411 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7413 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7414 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7416 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7417 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7418 "max-video-width", player->adaptive_info.limit.width,
7419 "max-video-height", player->adaptive_info.limit.height, NULL);
7421 } else if (g_strrstr(klass, "Demuxer")) {
7423 LOGD("plugged element is demuxer. take it");
7425 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7426 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7429 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7430 int surface_type = 0;
7432 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7435 // to support trust-zone only
7436 if (g_strrstr(factory_name, "asfdemux")) {
7437 LOGD("set file-location %s", player->profile.uri);
7438 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7439 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7440 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7441 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7442 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7443 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7444 (__mmplayer_is_only_mp3_type(player->type))) {
7445 LOGD("[mpegaudioparse] set streaming pull mode.");
7446 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7448 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7449 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7452 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7453 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7454 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7456 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7457 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7459 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7460 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7461 (MMPLAYER_IS_DASH_STREAMING(player))) {
7462 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7463 _mm_player_streaming_set_multiqueue(player->streamer, element);
7464 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7473 __mmplayer_release_misc(mmplayer_t *player)
7476 bool cur_mode = player->set_mode.rich_audio;
7479 MMPLAYER_RETURN_IF_FAIL(player);
7481 player->sent_bos = FALSE;
7482 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7484 player->seek_state = MMPLAYER_SEEK_NONE;
7486 player->total_bitrate = 0;
7487 player->total_maximum_bitrate = 0;
7489 player->not_found_demuxer = 0;
7491 player->last_position = 0;
7492 player->duration = 0;
7493 player->http_content_size = 0;
7494 player->not_supported_codec = MISSING_PLUGIN_NONE;
7495 player->can_support_codec = FOUND_PLUGIN_NONE;
7496 player->pending_seek.is_pending = false;
7497 player->pending_seek.pos = 0;
7498 player->msg_posted = FALSE;
7499 player->has_many_types = FALSE;
7500 player->is_subtitle_force_drop = FALSE;
7501 player->play_subtitle = FALSE;
7502 player->adjust_subtitle_pos = 0;
7503 player->has_closed_caption = FALSE;
7504 player->set_mode.video_export = false;
7505 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7506 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7508 player->set_mode.rich_audio = cur_mode;
7510 if (player->audio_device_cb_id > 0 &&
7511 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7512 LOGW("failed to remove audio device_connected_callback");
7513 player->audio_device_cb_id = 0;
7515 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7516 player->bitrate[i] = 0;
7517 player->maximum_bitrate[i] = 0;
7520 /* free memory related to audio effect */
7521 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7523 if (player->adaptive_info.var_list) {
7524 g_list_free_full(player->adaptive_info.var_list, g_free);
7525 player->adaptive_info.var_list = NULL;
7528 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7529 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7530 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7532 /* Reset video360 settings to their defaults in case if the pipeline is to be
7535 player->video360_metadata.is_spherical = -1;
7536 player->is_openal_plugin_used = FALSE;
7538 player->is_content_spherical = FALSE;
7539 player->is_video360_enabled = TRUE;
7540 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7541 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7542 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7543 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7544 player->video360_zoom = 1.0f;
7545 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7546 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7548 player->sound.rg_enable = false;
7550 __mmplayer_initialize_video_roi(player);
7555 __mmplayer_release_misc_post(mmplayer_t *player)
7557 char *original_uri = NULL;
7560 /* player->pipeline is already released before. */
7561 MMPLAYER_RETURN_IF_FAIL(player);
7563 player->video_decoded_cb = NULL;
7564 player->video_decoded_cb_user_param = NULL;
7565 player->video_stream_prerolled = false;
7567 player->audio_decoded_cb = NULL;
7568 player->audio_decoded_cb_user_param = NULL;
7569 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7571 player->audio_stream_changed_cb = NULL;
7572 player->audio_stream_changed_cb_user_param = NULL;
7574 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7576 /* clean found audio decoders */
7577 if (player->audio_decoders) {
7578 GList *a_dec = player->audio_decoders;
7579 for (; a_dec; a_dec = g_list_next(a_dec)) {
7580 gchar *name = a_dec->data;
7581 MMPLAYER_FREEIF(name);
7583 g_list_free(player->audio_decoders);
7584 player->audio_decoders = NULL;
7587 /* clean the uri list except original uri */
7588 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7589 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7591 LOGW("failed to get original uri info");
7593 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7594 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7596 GList *uri_list = player->uri_info.uri_list;
7597 for (; uri_list; uri_list = g_list_next(uri_list)) {
7598 gchar *uri = uri_list->data;
7599 if (original_uri != uri)
7600 MMPLAYER_FREEIF(uri);
7604 /* clear the audio stream buffer list */
7605 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7607 /* clear the video stream bo list */
7608 __mmplayer_video_stream_destroy_bo_list(player);
7609 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7611 if (player->profile.input_mem.buf) {
7612 free(player->profile.input_mem.buf);
7613 player->profile.input_mem.buf = NULL;
7615 player->profile.input_mem.len = 0;
7616 player->profile.input_mem.offset = 0;
7618 player->uri_info.uri_idx = 0;
7623 __mmplayer_check_subtitle(mmplayer_t *player)
7625 MMHandleType attrs = 0;
7626 char *subtitle_uri = NULL;
7630 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7632 /* get subtitle attribute */
7633 attrs = MMPLAYER_GET_ATTRS(player);
7637 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7638 if (!subtitle_uri || !strlen(subtitle_uri))
7641 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7642 player->is_external_subtitle_present = TRUE;
7650 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7652 MMPLAYER_RETURN_IF_FAIL(player);
7654 if (player->eos_timer) {
7655 LOGD("cancel eos timer");
7656 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7657 player->eos_timer = 0;
7664 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7668 MMPLAYER_RETURN_IF_FAIL(player);
7669 MMPLAYER_RETURN_IF_FAIL(sink);
7671 player->sink_elements = g_list_append(player->sink_elements, sink);
7677 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7681 MMPLAYER_RETURN_IF_FAIL(player);
7682 MMPLAYER_RETURN_IF_FAIL(sink);
7684 player->sink_elements = g_list_remove(player->sink_elements, sink);
7690 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7691 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7693 mmplayer_signal_item_t *item = NULL;
7696 MMPLAYER_RETURN_IF_FAIL(player);
7698 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7699 LOGE("invalid signal type [%d]", type);
7703 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7705 LOGE("cannot connect signal [%s]", signal);
7710 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7711 player->signals[type] = g_list_append(player->signals[type], item);
7717 /* NOTE : be careful with calling this api. please refer to below glib comment
7718 * glib comment : Note that there is a bug in GObject that makes this function much
7719 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7720 * will no longer be called, but, the signal handler is not currently disconnected.
7721 * If the instance is itself being freed at the same time than this doesn't matter,
7722 * since the signal will automatically be removed, but if instance persists,
7723 * then the signal handler will leak. You should not remove the signal yourself
7724 * because in a future versions of GObject, the handler will automatically be
7727 * It's possible to work around this problem in a way that will continue to work
7728 * with future versions of GObject by checking that the signal handler is still
7729 * connected before disconnected it:
7731 * if (g_signal_handler_is_connected(instance, id))
7732 * g_signal_handler_disconnect(instance, id);
7735 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7737 GList *sig_list = NULL;
7738 mmplayer_signal_item_t *item = NULL;
7742 MMPLAYER_RETURN_IF_FAIL(player);
7744 LOGD("release signals type : %d", type);
7746 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7747 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7748 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7749 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7750 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7751 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7755 sig_list = player->signals[type];
7757 for (; sig_list; sig_list = sig_list->next) {
7758 item = sig_list->data;
7760 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7761 if (g_signal_handler_is_connected(item->obj, item->sig))
7762 g_signal_handler_disconnect(item->obj, item->sig);
7765 MMPLAYER_FREEIF(item);
7768 g_list_free(player->signals[type]);
7769 player->signals[type] = NULL;
7777 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7779 mmplayer_t *player = 0;
7780 int prev_display_surface_type = 0;
7784 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7786 player = MM_PLAYER_CAST(handle);
7788 /* check video sinkbin is created */
7789 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7790 LOGW("Videosink is already created");
7791 return MM_ERROR_NONE;
7794 LOGD("videosink element is not yet ready");
7796 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7797 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7799 return MM_ERROR_INVALID_ARGUMENT;
7802 /* load previous attributes */
7803 if (player->attrs) {
7804 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7805 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7806 if (prev_display_surface_type == surface_type) {
7807 LOGD("incoming display surface type is same as previous one, do nothing..");
7809 return MM_ERROR_NONE;
7812 LOGE("failed to load attributes");
7814 return MM_ERROR_PLAYER_INTERNAL;
7817 /* videobin is not created yet, so we just set attributes related to display surface */
7818 LOGD("store display attribute for given surface type(%d)", surface_type);
7819 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7820 "display_overlay", wl_surface_id, NULL);
7823 return MM_ERROR_NONE;
7826 /* Note : if silent is true, then subtitle would not be displayed. :*/
7828 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7830 mmplayer_t *player = (mmplayer_t *)hplayer;
7834 /* check player handle */
7835 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7837 player->set_mode.subtitle_off = silent;
7839 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7843 return MM_ERROR_NONE;
7847 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7849 mmplayer_gst_element_t *mainbin = NULL;
7850 mmplayer_gst_element_t *textbin = NULL;
7851 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7852 GstState current_state = GST_STATE_VOID_PENDING;
7853 GstState element_state = GST_STATE_VOID_PENDING;
7854 GstState element_pending_state = GST_STATE_VOID_PENDING;
7856 GstEvent *event = NULL;
7857 int result = MM_ERROR_NONE;
7859 GstClock *curr_clock = NULL;
7860 GstClockTime base_time, start_time, curr_time;
7865 /* check player handle */
7866 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7868 player->pipeline->mainbin &&
7869 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7871 mainbin = player->pipeline->mainbin;
7872 textbin = player->pipeline->textbin;
7874 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7876 // sync clock with current pipeline
7877 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7878 curr_time = gst_clock_get_time(curr_clock);
7880 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7881 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7883 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7884 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7886 if (current_state > GST_STATE_READY) {
7887 // sync state with current pipeline
7888 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7889 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7890 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7892 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7893 if (GST_STATE_CHANGE_FAILURE == ret) {
7894 LOGE("fail to state change.");
7895 result = MM_ERROR_PLAYER_INTERNAL;
7899 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7900 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7903 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7904 gst_object_unref(curr_clock);
7907 // seek to current position
7908 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7909 result = MM_ERROR_PLAYER_INVALID_STATE;
7910 LOGE("gst_element_query_position failed, invalid state");
7914 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7915 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);
7917 _mmplayer_gst_send_event_to_sink(player, event);
7919 result = MM_ERROR_PLAYER_INTERNAL;
7920 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7924 /* sync state with current pipeline */
7925 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7926 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7927 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7929 return MM_ERROR_NONE;
7932 /* release text pipeline resource */
7933 player->textsink_linked = 0;
7935 /* release signal */
7936 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7938 /* release textbin with it's childs */
7939 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7940 MMPLAYER_FREEIF(player->pipeline->textbin);
7941 player->pipeline->textbin = NULL;
7943 /* release subtitle elem */
7944 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7945 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7951 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7953 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7954 GstState current_state = GST_STATE_VOID_PENDING;
7956 MMHandleType attrs = 0;
7957 mmplayer_gst_element_t *mainbin = NULL;
7958 mmplayer_gst_element_t *textbin = NULL;
7960 gchar *subtitle_uri = NULL;
7961 int result = MM_ERROR_NONE;
7962 const gchar *charset = NULL;
7966 /* check player handle */
7967 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7969 player->pipeline->mainbin &&
7970 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7971 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7973 mainbin = player->pipeline->mainbin;
7974 textbin = player->pipeline->textbin;
7976 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7977 if (current_state < GST_STATE_READY) {
7978 result = MM_ERROR_PLAYER_INVALID_STATE;
7979 LOGE("Pipeline is not in proper state");
7983 attrs = MMPLAYER_GET_ATTRS(player);
7985 LOGE("cannot get content attribute");
7986 result = MM_ERROR_PLAYER_INTERNAL;
7990 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7991 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7992 LOGE("subtitle uri is not proper filepath");
7993 result = MM_ERROR_PLAYER_INVALID_URI;
7997 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7998 LOGE("failed to get storage info of subtitle path");
7999 result = MM_ERROR_PLAYER_INVALID_URI;
8003 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8004 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8006 if (!strcmp(filepath, subtitle_uri)) {
8007 LOGD("subtitle path is not changed");
8010 if (mm_player_set_attribute((MMHandleType)player, NULL,
8011 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8012 LOGE("failed to set attribute");
8017 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8018 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8019 player->subtitle_language_list = NULL;
8020 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8022 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8023 if (ret != GST_STATE_CHANGE_SUCCESS) {
8024 LOGE("failed to change state of textbin to READY");
8025 result = MM_ERROR_PLAYER_INTERNAL;
8029 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8030 if (ret != GST_STATE_CHANGE_SUCCESS) {
8031 LOGE("failed to change state of subparse to READY");
8032 result = MM_ERROR_PLAYER_INTERNAL;
8036 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8037 if (ret != GST_STATE_CHANGE_SUCCESS) {
8038 LOGE("failed to change state of filesrc to READY");
8039 result = MM_ERROR_PLAYER_INTERNAL;
8043 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8045 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8047 charset = _mmplayer_get_charset(filepath);
8049 LOGD("detected charset is %s", charset);
8050 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8053 result = _mmplayer_sync_subtitle_pipeline(player);
8060 /* API to switch between external subtitles */
8062 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8064 int result = MM_ERROR_NONE;
8065 mmplayer_t *player = (mmplayer_t *)hplayer;
8070 /* check player handle */
8071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8073 /* filepath can be null in idle state */
8075 /* check file path */
8076 if ((path = strstr(filepath, "file://")))
8077 result = _mmplayer_exist_file_path(path + 7);
8079 result = _mmplayer_exist_file_path(filepath);
8081 if (result != MM_ERROR_NONE) {
8082 LOGE("invalid subtitle path 0x%X", result);
8083 return result; /* file not found or permission denied */
8087 if (!player->pipeline) {
8089 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8090 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8091 LOGE("failed to set attribute");
8092 return MM_ERROR_PLAYER_INTERNAL;
8095 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8096 /* check filepath */
8097 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8099 if (!__mmplayer_check_subtitle(player)) {
8100 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8101 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8102 LOGE("failed to set attribute");
8103 return MM_ERROR_PLAYER_INTERNAL;
8106 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8107 LOGE("fail to create text pipeline");
8108 return MM_ERROR_PLAYER_INTERNAL;
8111 result = _mmplayer_sync_subtitle_pipeline(player);
8113 result = __mmplayer_change_external_subtitle_language(player, filepath);
8116 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8117 player->is_external_subtitle_added_now = TRUE;
8119 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8120 if (!player->subtitle_language_list) {
8121 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8122 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8123 LOGW("subtitle language list is not updated yet");
8125 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8133 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8135 int result = MM_ERROR_NONE;
8136 gchar *change_pad_name = NULL;
8137 GstPad *sinkpad = NULL;
8138 mmplayer_gst_element_t *mainbin = NULL;
8139 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8140 GstCaps *caps = NULL;
8141 gint total_track_num = 0;
8145 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8146 MM_ERROR_PLAYER_NOT_INITIALIZED);
8148 LOGD("Change Track(%d) to %d", type, index);
8150 mainbin = player->pipeline->mainbin;
8152 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8153 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8154 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8155 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8157 /* Changing Video Track is not supported. */
8158 LOGE("Track Type Error");
8162 if (mainbin[elem_idx].gst == NULL) {
8163 result = MM_ERROR_PLAYER_NO_OP;
8164 LOGD("Req track doesn't exist");
8168 total_track_num = player->selector[type].total_track_num;
8169 if (total_track_num <= 0) {
8170 result = MM_ERROR_PLAYER_NO_OP;
8171 LOGD("Language list is not available");
8175 if ((index < 0) || (index >= total_track_num)) {
8176 result = MM_ERROR_INVALID_ARGUMENT;
8177 LOGD("Not a proper index : %d", index);
8181 /*To get the new pad from the selector*/
8182 change_pad_name = g_strdup_printf("sink_%u", index);
8183 if (change_pad_name == NULL) {
8184 result = MM_ERROR_PLAYER_INTERNAL;
8185 LOGD("Pad does not exists");
8189 LOGD("new active pad name: %s", change_pad_name);
8191 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8192 if (sinkpad == NULL) {
8193 LOGD("sinkpad is NULL");
8194 result = MM_ERROR_PLAYER_INTERNAL;
8198 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8199 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8201 caps = gst_pad_get_current_caps(sinkpad);
8202 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8205 gst_object_unref(sinkpad);
8207 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8208 __mmplayer_set_audio_attrs(player, caps);
8211 MMPLAYER_FREEIF(change_pad_name);
8216 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8218 int result = MM_ERROR_NONE;
8219 mmplayer_t *player = NULL;
8220 mmplayer_gst_element_t *mainbin = NULL;
8222 gint current_active_index = 0;
8224 GstState current_state = GST_STATE_VOID_PENDING;
8225 GstEvent *event = NULL;
8230 player = (mmplayer_t *)hplayer;
8231 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8233 if (!player->pipeline) {
8234 LOGE("Track %d pre setting -> %d", type, index);
8236 player->selector[type].active_pad_index = index;
8240 mainbin = player->pipeline->mainbin;
8242 current_active_index = player->selector[type].active_pad_index;
8244 /*If index is same as running index no need to change the pad*/
8245 if (current_active_index == index)
8248 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8249 result = MM_ERROR_PLAYER_INVALID_STATE;
8253 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8254 if (current_state < GST_STATE_PAUSED) {
8255 result = MM_ERROR_PLAYER_INVALID_STATE;
8256 LOGW("Pipeline not in porper state");
8260 result = __mmplayer_change_selector_pad(player, type, index);
8261 if (result != MM_ERROR_NONE) {
8262 LOGE("change selector pad error");
8266 player->selector[type].active_pad_index = index;
8268 if (current_state == GST_STATE_PLAYING) {
8269 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8270 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8271 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8273 _mmplayer_gst_send_event_to_sink(player, event);
8275 result = MM_ERROR_PLAYER_INTERNAL;
8285 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8287 mmplayer_t *player = (mmplayer_t *)hplayer;
8291 /* check player handle */
8292 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8294 *silent = player->set_mode.subtitle_off;
8296 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8300 return MM_ERROR_NONE;
8304 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8306 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8307 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8309 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8310 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8314 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8315 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8316 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8317 mmplayer_dump_t *dump_s;
8318 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8319 if (dump_s == NULL) {
8320 LOGE("malloc fail");
8324 dump_s->dump_element_file = NULL;
8325 dump_s->dump_pad = NULL;
8326 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8328 if (dump_s->dump_pad) {
8329 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8330 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]);
8331 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8332 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);
8333 /* add list for removed buffer probe and close FILE */
8334 player->dump_list = g_list_append(player->dump_list, dump_s);
8335 LOGD("%s sink pad added buffer probe for dump", factory_name);
8338 MMPLAYER_FREEIF(dump_s);
8339 LOGE("failed to get %s sink pad added", factory_name);
8346 static GstPadProbeReturn
8347 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8349 FILE *dump_data = (FILE *)u_data;
8351 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8352 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8354 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8356 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8358 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8360 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8362 gst_buffer_unmap(buffer, &probe_info);
8364 return GST_PAD_PROBE_OK;
8368 __mmplayer_release_dump_list(GList *dump_list)
8370 GList *d_list = dump_list;
8375 for (; d_list; d_list = g_list_next(d_list)) {
8376 mmplayer_dump_t *dump_s = d_list->data;
8377 if (dump_s->dump_pad) {
8378 if (dump_s->probe_handle_id)
8379 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8380 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8382 if (dump_s->dump_element_file) {
8383 fclose(dump_s->dump_element_file);
8384 dump_s->dump_element_file = NULL;
8386 MMPLAYER_FREEIF(dump_s);
8388 g_list_free(dump_list);
8393 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8395 mmplayer_t *player = (mmplayer_t *)hplayer;
8399 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8400 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8402 *exist = (bool)player->has_closed_caption;
8406 return MM_ERROR_NONE;
8410 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8415 LOGD("unref internal gst buffer %p", buffer);
8417 gst_buffer_unref((GstBuffer *)buffer);
8424 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8426 mmplayer_t *player = (mmplayer_t *)hplayer;
8430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8431 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8433 if (MMPLAYER_IS_STREAMING(player))
8434 *timeout = (int)player->ini.live_state_change_timeout;
8436 *timeout = (int)player->ini.localplayback_state_change_timeout;
8438 LOGD("timeout = %d", *timeout);
8441 return MM_ERROR_NONE;
8445 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8449 MMPLAYER_RETURN_IF_FAIL(player);
8451 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8453 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8454 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8455 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8456 player->storage_info[i].id = -1;
8457 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8459 if (path_type != MMPLAYER_PATH_MAX)
8468 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8470 int ret = MM_ERROR_NONE;
8471 mmplayer_t *player = (mmplayer_t *)hplayer;
8472 MMMessageParamType msg_param = {0, };
8475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8477 LOGW("state changed storage %d:%d", id, state);
8479 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8480 return MM_ERROR_NONE;
8482 /* FIXME: text path should be handled seperately. */
8483 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8484 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8485 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8486 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8487 LOGW("external storage is removed");
8489 if (player->msg_posted == FALSE) {
8490 memset(&msg_param, 0, sizeof(MMMessageParamType));
8491 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8492 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8493 player->msg_posted = TRUE;
8496 /* unrealize the player */
8497 ret = _mmplayer_unrealize(hplayer);
8498 if (ret != MM_ERROR_NONE)
8499 LOGE("failed to unrealize");
8507 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8509 int ret = MM_ERROR_NONE;
8510 mmplayer_t *player = (mmplayer_t *)hplayer;
8511 int idx = 0, total = 0;
8512 gchar *result = NULL, *tmp = NULL;
8515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8516 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8518 total = *num = g_list_length(player->adaptive_info.var_list);
8520 LOGW("There is no stream variant info.");
8524 result = g_strdup("");
8525 for (idx = 0 ; idx < total ; idx++) {
8526 stream_variant_t *v_data = NULL;
8527 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8530 gchar data[64] = {0};
8531 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8533 tmp = g_strconcat(result, data, NULL);
8537 LOGW("There is no variant data in %d", idx);
8542 *var_info = (char *)result;
8544 LOGD("variant info %d:%s", *num, *var_info);
8550 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8552 int ret = MM_ERROR_NONE;
8553 mmplayer_t *player = (mmplayer_t *)hplayer;
8556 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8558 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8560 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8561 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8562 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8564 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8565 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8566 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8567 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8569 /* FIXME: seek to current position for applying new variant limitation */
8578 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8580 int ret = MM_ERROR_NONE;
8581 mmplayer_t *player = (mmplayer_t *)hplayer;
8584 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8585 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8587 *bandwidth = player->adaptive_info.limit.bandwidth;
8588 *width = player->adaptive_info.limit.width;
8589 *height = player->adaptive_info.limit.height;
8591 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8598 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8600 int ret = MM_ERROR_NONE;
8601 mmplayer_t *player = (mmplayer_t *)hplayer;
8604 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8605 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8606 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8608 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8610 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8611 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8612 else /* live case */
8613 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8615 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8622 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8624 #define IDX_FIRST_SW_CODEC 0
8625 mmplayer_t *player = (mmplayer_t *)hplayer;
8626 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8631 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8632 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8633 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8635 switch (stream_type) {
8636 case MM_PLAYER_STREAM_TYPE_AUDIO:
8637 /* to support audio codec selection, codec info have to be added in ini file as below.
8638 audio codec element hw = xxxx
8639 audio codec element sw = avdec
8640 and in case of audio hw codec is supported and selected,
8641 audio filter elements should be applied depending on the hw capabilities.
8643 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8644 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8645 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8646 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8647 LOGE("There is no audio codec info for codec_type %d", codec_type);
8648 return MM_ERROR_PLAYER_NO_OP;
8651 case MM_PLAYER_STREAM_TYPE_VIDEO:
8652 /* to support video codec selection, codec info have to be added in ini file as below.
8653 video codec element hw = omx
8654 video codec element sw = avdec */
8655 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8656 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8657 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8658 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8659 LOGE("There is no video codec info for codec_type %d", codec_type);
8660 return MM_ERROR_PLAYER_NO_OP;
8664 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8665 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8669 LOGD("update %s codec_type to %d", attr_name, codec_type);
8670 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8673 return MM_ERROR_NONE;
8677 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8679 mmplayer_t *player = (mmplayer_t *)hplayer;
8680 GstElement *rg_vol_element = NULL;
8684 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8686 player->sound.rg_enable = enabled;
8688 /* just hold rgvolume enable value if pipeline is not ready */
8689 if (!player->pipeline || !player->pipeline->audiobin) {
8690 LOGD("pipeline is not ready. holding rgvolume enable value");
8691 return MM_ERROR_NONE;
8694 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8696 if (!rg_vol_element) {
8697 LOGD("rgvolume element is not created");
8698 return MM_ERROR_PLAYER_INTERNAL;
8702 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8704 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8708 return MM_ERROR_NONE;
8712 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8714 mmplayer_t *player = (mmplayer_t *)hplayer;
8715 GstElement *rg_vol_element = NULL;
8716 gboolean enable = FALSE;
8720 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8721 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8723 /* just hold enable_rg value if pipeline is not ready */
8724 if (!player->pipeline || !player->pipeline->audiobin) {
8725 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8726 *enabled = player->sound.rg_enable;
8727 return MM_ERROR_NONE;
8730 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8732 if (!rg_vol_element) {
8733 LOGD("rgvolume element is not created");
8734 return MM_ERROR_PLAYER_INTERNAL;
8737 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8738 *enabled = (bool)enable;
8742 return MM_ERROR_NONE;
8746 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8748 mmplayer_t *player = (mmplayer_t *)hplayer;
8749 MMHandleType attrs = 0;
8751 int ret = MM_ERROR_NONE;
8755 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8757 attrs = MMPLAYER_GET_ATTRS(player);
8758 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8760 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8762 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8763 return MM_ERROR_PLAYER_INTERNAL;
8766 player->video_roi.scale_x = scale_x;
8767 player->video_roi.scale_y = scale_y;
8768 player->video_roi.scale_width = scale_width;
8769 player->video_roi.scale_height = scale_height;
8771 /* check video sinkbin is created */
8772 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8773 return MM_ERROR_NONE;
8775 if (!gst_video_overlay_set_video_roi_area(
8776 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8777 scale_x, scale_y, scale_width, scale_height))
8778 ret = MM_ERROR_PLAYER_INTERNAL;
8780 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8781 scale_x, scale_y, scale_width, scale_height);
8789 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8791 mmplayer_t *player = (mmplayer_t *)hplayer;
8792 int ret = MM_ERROR_NONE;
8796 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8797 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8799 *scale_x = player->video_roi.scale_x;
8800 *scale_y = player->video_roi.scale_y;
8801 *scale_width = player->video_roi.scale_width;
8802 *scale_height = player->video_roi.scale_height;
8804 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8805 *scale_x, *scale_y, *scale_width, *scale_height);
8811 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8813 mmplayer_t *player = (mmplayer_t *)hplayer;
8817 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8819 player->client_pid = pid;
8821 LOGD("client pid[%d] %p", pid, player);
8825 return MM_ERROR_NONE;
8829 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8831 mmplayer_t *player = (mmplayer_t *)hplayer;
8832 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8833 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8838 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8841 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8843 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8845 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8846 return MM_ERROR_NONE;
8848 /* in case of audio codec default type is HW */
8850 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8851 if (player->ini.support_audio_effect)
8852 return MM_ERROR_NONE;
8853 elem_id = MMPLAYER_A_FILTER;
8855 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8856 if (player->ini.support_replaygain_control)
8857 return MM_ERROR_NONE;
8858 elem_id = MMPLAYER_A_RGVOL;
8860 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8861 if (player->ini.support_pitch_control)
8862 return MM_ERROR_NONE;
8863 elem_id = MMPLAYER_A_PITCH;
8865 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8866 if (player->ini.support_audio_effect)
8867 return MM_ERROR_NONE;
8869 /* default case handling is not required */
8872 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8873 LOGW("audio control option [%d] is not available", opt);
8876 /* setting pcm exporting option is allowed before READY state */
8877 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8878 return MM_ERROR_PLAYER_INVALID_STATE;
8880 /* check whether the audio filter exist or not after READY state,
8881 because the sw codec could be added during auto-plugging in some cases */
8882 if (!player->pipeline ||
8883 !player->pipeline->audiobin ||
8884 !player->pipeline->audiobin[elem_id].gst) {
8885 LOGW("there is no audio elem [%d]", elem_id);
8890 LOGD("audio control opt %d, available %d", opt, *available);
8894 return MM_ERROR_NONE;
8898 __mmplayer_update_duration_value(mmplayer_t *player)
8900 gboolean ret = FALSE;
8901 gint64 dur_nsec = 0;
8902 LOGD("try to update duration");
8904 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8905 player->duration = dur_nsec;
8906 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8910 if (player->duration < 0) {
8911 LOGW("duration is Non-Initialized !!!");
8912 player->duration = 0;
8915 /* update streaming service type */
8916 player->streaming_type = _mmplayer_get_stream_service_type(player);
8918 /* check duration is OK */
8919 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8920 /* FIXIT : find another way to get duration here. */
8921 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8927 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8929 /* update audio params
8930 NOTE : We need original audio params and it can be only obtained from src pad of audio
8931 decoder. Below code only valid when we are not using 'resampler' just before
8932 'audioconverter'. */
8933 GstCaps *caps_a = NULL;
8935 gint samplerate = 0, channels = 0;
8936 GstStructure *p = NULL;
8937 GstElement *aconv = NULL;
8939 LOGD("try to update audio attrs");
8941 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8943 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8944 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8945 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8946 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8948 LOGE("there is no audio converter");
8952 pad = gst_element_get_static_pad(aconv, "sink");
8955 LOGW("failed to get pad from audio converter");
8959 caps_a = gst_pad_get_current_caps(pad);
8961 LOGW("not ready to get audio caps");
8962 gst_object_unref(pad);
8966 p = gst_caps_get_structure(caps_a, 0);
8968 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8970 gst_structure_get_int(p, "rate", &samplerate);
8971 gst_structure_get_int(p, "channels", &channels);
8973 mm_player_set_attribute((MMHandleType)player, NULL,
8974 "content_audio_samplerate", samplerate,
8975 "content_audio_channels", channels, NULL);
8977 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8979 gst_caps_unref(caps_a);
8980 gst_object_unref(pad);
8986 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8988 LOGD("try to update video attrs");
8990 GstCaps *caps_v = NULL;
8994 GstStructure *p = NULL;
8996 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8997 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8999 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9001 LOGD("no videosink sink pad");
9005 caps_v = gst_pad_get_current_caps(pad);
9006 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9007 if (!caps_v && player->v_stream_caps) {
9008 caps_v = player->v_stream_caps;
9009 gst_caps_ref(caps_v);
9013 LOGD("no negitiated caps from videosink");
9014 gst_object_unref(pad);
9018 p = gst_caps_get_structure(caps_v, 0);
9019 gst_structure_get_int(p, "width", &width);
9020 gst_structure_get_int(p, "height", &height);
9022 mm_player_set_attribute((MMHandleType)player, NULL,
9023 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9025 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9027 SECURE_LOGD("width : %d height : %d", width, height);
9029 gst_caps_unref(caps_v);
9030 gst_object_unref(pad);
9033 mm_player_set_attribute((MMHandleType)player, NULL,
9034 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9035 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9042 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9044 gboolean ret = FALSE;
9045 guint64 data_size = 0;
9049 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9050 if (!player->duration)
9053 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9054 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9055 if (stat(path, &sb) == 0)
9056 data_size = (guint64)sb.st_size;
9058 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9059 data_size = player->http_content_size;
9062 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9065 guint64 bitrate = 0;
9066 guint64 msec_dur = 0;
9068 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9070 bitrate = data_size * 8 * 1000 / msec_dur;
9071 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9072 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9073 mm_player_set_attribute((MMHandleType)player, NULL,
9074 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9077 LOGD("player duration is less than 0");
9081 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9082 if (player->total_bitrate) {
9083 mm_player_set_attribute((MMHandleType)player, NULL,
9084 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9093 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9095 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9096 data->uri_type = uri_type;
9100 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9102 int ret = MM_ERROR_PLAYER_INVALID_URI;
9104 char *buffer = NULL;
9105 char *seperator = strchr(path, ',');
9106 char ext[100] = {0,}, size[100] = {0,};
9109 if ((buffer = strstr(path, "ext="))) {
9110 buffer += strlen("ext=");
9112 if (strlen(buffer)) {
9113 strncpy(ext, buffer, 99);
9115 if ((seperator = strchr(ext, ','))
9116 || (seperator = strchr(ext, ' '))
9117 || (seperator = strchr(ext, '\0'))) {
9118 seperator[0] = '\0';
9123 if ((buffer = strstr(path, "size="))) {
9124 buffer += strlen("size=");
9126 if (strlen(buffer) > 0) {
9127 strncpy(size, buffer, 99);
9129 if ((seperator = strchr(size, ','))
9130 || (seperator = strchr(size, ' '))
9131 || (seperator = strchr(size, '\0'))) {
9132 seperator[0] = '\0';
9135 mem_size = atoi(size);
9140 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9142 if (mem_size && param) {
9143 if (data->input_mem.buf)
9144 free(data->input_mem.buf);
9145 data->input_mem.buf = malloc(mem_size);
9147 if (data->input_mem.buf) {
9148 memcpy(data->input_mem.buf, param, mem_size);
9149 data->input_mem.len = mem_size;
9150 ret = MM_ERROR_NONE;
9152 LOGE("failed to alloc mem %d", mem_size);
9153 ret = MM_ERROR_PLAYER_INTERNAL;
9156 data->input_mem.offset = 0;
9157 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9164 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9166 gchar *location = NULL;
9169 int ret = MM_ERROR_NONE;
9171 if ((path = strstr(uri, "file://"))) {
9172 location = g_filename_from_uri(uri, NULL, &err);
9173 if (!location || (err != NULL)) {
9174 LOGE("Invalid URI '%s' for filesrc: %s", path,
9175 (err != NULL) ? err->message : "unknown error");
9179 MMPLAYER_FREEIF(location);
9181 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9182 return MM_ERROR_PLAYER_INVALID_URI;
9184 LOGD("path from uri: %s", location);
9187 path = (location != NULL) ? (location) : ((char *)uri);
9190 ret = _mmplayer_exist_file_path(path);
9192 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9193 if (ret == MM_ERROR_NONE) {
9194 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9195 if (_mmplayer_is_sdp_file(path)) {
9196 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9197 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9199 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9201 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9202 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9204 LOGE("invalid uri, could not play..");
9205 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9208 MMPLAYER_FREEIF(location);
9213 static mmplayer_video_decoded_data_info_t *
9214 __mmplayer_create_stream_from_pad(GstPad *pad)
9216 GstCaps *caps = NULL;
9217 GstStructure *structure = NULL;
9218 unsigned int fourcc = 0;
9219 const gchar *string_format = NULL;
9220 mmplayer_video_decoded_data_info_t *stream = NULL;
9222 MMPixelFormatType format;
9225 caps = gst_pad_get_current_caps(pad);
9227 LOGE("Caps is NULL.");
9232 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9234 structure = gst_caps_get_structure(caps, 0);
9235 gst_structure_get_int(structure, "width", &width);
9236 gst_structure_get_int(structure, "height", &height);
9237 string_format = gst_structure_get_string(structure, "format");
9240 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9241 format = _mmplayer_get_pixtype(fourcc);
9242 gst_video_info_from_caps(&info, caps);
9243 gst_caps_unref(caps);
9246 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9247 LOGE("Wrong condition!!");
9251 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9253 LOGE("failed to alloc mem for video data");
9257 stream->width = width;
9258 stream->height = height;
9259 stream->format = format;
9260 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9266 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9268 unsigned int pitch = 0;
9269 unsigned int size = 0;
9271 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9274 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9275 bo = gst_tizen_memory_get_bos(mem, index);
9277 stream->bo[index] = tbm_bo_ref(bo);
9279 LOGE("failed to get bo for index %d", index);
9282 for (index = 0; index < stream->plane_num; index++) {
9283 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9284 stream->stride[index] = pitch;
9286 stream->elevation[index] = size / pitch;
9288 stream->elevation[index] = stream->height;
9293 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9295 if (stream->format == MM_PIXEL_FORMAT_I420) {
9296 int ret = TBM_SURFACE_ERROR_NONE;
9297 tbm_surface_h surface;
9298 tbm_surface_info_s info;
9300 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9302 ret = tbm_surface_get_info(surface, &info);
9303 if (ret != TBM_SURFACE_ERROR_NONE) {
9304 tbm_surface_destroy(surface);
9308 tbm_surface_destroy(surface);
9309 stream->stride[0] = info.planes[0].stride;
9310 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9311 stream->stride[1] = info.planes[1].stride;
9312 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9313 stream->stride[2] = info.planes[2].stride;
9314 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9315 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9316 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9317 stream->stride[0] = stream->width * 4;
9318 stream->elevation[0] = stream->height;
9319 stream->bo_size = stream->stride[0] * stream->height;
9321 LOGE("Not support format %d", stream->format);
9329 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9331 tbm_bo_handle thandle;
9333 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9334 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9335 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9339 unsigned char *src = NULL;
9340 unsigned char *dest = NULL;
9341 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9343 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9345 LOGE("fail to gst_memory_map");
9349 if (!mapinfo.data) {
9350 LOGE("data pointer is wrong");
9354 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9355 if (!stream->bo[0]) {
9356 LOGE("Fail to tbm_bo_alloc!!");
9360 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9362 LOGE("thandle pointer is wrong");
9366 if (stream->format == MM_PIXEL_FORMAT_I420) {
9367 src_stride[0] = GST_ROUND_UP_4(stream->width);
9368 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9369 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9370 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9373 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9374 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9376 for (i = 0; i < 3; i++) {
9377 src = mapinfo.data + src_offset[i];
9378 dest = thandle.ptr + dest_offset[i];
9383 for (j = 0; j < stream->height >> k; j++) {
9384 memcpy(dest, src, stream->width>>k);
9385 src += src_stride[i];
9386 dest += stream->stride[i];
9389 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9390 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9392 LOGE("Not support format %d", stream->format);
9396 tbm_bo_unmap(stream->bo[0]);
9397 gst_memory_unmap(mem, &mapinfo);
9403 tbm_bo_unmap(stream->bo[0]);
9406 gst_memory_unmap(mem, &mapinfo);
9412 __mmplayer_set_pause_state(mmplayer_t *player)
9414 if (player->sent_bos)
9417 /* rtsp case, get content attrs by GstMessage */
9418 if (MMPLAYER_IS_RTSP_STREAMING(player))
9421 /* it's first time to update all content attrs. */
9422 _mmplayer_update_content_attrs(player, ATTR_ALL);
9426 __mmplayer_set_playing_state(mmplayer_t *player)
9428 gchar *audio_codec = NULL;
9430 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9431 /* initialize because auto resume is done well. */
9432 player->resumed_by_rewind = FALSE;
9433 player->playback_rate = 1.0;
9436 if (player->sent_bos)
9439 /* try to get content metadata */
9441 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9442 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9443 * legacy mmfw-player api
9445 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9447 if ((player->cmd == MMPLAYER_COMMAND_START)
9448 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9449 __mmplayer_handle_missed_plugin(player);
9452 /* check audio codec field is set or not
9453 * we can get it from typefinder or codec's caps.
9455 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9457 /* The codec format can't be sent for audio only case like amr, mid etc.
9458 * Because, parser don't make related TAG.
9459 * So, if it's not set yet, fill it with found data.
9462 if (g_strrstr(player->type, "audio/midi"))
9463 audio_codec = "MIDI";
9464 else if (g_strrstr(player->type, "audio/x-amr"))
9465 audio_codec = "AMR";
9466 else if (g_strrstr(player->type, "audio/mpeg")
9467 && !g_strrstr(player->type, "mpegversion=(int)1"))
9468 audio_codec = "AAC";
9470 audio_codec = "unknown";
9472 if (mm_player_set_attribute((MMHandleType)player, NULL,
9473 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9474 LOGE("failed to set attribute");
9476 LOGD("set audio codec type with caps");