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_watcher_removed_notify(gpointer data)
761 mmplayer_t *player = (mmplayer_t *)data;
762 MMPLAYER_RETURN_IF_FAIL(player);
764 MMPLAYER_BUS_WATCHER_LOCK(player);
765 player->bus_watcher = 0;
766 MMPLAYER_BUS_WATCHER_SIGNAL(player);
767 MMPLAYER_BUS_WATCHER_UNLOCK(player);
771 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
773 mmplayer_t *player = (mmplayer_t *)hplayer;
776 MMPLAYER_RETURN_IF_FAIL(player);
778 /* disconnecting bus watch */
779 if (player->bus_watcher > 0) {
780 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
781 MMPLAYER_BUS_WATCHER_LOCK(player);
782 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
783 while (player->bus_watcher > 0)
784 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
785 MMPLAYER_BUS_WATCHER_UNLOCK(player);
787 g_mutex_clear(&player->bus_watcher_mutex);
788 g_cond_clear(&player->bus_watcher_cond);
795 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
797 mmplayer_t *player = (mmplayer_t *)hplayer;
798 GstMessage *msg = NULL;
799 GQueue *queue = NULL;
802 MMPLAYER_RETURN_IF_FAIL(player);
804 /* destroy the gst bus msg thread */
805 if (player->bus_msg_thread) {
806 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
807 player->bus_msg_thread_exit = TRUE;
808 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
809 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
811 LOGD("gst bus msg thread exit.");
812 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
813 player->bus_msg_thread = NULL;
815 g_mutex_clear(&player->bus_msg_thread_mutex);
816 g_cond_clear(&player->bus_msg_thread_cond);
819 g_mutex_lock(&player->bus_msg_q_lock);
820 queue = player->bus_msg_q;
821 while (!g_queue_is_empty(queue)) {
822 msg = (GstMessage *)g_queue_pop_head(queue);
827 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
828 gst_message_unref(msg);
830 g_mutex_unlock(&player->bus_msg_q_lock);
836 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
838 GstElement *parent = NULL;
840 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
841 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
844 MMPLAYER_FSINK_LOCK(player);
846 /* get parent of fakesink */
847 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
849 LOGD("fakesink already removed");
853 gst_element_set_locked_state(fakesink->gst, TRUE);
855 /* setting the state to NULL never returns async
856 * so no need to wait for completion of state transiton
858 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
859 LOGE("fakesink state change failure!");
860 /* FIXIT : should I return here? or try to proceed to next? */
863 /* remove fakesink from it's parent */
864 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
865 LOGE("failed to remove fakesink");
867 gst_object_unref(parent);
872 gst_object_unref(parent);
874 LOGD("state-holder removed");
876 gst_element_set_locked_state(fakesink->gst, FALSE);
878 MMPLAYER_FSINK_UNLOCK(player);
883 gst_element_set_locked_state(fakesink->gst, FALSE);
885 MMPLAYER_FSINK_UNLOCK(player);
889 static GstPadProbeReturn
890 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
892 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
893 return GST_PAD_PROBE_OK;
897 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
899 gint64 stop_running_time = 0;
900 gint64 position_running_time = 0;
904 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
905 if ((player->gapless.update_segment[idx] == TRUE) ||
906 !(player->selector[idx].event_probe_id)) {
908 LOGW("[%d] skip", idx);
913 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
915 gst_segment_to_running_time(&player->gapless.segment[idx],
916 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
917 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
919 gst_segment_to_running_time(&player->gapless.segment[idx],
920 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
922 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
924 gst_segment_to_running_time(&player->gapless.segment[idx],
925 GST_FORMAT_TIME, player->duration);
928 position_running_time =
929 gst_segment_to_running_time(&player->gapless.segment[idx],
930 GST_FORMAT_TIME, player->gapless.segment[idx].position);
932 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
933 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
935 GST_TIME_ARGS(stop_running_time),
936 GST_TIME_ARGS(position_running_time),
937 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
938 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
940 position_running_time = MAX(position_running_time, stop_running_time);
941 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].start);
943 position_running_time = MAX(0, position_running_time);
944 position = MAX(position, position_running_time);
948 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
949 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
950 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
952 player->gapless.start_time[stream_type] += position;
958 static GstPadProbeReturn
959 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
961 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
962 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
963 mmplayer_t *player = (mmplayer_t *)data;
964 GstCaps *caps = NULL;
965 GstStructure *str = NULL;
966 const gchar *name = NULL;
967 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
968 gboolean caps_ret = TRUE;
970 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
971 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
972 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
973 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
974 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
977 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
981 if (strstr(name, "audio")) {
982 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
983 } else if (strstr(name, "video")) {
984 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
986 /* text track is not supportable */
987 LOGE("invalid name %s", name);
991 switch (GST_EVENT_TYPE(event)) {
994 /* in case of gapless, drop eos event not to send it to sink */
995 if (player->gapless.reconfigure && !player->msg_posted) {
996 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
997 ret = GST_PAD_PROBE_DROP;
1001 case GST_EVENT_STREAM_START:
1003 __mmplayer_gst_selector_update_start_time(player, stream_type);
1006 case GST_EVENT_FLUSH_STOP:
1008 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1009 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1010 player->gapless.start_time[stream_type] = 0;
1013 case GST_EVENT_SEGMENT:
1018 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1019 gst_event_copy_segment(event, &segment);
1021 if (segment.format != GST_FORMAT_TIME)
1024 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1025 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1026 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1027 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1028 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1029 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1031 /* keep the all the segment ev to cover the seeking */
1032 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1033 player->gapless.update_segment[stream_type] = TRUE;
1035 if (!player->gapless.running)
1038 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1040 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1042 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1043 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1044 gst_event_unref(event);
1045 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1051 gdouble proportion = 0.0;
1052 GstClockTimeDiff diff = 0;
1053 GstClockTime timestamp = 0;
1054 gint64 running_time_diff = -1;
1055 GstQOSType type = 0;
1056 GstEvent *tmpev = NULL;
1058 running_time_diff = player->gapless.segment[stream_type].base;
1060 if (running_time_diff <= 0) /* don't need to adjust */
1063 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1064 gst_event_unref(event);
1066 if (timestamp < running_time_diff) {
1067 LOGW("QOS event from previous group");
1068 ret = GST_PAD_PROBE_DROP;
1073 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1074 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1075 stream_type, GST_TIME_ARGS(timestamp),
1076 GST_TIME_ARGS(running_time_diff),
1077 GST_TIME_ARGS(timestamp - running_time_diff));
1080 timestamp -= running_time_diff;
1082 /* That case is invalid for QoS events */
1083 if (diff < 0 && -diff > timestamp) {
1084 LOGW("QOS event from previous group");
1085 ret = GST_PAD_PROBE_DROP;
1089 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1090 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1100 gst_caps_unref(caps);
1104 /* create fakesink for audio or video path witout audiobin or videobin */
1106 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1108 GstElement *pipeline = NULL;
1109 GstElement *fakesink = NULL;
1110 GstPad *sinkpad = NULL;
1113 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1115 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1118 fakesink = gst_element_factory_make("fakesink", NULL);
1119 if (fakesink == NULL) {
1120 LOGE("failed to create fakesink");
1124 /* store it as it's sink element */
1125 __mmplayer_add_sink(player, fakesink);
1127 gst_bin_add(GST_BIN(pipeline), fakesink);
1130 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1132 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1134 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1135 LOGE("failed to link fakesink");
1136 gst_object_unref(GST_OBJECT(fakesink));
1140 if (strstr(name, "video")) {
1141 if (player->v_stream_caps) {
1142 gst_caps_unref(player->v_stream_caps);
1143 player->v_stream_caps = NULL;
1145 if (player->ini.set_dump_element_flag)
1146 __mmplayer_add_dump_buffer_probe(player, fakesink);
1149 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1150 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1154 gst_object_unref(GST_OBJECT(sinkpad));
1161 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1163 GstElement *pipeline = NULL;
1164 GstElement *selector = NULL;
1165 GstPad *srcpad = NULL;
1168 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1170 selector = gst_element_factory_make("input-selector", NULL);
1172 LOGE("failed to create input-selector");
1175 g_object_set(selector, "sync-streams", TRUE, NULL);
1177 player->pipeline->mainbin[elem_idx].id = elem_idx;
1178 player->pipeline->mainbin[elem_idx].gst = selector;
1180 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1182 srcpad = gst_element_get_static_pad(selector, "src");
1184 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1185 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1186 __mmplayer_gst_selector_blocked, NULL, NULL);
1187 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1188 __mmplayer_gst_selector_event_probe, player, NULL);
1190 gst_element_set_state(selector, GST_STATE_PAUSED);
1192 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1193 gst_bin_add(GST_BIN(pipeline), selector);
1195 gst_object_unref(GST_OBJECT(srcpad));
1202 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1204 mmplayer_t *player = (mmplayer_t *)data;
1205 GstElement *selector = NULL;
1206 GstCaps *caps = NULL;
1207 GstStructure *str = NULL;
1208 const gchar *name = NULL;
1209 GstPad *sinkpad = NULL;
1210 gboolean first_track = FALSE;
1212 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1213 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1216 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1217 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1219 LOGD("pad-added signal handling");
1221 /* get mimetype from caps */
1222 caps = gst_pad_get_current_caps(pad);
1224 str = gst_caps_get_structure(caps, 0);
1226 name = gst_structure_get_name(str);
1231 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1233 LOGD("detected mimetype : %s", name);
1236 if (strstr(name, "video")) {
1238 gchar *caps_str = NULL;
1240 caps_str = gst_caps_to_string(caps);
1241 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1242 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1243 player->set_mode.video_zc = true;
1245 MMPLAYER_FREEIF(caps_str);
1247 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1248 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1250 LOGD("surface type : %d", stype);
1252 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1253 __mmplayer_gst_create_sinkbin(elem, pad, player);
1257 /* in case of exporting video frame, it requires the 360 video filter.
1258 * it will be handled in _no_more_pads(). */
1259 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1260 __mmplayer_gst_make_fakesink(player, pad, name);
1264 LOGD("video selector is required");
1265 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1266 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1267 } else if (strstr(name, "audio")) {
1268 gint samplerate = 0;
1271 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1272 if (player->build_audio_offload)
1273 player->no_more_pad = TRUE; /* remove state holder */
1274 __mmplayer_gst_create_sinkbin(elem, pad, player);
1278 gst_structure_get_int(str, "rate", &samplerate);
1279 gst_structure_get_int(str, "channels", &channels);
1281 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1282 __mmplayer_gst_make_fakesink(player, pad, name);
1286 LOGD("audio selector is required");
1287 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1288 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1290 } else if (strstr(name, "text")) {
1291 LOGD("text selector is required");
1292 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1293 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1295 LOGE("invalid caps info");
1299 /* check selector and create it */
1300 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1301 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1306 LOGD("input-selector is already created.");
1310 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1312 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1314 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1315 LOGE("failed to link selector");
1316 gst_object_unref(GST_OBJECT(selector));
1321 LOGD("this track will be activated");
1322 g_object_set(selector, "active-pad", sinkpad, NULL);
1325 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1331 gst_caps_unref(caps);
1334 gst_object_unref(GST_OBJECT(sinkpad));
1342 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1344 GstPad *srcpad = NULL;
1347 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1349 LOGD("type %d", type);
1352 LOGD("there is no %d track", type);
1356 srcpad = gst_element_get_static_pad(selector, "src");
1358 LOGE("failed to get srcpad from selector");
1362 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1364 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1366 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1367 if (player->selector[type].block_id) {
1368 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1369 player->selector[type].block_id = 0;
1373 gst_object_unref(GST_OBJECT(srcpad));
1382 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1384 gint active_index = 0;
1387 MMPLAYER_RETURN_IF_FAIL(player);
1389 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1391 /* change track to active pad */
1392 active_index = player->selector[type].active_pad_index;
1393 if ((active_index != DEFAULT_TRACK) &&
1394 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1395 LOGW("failed to change %d type track to %d", type, active_index);
1396 player->selector[type].active_pad_index = DEFAULT_TRACK;
1400 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1401 mm_player_set_attribute((MMHandleType)player, NULL,
1402 "content_text_track_num", player->selector[type].total_track_num,
1403 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1410 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1413 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1415 if (!audio_selector) {
1416 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1418 /* in case the source is changed, output can be changed. */
1419 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1420 LOGD("remove previous audiobin if it exist");
1422 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1423 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1425 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1426 MMPLAYER_FREEIF(player->pipeline->audiobin);
1429 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1430 __mmplayer_pipeline_complete(NULL, player);
1435 /* apply the audio track information */
1436 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1438 /* create audio sink path */
1439 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1440 LOGE("failed to create audio sink path");
1449 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1452 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1454 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1455 LOGD("text path is not supproted");
1459 /* apply the text track information */
1460 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1462 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1463 player->has_closed_caption = TRUE;
1465 /* create text decode path */
1466 player->no_more_pad = TRUE;
1468 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1469 LOGE("failed to create text sink path");
1478 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1480 gint64 dur_bytes = 0L;
1483 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1484 player->pipeline->mainbin && player->streamer, FALSE);
1486 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1487 LOGE("fail to get duration.");
1489 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1490 * use file information was already set on Q2 when it was created. */
1491 _mm_player_streaming_set_queue2(player->streamer,
1492 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1493 TRUE, /* use_buffering */
1494 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1495 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1502 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1504 mmplayer_t *player = NULL;
1505 GstElement *video_selector = NULL;
1506 GstElement *audio_selector = NULL;
1507 GstElement *text_selector = NULL;
1510 player = (mmplayer_t *)data;
1512 LOGD("no-more-pad signal handling");
1514 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1515 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1516 LOGW("player is shutting down");
1520 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1521 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1522 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1523 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1524 LOGE("failed to set queue2 buffering");
1529 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1530 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1531 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1533 if (!video_selector && !audio_selector && !text_selector) {
1534 LOGW("there is no selector");
1535 player->no_more_pad = TRUE;
1539 /* create video path followed by video-select */
1540 if (video_selector && !audio_selector && !text_selector)
1541 player->no_more_pad = TRUE;
1543 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1546 /* create audio path followed by audio-select */
1547 if (audio_selector && !text_selector)
1548 player->no_more_pad = TRUE;
1550 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1553 /* create text path followed by text-select */
1554 __mmplayer_create_text_sink_path(player, text_selector);
1557 _mmplayer_set_reconfigure_state(player, FALSE);
1562 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1564 gboolean ret = FALSE;
1565 GstElement *pipeline = NULL;
1566 GstPad *sinkpad = NULL;
1569 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1570 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1572 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1574 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1576 LOGE("failed to get pad from sinkbin");
1582 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1583 LOGE("failed to link sinkbin for reusing");
1584 goto EXIT; /* exit either pass or fail */
1588 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1589 LOGE("failed to set state(READY) to sinkbin");
1594 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1595 LOGE("failed to add sinkbin to pipeline");
1600 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1601 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1606 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1607 LOGE("failed to set state(PAUSED) to sinkbin");
1616 gst_object_unref(GST_OBJECT(sinkpad));
1624 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1626 mmplayer_t *player = NULL;
1627 GstCaps *caps = NULL;
1628 gchar *caps_str = NULL;
1629 GstStructure *str = NULL;
1630 const gchar *name = NULL;
1631 GstElement *sinkbin = NULL;
1632 gboolean reusing = FALSE;
1633 gboolean caps_ret = TRUE;
1634 gchar *sink_pad_name = "sink";
1637 player = (mmplayer_t *)data;
1640 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1641 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1643 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1647 caps_str = gst_caps_to_string(caps);
1649 LOGD("detected mimetype : %s", name);
1651 if (strstr(name, "audio")) {
1652 if (player->pipeline->audiobin == NULL) {
1653 const gchar *audio_format = gst_structure_get_string(str, "format");
1655 LOGD("original audio format %s", audio_format);
1656 mm_player_set_attribute((MMHandleType)player, NULL,
1657 "content_audio_format", audio_format, strlen(audio_format), NULL);
1660 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1661 LOGE("failed to create audiobin. continuing without audio");
1665 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1666 LOGD("creating audiobin success");
1669 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1670 LOGD("reusing audiobin");
1671 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1673 } else if (strstr(name, "video")) {
1674 /* 1. zero copy is updated at _decode_pad_added()
1675 * 2. NULL surface type is handled in _decode_pad_added() */
1676 LOGD("zero copy %d", player->set_mode.video_zc);
1677 if (player->pipeline->videobin == NULL) {
1678 int surface_type = 0;
1679 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1680 LOGD("display_surface_type (%d)", surface_type);
1682 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1683 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1684 LOGE("failed to acquire video overlay resource");
1688 player->interrupted_by_resource = FALSE;
1690 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1691 LOGE("failed to create videobin. continuing without video");
1695 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1696 LOGD("creating videosink bin success");
1699 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1700 LOGD("re-using videobin");
1701 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1703 } else if (strstr(name, "text")) {
1704 if (player->pipeline->textbin == NULL) {
1705 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1706 LOGE("failed to create text sink bin. continuing without text");
1710 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1711 player->textsink_linked = 1;
1712 LOGD("creating textsink bin success");
1714 if (!player->textsink_linked) {
1715 LOGD("re-using textbin");
1717 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1718 player->textsink_linked = 1;
1720 /* linked textbin exist which means that the external subtitle path exist already */
1721 LOGW("ignoring internal subtutle since external subtitle is available");
1724 sink_pad_name = "text_sink";
1726 LOGW("unknown mime type %s, ignoring it", name);
1730 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1733 LOGD("[handle: %p] success to create and link sink bin", player);
1735 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1736 * streaming task. if the task blocked, then buffer will not flow to the next element
1737 *(autoplugging element). so this is special hack for streaming. please try to remove it
1739 /* dec stream count. we can remove fakesink if it's zero */
1740 if (player->num_dynamic_pad)
1741 player->num_dynamic_pad--;
1743 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1745 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1746 __mmplayer_pipeline_complete(NULL, player);
1750 MMPLAYER_FREEIF(caps_str);
1753 gst_caps_unref(caps);
1759 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1761 int required_angle = 0; /* Angle required for straight view */
1762 int rotation_angle = 0;
1764 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1765 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1767 /* Counter clockwise */
1768 switch (orientation) {
1773 required_angle = 270;
1776 required_angle = 180;
1779 required_angle = 90;
1783 rotation_angle = display_angle + required_angle;
1784 if (rotation_angle >= 360)
1785 rotation_angle -= 360;
1787 /* chech if supported or not */
1788 if (rotation_angle % 90) {
1789 LOGD("not supported rotation angle = %d", rotation_angle);
1793 switch (rotation_angle) {
1795 *value = MM_DISPLAY_ROTATION_NONE;
1798 *value = MM_DISPLAY_ROTATION_90;
1801 *value = MM_DISPLAY_ROTATION_180;
1804 *value = MM_DISPLAY_ROTATION_270;
1808 LOGD("setting rotation property value : %d", *value);
1814 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1816 int display_rotation = 0;
1817 gchar *org_orient = NULL;
1818 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1821 LOGE("cannot get content attribute");
1822 return MM_ERROR_PLAYER_INTERNAL;
1825 if (display_angle) {
1826 /* update user roation */
1827 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1829 /* Counter clockwise */
1830 switch (display_rotation) {
1831 case MM_DISPLAY_ROTATION_NONE:
1834 case MM_DISPLAY_ROTATION_90:
1835 *display_angle = 90;
1837 case MM_DISPLAY_ROTATION_180:
1838 *display_angle = 180;
1840 case MM_DISPLAY_ROTATION_270:
1841 *display_angle = 270;
1844 LOGW("wrong angle type : %d", display_rotation);
1847 LOGD("check user angle: %d", *display_angle);
1851 /* Counter clockwise */
1852 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1855 if (!strcmp(org_orient, "rotate-90"))
1857 else if (!strcmp(org_orient, "rotate-180"))
1859 else if (!strcmp(org_orient, "rotate-270"))
1862 LOGD("original rotation is %s", org_orient);
1864 LOGD("content_video_orientation get fail");
1867 LOGD("check orientation: %d", *orientation);
1870 return MM_ERROR_NONE;
1873 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1875 int rotation_value = 0;
1876 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1877 int display_angle = 0;
1880 /* check video sinkbin is created */
1881 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1884 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1886 /* get rotation value to set */
1887 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1888 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1889 LOGD("set video param : rotate %d", rotation_value);
1892 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1894 MMHandleType attrs = 0;
1898 /* check video sinkbin is created */
1899 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1902 attrs = MMPLAYER_GET_ATTRS(player);
1903 MMPLAYER_RETURN_IF_FAIL(attrs);
1905 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1906 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1907 LOGD("set video param : visible %d", visible);
1910 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1912 MMHandleType attrs = 0;
1913 int display_method = 0;
1916 /* check video sinkbin is created */
1917 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1920 attrs = MMPLAYER_GET_ATTRS(player);
1921 MMPLAYER_RETURN_IF_FAIL(attrs);
1923 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1924 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1925 LOGD("set video param : method %d", display_method);
1928 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1930 MMHandleType attrs = 0;
1934 /* check video sinkbin is created */
1935 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1938 attrs = MMPLAYER_GET_ATTRS(player);
1939 MMPLAYER_RETURN_IF_FAIL(attrs);
1941 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1942 MMPLAYER_RETURN_IF_FAIL(handle);
1944 gst_video_overlay_set_video_roi_area(
1945 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1946 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1947 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1948 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1951 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1953 MMHandleType attrs = 0;
1958 int win_roi_width = 0;
1959 int win_roi_height = 0;
1962 /* check video sinkbin is created */
1963 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1966 attrs = MMPLAYER_GET_ATTRS(player);
1967 MMPLAYER_RETURN_IF_FAIL(attrs);
1969 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1970 MMPLAYER_RETURN_IF_FAIL(handle);
1972 /* It should be set after setting window */
1973 mm_attrs_multiple_get(attrs, NULL,
1974 "display_win_roi_x", &win_roi_x,
1975 "display_win_roi_y", &win_roi_y,
1976 "display_win_roi_width", &win_roi_width,
1977 "display_win_roi_height", &win_roi_height, NULL);
1979 /* After setting window handle, set display roi area */
1980 gst_video_overlay_set_display_roi_area(
1981 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1982 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1983 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1984 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1987 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1989 MMHandleType attrs = 0;
1992 /* check video sinkbin is created */
1993 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1996 attrs = MMPLAYER_GET_ATTRS(player);
1997 MMPLAYER_RETURN_IF_FAIL(attrs);
1999 /* common case if using overlay surface */
2000 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2001 MMPLAYER_RETURN_IF_FAIL(handle);
2003 /* default is using wl_surface_id */
2004 LOGD("set video param : wl_surface_id %d", handle);
2005 gst_video_overlay_set_wl_window_wl_surface_id(
2006 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2011 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2013 gboolean update_all_param = FALSE;
2017 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2018 LOGW("videosink is not ready yet");
2019 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2022 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2023 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2024 return MM_ERROR_PLAYER_INTERNAL;
2027 LOGD("param_name : %s", param_name);
2028 if (!g_strcmp0(param_name, "update_all_param"))
2029 update_all_param = TRUE;
2031 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2032 __mmplayer_video_param_set_display_overlay(player);
2033 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2034 __mmplayer_video_param_set_display_method(player);
2035 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2036 __mmplayer_video_param_set_display_visible(player);
2037 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2038 __mmplayer_video_param_set_display_rotation(player);
2039 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2040 __mmplayer_video_param_set_roi_area(player);
2041 if (update_all_param)
2042 __mmplayer_video_param_set_video_roi_area(player);
2046 return MM_ERROR_NONE;
2050 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2052 gboolean disable_overlay = FALSE;
2053 mmplayer_t *player = (mmplayer_t *)hplayer;
2056 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2057 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2058 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2059 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2061 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2062 LOGW("Display control is not supported");
2063 return MM_ERROR_PLAYER_INTERNAL;
2066 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2068 if (audio_only == (bool)disable_overlay) {
2069 LOGE("It's the same with current setting: (%d)", audio_only);
2070 return MM_ERROR_NONE;
2074 LOGE("disable overlay");
2075 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2077 /* release overlay resource */
2078 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2079 LOGE("failed to release overlay resource");
2083 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2084 LOGE("failed to acquire video overlay resource");
2087 player->interrupted_by_resource = FALSE;
2089 LOGD("enable overlay");
2090 __mmplayer_video_param_set_display_overlay(player);
2091 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2096 return MM_ERROR_NONE;
2100 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2102 mmplayer_t *player = (mmplayer_t *)hplayer;
2103 gboolean disable_overlay = FALSE;
2107 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2108 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2109 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2110 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2111 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2113 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2114 LOGW("Display control is not supported");
2115 return MM_ERROR_PLAYER_INTERNAL;
2118 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2120 *paudio_only = (bool)disable_overlay;
2122 LOGD("audio_only : %d", *paudio_only);
2126 return MM_ERROR_NONE;
2130 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2132 GList *bucket = element_bucket;
2133 mmplayer_gst_element_t *element = NULL;
2134 mmplayer_gst_element_t *prv_element = NULL;
2135 GstElement *tee_element = NULL;
2136 gint successful_link_count = 0;
2140 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2142 prv_element = (mmplayer_gst_element_t *)bucket->data;
2143 bucket = bucket->next;
2145 for (; bucket; bucket = bucket->next) {
2146 element = (mmplayer_gst_element_t *)bucket->data;
2148 if (element && element->gst) {
2149 if (prv_element && prv_element->gst) {
2150 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2152 prv_element->gst = tee_element;
2154 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2155 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2156 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2160 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2161 LOGD("linking [%s] to [%s] success",
2162 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2163 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2164 successful_link_count++;
2165 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2166 LOGD("keep audio-tee element for next audio pipeline branch");
2167 tee_element = prv_element->gst;
2170 LOGD("linking [%s] to [%s] failed",
2171 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2172 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2178 prv_element = element;
2183 return successful_link_count;
2187 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2189 GList *bucket = element_bucket;
2190 mmplayer_gst_element_t *element = NULL;
2191 int successful_add_count = 0;
2195 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2196 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2198 for (; bucket; bucket = bucket->next) {
2199 element = (mmplayer_gst_element_t *)bucket->data;
2201 if (element && element->gst) {
2202 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2203 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2204 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2205 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2208 successful_add_count++;
2214 return successful_add_count;
2218 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2220 mmplayer_t *player = (mmplayer_t *)data;
2221 GstCaps *caps = NULL;
2222 GstStructure *str = NULL;
2224 gboolean caps_ret = TRUE;
2228 MMPLAYER_RETURN_IF_FAIL(pad);
2229 MMPLAYER_RETURN_IF_FAIL(unused);
2230 MMPLAYER_RETURN_IF_FAIL(data);
2232 caps = gst_pad_get_current_caps(pad);
2236 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2240 LOGD("name = %s", name);
2242 if (strstr(name, "audio")) {
2243 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2245 if (player->audio_stream_changed_cb) {
2246 LOGE("call the audio stream changed cb");
2247 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2249 } else if (strstr(name, "video")) {
2250 if ((name = gst_structure_get_string(str, "format")))
2251 player->set_mode.video_zc = name[0] == 'S';
2253 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2254 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2256 LOGW("invalid caps info");
2261 gst_caps_unref(caps);
2269 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2274 MMPLAYER_RETURN_IF_FAIL(player);
2276 if (player->audio_stream_buff_list) {
2277 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2278 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2281 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2282 __mmplayer_audio_stream_send_data(player, tmp);
2284 MMPLAYER_FREEIF(tmp->pcm_data);
2285 MMPLAYER_FREEIF(tmp);
2288 g_list_free(player->audio_stream_buff_list);
2289 player->audio_stream_buff_list = NULL;
2296 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2298 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2301 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2303 audio_stream.bitrate = a_buffer->bitrate;
2304 audio_stream.channel = a_buffer->channel;
2305 audio_stream.channel_mask = a_buffer->channel_mask;
2306 audio_stream.data_size = a_buffer->data_size;
2307 audio_stream.data = a_buffer->pcm_data;
2308 audio_stream.pcm_format = a_buffer->pcm_format;
2310 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2312 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2318 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2320 mmplayer_t *player = (mmplayer_t *)data;
2321 const gchar *pcm_format = NULL;
2324 guint64 channel_mask = 0;
2325 void *a_data = NULL;
2327 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2328 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2332 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2334 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2335 a_data = mapinfo.data;
2336 a_size = mapinfo.size;
2338 GstCaps *caps = gst_pad_get_current_caps(pad);
2339 GstStructure *structure = gst_caps_get_structure(caps, 0);
2341 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2343 pcm_format = gst_structure_get_string(structure, "format");
2344 gst_structure_get_int(structure, "rate", &rate);
2345 gst_structure_get_int(structure, "channels", &channel);
2346 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2347 gst_caps_unref(GST_CAPS(caps));
2349 /* In case of the sync is false, use buffer list. *
2350 * The num of buffer list depends on the num of audio channels */
2351 if (player->audio_stream_buff_list) {
2352 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2353 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2355 if (channel_mask == tmp->channel_mask) {
2357 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2359 if (tmp->data_size + a_size < tmp->buff_size) {
2360 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2361 tmp->data_size += a_size;
2363 /* send data to client */
2364 __mmplayer_audio_stream_send_data(player, tmp);
2366 if (a_size > tmp->buff_size) {
2367 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2368 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2369 if (tmp->pcm_data == NULL) {
2370 LOGE("failed to realloc data.");
2373 tmp->buff_size = a_size;
2375 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2376 memcpy(tmp->pcm_data, a_data, a_size);
2377 tmp->data_size = a_size;
2382 LOGE("data is empty in list.");
2388 /* create new audio stream data for newly found audio channel */
2389 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2390 if (a_buffer == NULL) {
2391 LOGE("failed to alloc data.");
2394 a_buffer->bitrate = rate;
2395 a_buffer->channel = channel;
2396 a_buffer->channel_mask = channel_mask;
2397 a_buffer->data_size = a_size;
2398 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2400 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2401 /* If sync is FALSE, use buffer list to reduce the IPC. */
2402 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2403 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2404 if (a_buffer->pcm_data == NULL) {
2405 LOGE("failed to alloc data.");
2406 MMPLAYER_FREEIF(a_buffer);
2409 memcpy(a_buffer->pcm_data, a_data, a_size);
2411 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2413 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2415 /* If sync is TRUE, send data directly. */
2416 a_buffer->pcm_data = a_data;
2417 __mmplayer_audio_stream_send_data(player, a_buffer);
2418 MMPLAYER_FREEIF(a_buffer);
2422 gst_buffer_unmap(buffer, &mapinfo);
2427 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2429 mmplayer_t *player = (mmplayer_t *)data;
2430 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2431 GstPad *sinkpad = NULL;
2432 GstElement *queue = NULL, *sink = NULL;
2435 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2437 queue = gst_element_factory_make("queue", NULL);
2438 if (queue == NULL) {
2439 LOGD("fail make queue");
2443 sink = gst_element_factory_make("fakesink", NULL);
2445 LOGD("fail make fakesink");
2449 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2451 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2452 LOGW("failed to link queue & sink");
2456 sinkpad = gst_element_get_static_pad(queue, "sink");
2458 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2459 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2463 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2465 gst_object_unref(sinkpad);
2466 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2467 g_object_set(sink, "sync", TRUE, NULL);
2468 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2470 /* keep the first sink reference only */
2471 if (!audiobin[MMPLAYER_A_SINK].gst) {
2472 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2473 audiobin[MMPLAYER_A_SINK].gst = sink;
2477 _mmplayer_add_signal_connection(player,
2479 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2481 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2484 __mmplayer_add_sink(player, sink);
2486 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2487 LOGE("failed to sync state");
2491 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2492 LOGE("failed to sync state");
2500 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2502 gst_object_unref(GST_OBJECT(queue));
2506 gst_object_unref(GST_OBJECT(sink));
2510 gst_object_unref(GST_OBJECT(sinkpad));
2518 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2520 mmplayer_t *player = (mmplayer_t *)data;
2523 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2525 player->no_more_pad = TRUE;
2526 __mmplayer_pipeline_complete(NULL, player);
2533 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2535 #define MAX_PROPS_LEN 128
2536 mmplayer_gst_element_t *audiobin = NULL;
2537 gint latency_mode = 0;
2538 gchar *stream_type = NULL;
2539 gchar *latency = NULL;
2541 gchar stream_props[MAX_PROPS_LEN] = {0,};
2542 GstStructure *props = NULL;
2545 * It should be set after player creation through attribute.
2546 * But, it can not be changed during playing.
2549 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2551 audiobin = player->pipeline->audiobin;
2553 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2554 if (player->sound.mute) {
2555 LOGD("mute enabled");
2556 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2559 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2560 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2563 snprintf(stream_props, sizeof(stream_props) - 1,
2564 "props,application.process.id.origin=%d", player->client_pid);
2566 snprintf(stream_props, sizeof(stream_props) - 1,
2567 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2568 stream_type, stream_id, player->client_pid);
2570 props = gst_structure_from_string(stream_props, NULL);
2571 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2572 LOGI("props result[%s].", stream_props);
2573 gst_structure_free(props);
2575 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2577 switch (latency_mode) {
2578 case AUDIO_LATENCY_MODE_LOW:
2579 latency = g_strdup("low");
2581 case AUDIO_LATENCY_MODE_MID:
2582 latency = g_strdup("mid");
2584 case AUDIO_LATENCY_MODE_HIGH:
2585 latency = g_strdup("high");
2588 latency = g_strdup("mid");
2592 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2594 LOGD("audiosink property - latency=%s", latency);
2596 MMPLAYER_FREEIF(latency);
2602 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2604 mmplayer_gst_element_t *audiobin = NULL;
2607 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2608 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2610 audiobin = player->pipeline->audiobin;
2612 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2613 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2614 LOGE("failed to create media stream info");
2615 return MM_ERROR_PLAYER_INTERNAL;
2618 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2620 if (player->video360_yaw_radians <= M_PI &&
2621 player->video360_yaw_radians >= -M_PI &&
2622 player->video360_pitch_radians <= M_PI_2 &&
2623 player->video360_pitch_radians >= -M_PI_2) {
2624 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2625 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2626 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2627 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2628 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2629 "source-orientation-y", player->video360_metadata.init_view_heading,
2630 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2634 return MM_ERROR_NONE;
2638 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2640 mmplayer_gst_element_t *audiobin = NULL;
2641 GstPad *sink_pad = NULL;
2642 GstCaps *acaps = NULL;
2644 int pitch_control = 0;
2645 double pitch_value = 1.0;
2648 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2649 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2651 audiobin = player->pipeline->audiobin;
2653 LOGD("make element for normal audio playback");
2655 /* audio bin structure for playback. {} means optional.
2656 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2658 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2659 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2662 /* for pitch control */
2663 mm_attrs_multiple_get(player->attrs, NULL,
2664 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2665 MM_PLAYER_PITCH_VALUE, &pitch_value,
2668 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2669 if (pitch_control && (player->videodec_linked == 0)) {
2670 GstElementFactory *factory;
2672 factory = gst_element_factory_find("pitch");
2674 gst_object_unref(factory);
2677 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2680 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2681 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2683 LOGW("there is no pitch element");
2688 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2690 /* replaygain volume */
2691 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2692 if (player->sound.rg_enable)
2693 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2698 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2700 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2701 /* currently, only openalsink uses volume element */
2702 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2703 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2705 if (player->sound.mute) {
2706 LOGD("mute enabled");
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2711 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2713 /* audio effect element. if audio effect is enabled */
2714 if ((strcmp(player->ini.audioeffect_element, ""))
2716 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2719 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2721 if ((!player->bypass_audio_effect)
2722 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2723 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2724 if (!_mmplayer_audio_effect_custom_apply(player))
2725 LOGI("apply audio effect(custom) setting success");
2729 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2730 && (player->set_mode.rich_audio)) {
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2735 /* create audio sink */
2736 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2737 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2738 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2740 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2741 if (player->is_360_feature_enabled &&
2742 player->is_content_spherical &&
2744 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2745 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2746 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2748 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2750 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2752 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2753 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2754 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2755 gst_caps_unref(acaps);
2757 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2759 player->is_openal_plugin_used = TRUE;
2761 if (player->is_360_feature_enabled && player->is_content_spherical)
2762 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2763 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2766 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2767 (player->videodec_linked && player->ini.use_system_clock)) {
2768 LOGD("system clock will be used.");
2769 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2772 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2773 __mmplayer_gst_set_pulsesink_property(player);
2774 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2775 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2780 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2781 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2783 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2784 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2785 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2786 gst_object_unref(GST_OBJECT(sink_pad));
2788 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2791 return MM_ERROR_NONE;
2793 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2795 return MM_ERROR_PLAYER_INTERNAL;
2799 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2801 mmplayer_gst_element_t *audiobin = NULL;
2802 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2804 gchar *dst_format = NULL;
2806 int dst_samplerate = 0;
2807 int dst_channels = 0;
2808 GstCaps *caps = NULL;
2809 char *caps_str = NULL;
2812 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2813 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2815 audiobin = player->pipeline->audiobin;
2817 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2819 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2821 [case 1] extract interleave audio pcm without playback
2822 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2823 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2825 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2827 [case 2] deinterleave for each channel without playback
2828 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2829 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2831 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2832 - fakesink (sync or not)
2835 [case 3] [case 1(sync only)] + playback
2836 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2838 * src - ... - tee - queue1 - playback path
2839 - queue2 - [case1 pipeline with sync]
2841 [case 4] [case 2(sync only)] + playback
2842 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2844 * src - ... - tee - queue1 - playback path
2845 - queue2 - [case2 pipeline with sync]
2849 /* 1. create tee and playback path
2850 'tee' should be added at first to copy the decoded stream
2852 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2853 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2854 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2856 /* tee - path 1 : for playback path */
2857 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2858 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2860 /* tee - path 2 : for extract path */
2861 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2862 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2865 /* if there is tee, 'tee - path 2' is linked here */
2867 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2870 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2872 /* 2. decide the extract pcm format */
2873 mm_attrs_multiple_get(player->attrs, NULL,
2874 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2875 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2876 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2879 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2880 dst_format, dst_len, dst_samplerate, dst_channels);
2882 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2883 mm_attrs_multiple_get(player->attrs, NULL,
2884 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2885 "content_audio_samplerate", &dst_samplerate,
2886 "content_audio_channels", &dst_channels,
2889 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2890 dst_format, dst_len, dst_samplerate, dst_channels);
2892 /* If there is no enough information, set it to platform default value. */
2893 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2894 LOGD("set platform default format");
2895 dst_format = DEFAULT_PCM_OUT_FORMAT;
2897 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2898 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2901 /* 3. create capsfilter */
2902 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2903 caps = gst_caps_new_simple("audio/x-raw",
2904 "format", G_TYPE_STRING, dst_format,
2905 "rate", G_TYPE_INT, dst_samplerate,
2906 "channels", G_TYPE_INT, dst_channels,
2909 caps_str = gst_caps_to_string(caps);
2910 LOGD("new caps : %s", caps_str);
2912 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2915 gst_caps_unref(caps);
2916 MMPLAYER_FREEIF(caps_str);
2918 /* 4-1. create deinterleave to extract pcm for each channel */
2919 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2920 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2921 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2923 /* audiosink will be added after getting signal for each channel */
2924 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2925 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2926 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2927 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2928 player->no_more_pad = FALSE;
2930 /* 4-2. create fakesink to extract interlevaed pcm */
2931 LOGD("add audio fakesink for interleaved audio");
2932 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2933 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2934 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2935 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2937 _mmplayer_add_signal_connection(player,
2938 G_OBJECT(audiobin[extract_sink_id].gst),
2939 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2941 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2944 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2948 return MM_ERROR_NONE;
2950 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2952 return MM_ERROR_PLAYER_INTERNAL;
2956 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2958 int ret = MM_ERROR_NONE;
2959 mmplayer_gst_element_t *audiobin = NULL;
2960 GList *element_bucket = NULL;
2963 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2964 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2966 audiobin = player->pipeline->audiobin;
2968 if (player->build_audio_offload) { /* skip all the audio filters */
2969 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2971 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2972 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2973 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2975 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2979 /* FIXME: need to mention the supportable condition at API reference */
2980 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2981 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2983 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2985 if (ret != MM_ERROR_NONE)
2988 LOGD("success to make audio bin element");
2989 *bucket = element_bucket;
2992 return MM_ERROR_NONE;
2995 LOGE("failed to make audio bin element");
2996 g_list_free(element_bucket);
3000 return MM_ERROR_PLAYER_INTERNAL;
3004 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3006 mmplayer_gst_element_t *first_element = NULL;
3007 mmplayer_gst_element_t *audiobin = NULL;
3009 GstPad *ghostpad = NULL;
3010 GList *element_bucket = NULL;
3014 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3017 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3019 LOGE("failed to allocate memory for audiobin");
3020 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3024 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3025 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3026 if (!audiobin[MMPLAYER_A_BIN].gst) {
3027 LOGE("failed to create audiobin");
3032 player->pipeline->audiobin = audiobin;
3034 /* create audio filters and audiosink */
3035 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3038 /* adding created elements to bin */
3039 LOGD("adding created elements to bin");
3040 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3043 /* linking elements in the bucket by added order. */
3044 LOGD("Linking elements in the bucket by added order.");
3045 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3048 /* get first element's sinkpad for creating ghostpad */
3049 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3050 if (!first_element) {
3051 LOGE("failed to get first elem");
3055 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3057 LOGE("failed to get pad from first element of audiobin");
3061 ghostpad = gst_ghost_pad_new("sink", pad);
3063 LOGE("failed to create ghostpad");
3067 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3068 LOGE("failed to add ghostpad to audiobin");
3072 gst_object_unref(pad);
3074 g_list_free(element_bucket);
3077 return MM_ERROR_NONE;
3080 LOGD("ERROR : releasing audiobin");
3083 gst_object_unref(GST_OBJECT(pad));
3086 gst_object_unref(GST_OBJECT(ghostpad));
3089 g_list_free(element_bucket);
3091 /* release element which are not added to bin */
3092 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3093 /* NOTE : skip bin */
3094 if (audiobin[i].gst) {
3095 GstObject *parent = NULL;
3096 parent = gst_element_get_parent(audiobin[i].gst);
3099 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3100 audiobin[i].gst = NULL;
3102 gst_object_unref(GST_OBJECT(parent));
3106 /* release audiobin with it's childs */
3107 if (audiobin[MMPLAYER_A_BIN].gst)
3108 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3110 MMPLAYER_FREEIF(audiobin);
3112 player->pipeline->audiobin = NULL;
3114 return MM_ERROR_PLAYER_INTERNAL;
3118 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3120 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3124 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3126 int ret = MM_ERROR_NONE;
3128 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3129 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3131 MMPLAYER_VIDEO_BO_LOCK(player);
3133 if (player->video_bo_list) {
3134 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3135 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3136 if (tmp && tmp->bo == bo) {
3138 LOGD("release bo %p", bo);
3139 tbm_bo_unref(tmp->bo);
3140 MMPLAYER_VIDEO_BO_UNLOCK(player);
3141 MMPLAYER_VIDEO_BO_SIGNAL(player);
3146 /* hw codec is running or the list was reset for DRC. */
3147 LOGW("there is no bo list.");
3149 MMPLAYER_VIDEO_BO_UNLOCK(player);
3151 LOGW("failed to find bo %p", bo);
3156 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3161 MMPLAYER_RETURN_IF_FAIL(player);
3163 MMPLAYER_VIDEO_BO_LOCK(player);
3164 if (player->video_bo_list) {
3165 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3166 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3167 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3170 tbm_bo_unref(tmp->bo);
3174 g_list_free(player->video_bo_list);
3175 player->video_bo_list = NULL;
3177 player->video_bo_size = 0;
3178 MMPLAYER_VIDEO_BO_UNLOCK(player);
3185 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3188 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3189 gboolean ret = TRUE;
3191 /* check DRC, if it is, destroy the prev bo list to create again */
3192 if (player->video_bo_size != size) {
3193 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3194 __mmplayer_video_stream_destroy_bo_list(player);
3195 player->video_bo_size = size;
3198 MMPLAYER_VIDEO_BO_LOCK(player);
3200 if ((!player->video_bo_list) ||
3201 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3203 /* create bo list */
3205 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3207 if (player->video_bo_list) {
3208 /* if bo list did not created all, try it again. */
3209 idx = g_list_length(player->video_bo_list);
3210 LOGD("bo list exist(len: %d)", idx);
3213 for (; idx < player->ini.num_of_video_bo; idx++) {
3214 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3216 LOGE("Fail to alloc bo_info.");
3219 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3221 LOGE("Fail to tbm_bo_alloc.");
3222 MMPLAYER_FREEIF(bo_info);
3225 bo_info->used = FALSE;
3226 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3229 /* update video num buffers */
3230 LOGD("video_num_buffers : %d", idx);
3231 mm_player_set_attribute((MMHandleType)player, NULL,
3232 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3233 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3237 MMPLAYER_VIDEO_BO_UNLOCK(player);
3243 /* get bo from list*/
3244 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3245 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3246 if (tmp && (tmp->used == FALSE)) {
3247 LOGD("found bo %p to use", tmp->bo);
3249 MMPLAYER_VIDEO_BO_UNLOCK(player);
3250 return tbm_bo_ref(tmp->bo);
3254 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3255 MMPLAYER_VIDEO_BO_UNLOCK(player);
3259 if (player->ini.video_bo_timeout <= 0) {
3260 MMPLAYER_VIDEO_BO_WAIT(player);
3262 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3263 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3270 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3272 mmplayer_t *player = (mmplayer_t *)data;
3274 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3276 /* send prerolled pkt */
3277 player->video_stream_prerolled = false;
3279 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3281 /* not to send prerolled pkt again */
3282 player->video_stream_prerolled = true;
3286 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3288 mmplayer_t *player = (mmplayer_t *)data;
3289 mmplayer_video_decoded_data_info_t *stream = NULL;
3290 GstMemory *mem = NULL;
3293 MMPLAYER_RETURN_IF_FAIL(player);
3294 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3296 if (player->video_stream_prerolled) {
3297 player->video_stream_prerolled = false;
3298 LOGD("skip the prerolled pkt not to send it again");
3302 /* clear stream data structure */
3303 stream = __mmplayer_create_stream_from_pad(pad);
3305 LOGE("failed to alloc stream");
3309 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3311 /* set size and timestamp */
3312 mem = gst_buffer_peek_memory(buffer, 0);
3313 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3314 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3316 /* check zero-copy */
3317 if (player->set_mode.video_zc &&
3318 player->set_mode.video_export &&
3319 gst_is_tizen_memory(mem)) {
3320 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3321 stream->internal_buffer = gst_buffer_ref(buffer);
3322 } else { /* sw codec */
3323 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3326 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3330 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3331 LOGE("failed to send video decoded data.");
3338 LOGE("release video stream resource.");
3339 if (gst_is_tizen_memory(mem)) {
3341 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3343 tbm_bo_unref(stream->bo[i]);
3346 /* unref gst buffer */
3347 if (stream->internal_buffer)
3348 gst_buffer_unref(stream->internal_buffer);
3351 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3353 MMPLAYER_FREEIF(stream);
3358 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3360 mmplayer_gst_element_t *videobin = NULL;
3363 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3365 videobin = player->pipeline->videobin;
3367 /* Set spatial media metadata and/or user settings to the element.
3369 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3370 "projection-type", player->video360_metadata.projection_type, NULL);
3372 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3373 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3375 if (player->video360_metadata.full_pano_width_pixels &&
3376 player->video360_metadata.full_pano_height_pixels &&
3377 player->video360_metadata.cropped_area_image_width &&
3378 player->video360_metadata.cropped_area_image_height) {
3379 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3380 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3381 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3382 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3383 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3384 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3385 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3389 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3390 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3391 "horizontal-fov", player->video360_horizontal_fov,
3392 "vertical-fov", player->video360_vertical_fov, NULL);
3395 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3396 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3397 "zoom", 1.0f / player->video360_zoom, NULL);
3400 if (player->video360_yaw_radians <= M_PI &&
3401 player->video360_yaw_radians >= -M_PI &&
3402 player->video360_pitch_radians <= M_PI_2 &&
3403 player->video360_pitch_radians >= -M_PI_2) {
3404 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3405 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3406 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3407 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3408 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3409 "pose-yaw", player->video360_metadata.init_view_heading,
3410 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3413 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3414 "passthrough", !player->is_video360_enabled, NULL);
3421 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3423 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3424 GList *element_bucket = NULL;
3427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3429 /* create video360 filter */
3430 if (player->is_360_feature_enabled && player->is_content_spherical) {
3431 LOGD("create video360 element");
3432 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3433 __mmplayer_gst_set_video360_property(player);
3437 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3438 LOGD("skip creating the videoconv and rotator");
3439 return MM_ERROR_NONE;
3442 /* in case of sw codec & overlay surface type, except 360 playback.
3443 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3444 LOGD("create video converter: %s", video_csc);
3445 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3448 *bucket = element_bucket;
3450 return MM_ERROR_NONE;
3452 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3453 g_list_free(element_bucket);
3457 return MM_ERROR_PLAYER_INTERNAL;
3461 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3463 gchar *factory_name = NULL;
3465 switch (surface_type) {
3466 case MM_DISPLAY_SURFACE_OVERLAY:
3467 if (strlen(player->ini.videosink_element_overlay) > 0)
3468 factory_name = player->ini.videosink_element_overlay;
3470 case MM_DISPLAY_SURFACE_REMOTE:
3471 case MM_DISPLAY_SURFACE_NULL:
3472 if (strlen(player->ini.videosink_element_fake) > 0)
3473 factory_name = player->ini.videosink_element_fake;
3476 LOGE("unidentified surface type");
3480 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3481 return factory_name;
3485 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3487 gchar *factory_name = NULL;
3488 mmplayer_gst_element_t *videobin = NULL;
3493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3495 videobin = player->pipeline->videobin;
3496 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3498 attrs = MMPLAYER_GET_ATTRS(player);
3500 LOGE("cannot get content attribute");
3501 return MM_ERROR_PLAYER_INTERNAL;
3504 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3505 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3506 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3507 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3508 "use-tbm", use_tbm, NULL);
3511 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3512 return MM_ERROR_PLAYER_INTERNAL;
3514 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3517 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3518 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3521 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3523 LOGD("disable last-sample");
3524 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3527 if (player->set_mode.video_export) {
3529 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3530 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3531 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3533 _mmplayer_add_signal_connection(player,
3534 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3535 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3537 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3540 _mmplayer_add_signal_connection(player,
3541 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3542 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3544 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3548 if (videobin[MMPLAYER_V_SINK].gst) {
3549 GstPad *sink_pad = NULL;
3550 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3552 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3553 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3554 gst_object_unref(GST_OBJECT(sink_pad));
3556 LOGE("failed to get sink pad from videosink");
3560 return MM_ERROR_NONE;
3565 * - video overlay surface(arm/x86) : tizenwlsink
3568 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3571 GList *element_bucket = NULL;
3572 mmplayer_gst_element_t *first_element = NULL;
3573 mmplayer_gst_element_t *videobin = NULL;
3574 gchar *videosink_factory_name = NULL;
3577 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3580 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3582 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3584 player->pipeline->videobin = videobin;
3587 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3588 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3589 if (!videobin[MMPLAYER_V_BIN].gst) {
3590 LOGE("failed to create videobin");
3594 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3597 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3598 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3600 /* additional setting for sink plug-in */
3601 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3602 LOGE("failed to set video property");
3606 /* store it as it's sink element */
3607 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3609 /* adding created elements to bin */
3610 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3611 LOGE("failed to add elements");
3615 /* Linking elements in the bucket by added order */
3616 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3617 LOGE("failed to link elements");
3621 /* get first element's sinkpad for creating ghostpad */
3622 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3623 if (!first_element) {
3624 LOGE("failed to get first element from bucket");
3628 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3630 LOGE("failed to get pad from first element");
3634 /* create ghostpad */
3635 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3636 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3637 LOGE("failed to add ghostpad to videobin");
3640 gst_object_unref(pad);
3642 /* done. free allocated variables */
3643 g_list_free(element_bucket);
3647 return MM_ERROR_NONE;
3650 LOGE("ERROR : releasing videobin");
3651 g_list_free(element_bucket);
3654 gst_object_unref(GST_OBJECT(pad));
3656 /* release videobin with it's childs */
3657 if (videobin[MMPLAYER_V_BIN].gst)
3658 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3660 MMPLAYER_FREEIF(videobin);
3661 player->pipeline->videobin = NULL;
3663 return MM_ERROR_PLAYER_INTERNAL;
3667 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3669 GList *element_bucket = NULL;
3670 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3672 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3673 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3674 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3675 "signal-handoffs", FALSE,
3678 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3679 _mmplayer_add_signal_connection(player,
3680 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3681 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3683 G_CALLBACK(__mmplayer_update_subtitle),
3686 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3687 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3689 if (!player->play_subtitle) {
3690 LOGD("add textbin sink as sink element of whole pipeline.");
3691 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3694 /* adding created elements to bin */
3695 LOGD("adding created elements to bin");
3696 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3697 LOGE("failed to add elements");
3701 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3702 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3703 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3705 /* linking elements in the bucket by added order. */
3706 LOGD("Linking elements in the bucket by added order.");
3707 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3708 LOGE("failed to link elements");
3712 /* done. free allocated variables */
3713 g_list_free(element_bucket);
3715 if (textbin[MMPLAYER_T_QUEUE].gst) {
3717 GstPad *ghostpad = NULL;
3719 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3721 LOGE("failed to get sink pad of text queue");
3725 ghostpad = gst_ghost_pad_new("text_sink", pad);
3726 gst_object_unref(pad);
3729 LOGE("failed to create ghostpad of textbin");
3733 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3734 LOGE("failed to add ghostpad to textbin");
3735 gst_object_unref(ghostpad);
3740 return MM_ERROR_NONE;
3743 g_list_free(element_bucket);
3745 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3746 LOGE("remove textbin sink from sink list");
3747 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3750 /* release element at __mmplayer_gst_create_text_sink_bin */
3751 return MM_ERROR_PLAYER_INTERNAL;
3755 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3757 mmplayer_gst_element_t *textbin = NULL;
3758 GList *element_bucket = NULL;
3759 int surface_type = 0;
3764 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3767 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3769 LOGE("failed to allocate memory for textbin");
3770 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3774 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3775 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3776 if (!textbin[MMPLAYER_T_BIN].gst) {
3777 LOGE("failed to create textbin");
3782 player->pipeline->textbin = textbin;
3785 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3786 LOGD("surface type for subtitle : %d", surface_type);
3787 switch (surface_type) {
3788 case MM_DISPLAY_SURFACE_OVERLAY:
3789 case MM_DISPLAY_SURFACE_NULL:
3790 case MM_DISPLAY_SURFACE_REMOTE:
3791 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3792 LOGE("failed to make plain text elements");
3803 return MM_ERROR_NONE;
3807 LOGD("ERROR : releasing textbin");
3809 g_list_free(element_bucket);
3811 /* release signal */
3812 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3814 /* release element which are not added to bin */
3815 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3816 /* NOTE : skip bin */
3817 if (textbin[i].gst) {
3818 GstObject *parent = NULL;
3819 parent = gst_element_get_parent(textbin[i].gst);
3822 gst_object_unref(GST_OBJECT(textbin[i].gst));
3823 textbin[i].gst = NULL;
3825 gst_object_unref(GST_OBJECT(parent));
3830 /* release textbin with it's childs */
3831 if (textbin[MMPLAYER_T_BIN].gst)
3832 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3834 MMPLAYER_FREEIF(textbin);
3835 player->pipeline->textbin = NULL;
3838 return MM_ERROR_PLAYER_INTERNAL;
3842 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3844 mmplayer_gst_element_t *mainbin = NULL;
3845 mmplayer_gst_element_t *textbin = NULL;
3846 MMHandleType attrs = 0;
3847 GstElement *subsrc = NULL;
3848 GstElement *subparse = NULL;
3849 gchar *subtitle_uri = NULL;
3850 const gchar *charset = NULL;
3856 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3858 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3860 mainbin = player->pipeline->mainbin;
3862 attrs = MMPLAYER_GET_ATTRS(player);
3864 LOGE("cannot get content attribute");
3865 return MM_ERROR_PLAYER_INTERNAL;
3868 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3869 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3870 LOGE("subtitle uri is not proper filepath.");
3871 return MM_ERROR_PLAYER_INVALID_URI;
3874 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3875 LOGE("failed to get storage info of subtitle path");
3876 return MM_ERROR_PLAYER_INVALID_URI;
3879 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3881 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3882 player->subtitle_language_list = NULL;
3883 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3885 /* create the subtitle source */
3886 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3888 LOGE("failed to create filesrc element");
3891 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3893 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3894 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3896 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3897 LOGW("failed to add queue");
3898 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3899 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3900 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3905 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3907 LOGE("failed to create subparse element");
3911 charset = _mmplayer_get_charset(subtitle_uri);
3913 LOGD("detected charset is %s", charset);
3914 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3917 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3918 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3920 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3921 LOGW("failed to add subparse");
3922 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3923 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3924 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3928 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3929 LOGW("failed to link subsrc and subparse");
3933 player->play_subtitle = TRUE;
3934 player->adjust_subtitle_pos = 0;
3936 LOGD("play subtitle using subtitle file");
3938 if (player->pipeline->textbin == NULL) {
3939 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3940 LOGE("failed to create text sink bin. continuing without text");
3944 textbin = player->pipeline->textbin;
3946 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3947 LOGW("failed to add textbin");
3949 /* release signal */
3950 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3952 /* release textbin with it's childs */
3953 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3954 MMPLAYER_FREEIF(player->pipeline->textbin);
3955 player->pipeline->textbin = textbin = NULL;
3959 LOGD("link text input selector and textbin ghost pad");
3961 player->textsink_linked = 1;
3962 player->external_text_idx = 0;
3963 LOGI("textsink is linked");
3965 textbin = player->pipeline->textbin;
3966 LOGD("text bin has been created. reuse it.");
3967 player->external_text_idx = 1;
3970 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3971 LOGW("failed to link subparse and textbin");
3975 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3977 LOGE("failed to get sink pad from textsink to probe data");
3981 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3982 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3984 gst_object_unref(pad);
3987 /* create dot. for debugging */
3988 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3991 return MM_ERROR_NONE;
3994 /* release text pipeline resource */
3995 player->textsink_linked = 0;
3997 /* release signal */
3998 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4000 if (player->pipeline->textbin) {
4001 LOGE("remove textbin");
4003 /* release textbin with it's childs */
4004 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4005 MMPLAYER_FREEIF(player->pipeline->textbin);
4006 player->pipeline->textbin = NULL;
4010 /* release subtitle elem */
4011 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4012 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4014 return MM_ERROR_PLAYER_INTERNAL;
4018 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4020 mmplayer_t *player = (mmplayer_t *)data;
4021 MMMessageParamType msg = {0, };
4022 GstClockTime duration = 0;
4023 gpointer text = NULL;
4024 guint text_size = 0;
4025 gboolean ret = TRUE;
4026 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4030 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4031 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4033 if (player->is_subtitle_force_drop) {
4034 LOGW("subtitle is dropped forcedly.");
4038 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4039 text = mapinfo.data;
4040 text_size = mapinfo.size;
4042 if (player->set_mode.subtitle_off) {
4043 LOGD("subtitle is OFF.");
4047 if (!text || (text_size == 0)) {
4048 LOGD("There is no subtitle to be displayed.");
4052 msg.data = (void *)text;
4054 duration = GST_BUFFER_DURATION(buffer);
4056 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4057 if (player->duration > GST_BUFFER_PTS(buffer))
4058 duration = player->duration - GST_BUFFER_PTS(buffer);
4061 LOGI("subtitle duration is invalid, subtitle duration change "
4062 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4064 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4066 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4068 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4069 gst_buffer_unmap(buffer, &mapinfo);
4076 static GstPadProbeReturn
4077 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4079 mmplayer_t *player = (mmplayer_t *)u_data;
4080 GstClockTime cur_timestamp = 0;
4081 gint64 adjusted_timestamp = 0;
4082 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4084 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4086 if (player->set_mode.subtitle_off) {
4087 LOGD("subtitle is OFF.");
4091 if (player->adjust_subtitle_pos == 0) {
4092 LOGD("nothing to do");
4096 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4097 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4099 if (adjusted_timestamp < 0) {
4100 LOGD("adjusted_timestamp under zero");
4105 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4106 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4107 GST_TIME_ARGS(cur_timestamp),
4108 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4110 return GST_PAD_PROBE_OK;
4114 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4118 /* check player and subtitlebin are created */
4119 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4120 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4122 if (position == 0) {
4123 LOGD("nothing to do");
4125 return MM_ERROR_NONE;
4128 /* check current postion */
4129 player->adjust_subtitle_pos = position;
4131 LOGD("save adjust_subtitle_pos in player");
4135 return MM_ERROR_NONE;
4139 * This function is to create audio or video pipeline for playing.
4141 * @param player [in] handle of player
4143 * @return This function returns zero on success.
4148 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4150 int ret = MM_ERROR_NONE;
4151 mmplayer_gst_element_t *mainbin = NULL;
4152 MMHandleType attrs = 0;
4155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4157 /* get profile attribute */
4158 attrs = MMPLAYER_GET_ATTRS(player);
4160 LOGE("failed to get content attribute");
4164 /* create pipeline handles */
4165 if (player->pipeline) {
4166 LOGE("pipeline should be released before create new one");
4170 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4172 /* create mainbin */
4173 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4174 if (mainbin == NULL)
4177 /* create pipeline */
4178 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4179 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4180 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4181 LOGE("failed to create pipeline");
4186 player->pipeline->mainbin = mainbin;
4188 /* create the source and decoder elements */
4189 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4190 ret = _mmplayer_gst_build_es_pipeline(player);
4192 ret = _mmplayer_gst_build_pipeline(player);
4194 if (ret != MM_ERROR_NONE) {
4195 LOGE("failed to create some elements");
4199 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4200 if (__mmplayer_check_subtitle(player)
4201 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4202 LOGE("failed to create text pipeline");
4205 ret = _mmplayer_gst_add_bus_watch(player);
4206 if (ret != MM_ERROR_NONE) {
4207 LOGE("failed to add bus watch");
4212 return MM_ERROR_NONE;
4215 _mmplayer_bus_watcher_remove(player);
4216 __mmplayer_gst_destroy_pipeline(player);
4217 return MM_ERROR_PLAYER_INTERNAL;
4221 __mmplayer_reset_gapless_state(mmplayer_t *player)
4224 MMPLAYER_RETURN_IF_FAIL(player
4226 && player->pipeline->audiobin
4227 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4229 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4236 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4239 int ret = MM_ERROR_NONE;
4243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4245 /* cleanup stuffs */
4246 MMPLAYER_FREEIF(player->type);
4247 player->no_more_pad = FALSE;
4248 player->num_dynamic_pad = 0;
4249 player->demux_pad_index = 0;
4251 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4252 player->subtitle_language_list = NULL;
4253 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4255 MMPLAYER_RECONFIGURE_LOCK(player);
4256 __mmplayer_reset_gapless_state(player);
4257 MMPLAYER_RECONFIGURE_UNLOCK(player);
4259 if (player->streamer) {
4260 _mm_player_streaming_initialize(player->streamer, FALSE);
4261 _mm_player_streaming_destroy(player->streamer);
4262 player->streamer = NULL;
4265 /* cleanup unlinked mime type */
4266 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4267 MMPLAYER_FREEIF(player->unlinked_video_mime);
4268 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4270 /* cleanup running stuffs */
4271 _mmplayer_cancel_eos_timer(player);
4273 /* cleanup gst stuffs */
4274 if (player->pipeline) {
4275 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4276 GstTagList *tag_list = player->pipeline->tag_list;
4278 /* first we need to disconnect all signal hander */
4279 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4282 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4283 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4284 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4285 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4286 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4287 gst_object_unref(bus);
4289 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4290 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4291 if (ret != MM_ERROR_NONE) {
4292 LOGE("fail to change state to NULL");
4293 return MM_ERROR_PLAYER_INTERNAL;
4296 LOGW("succeeded in changing state to NULL");
4298 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4301 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4302 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4304 /* free avsysaudiosink
4305 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4306 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4308 MMPLAYER_FREEIF(audiobin);
4309 MMPLAYER_FREEIF(videobin);
4310 MMPLAYER_FREEIF(textbin);
4311 MMPLAYER_FREEIF(mainbin);
4315 gst_tag_list_unref(tag_list);
4317 MMPLAYER_FREEIF(player->pipeline);
4319 MMPLAYER_FREEIF(player->album_art);
4321 if (player->v_stream_caps) {
4322 gst_caps_unref(player->v_stream_caps);
4323 player->v_stream_caps = NULL;
4326 if (player->a_stream_caps) {
4327 gst_caps_unref(player->a_stream_caps);
4328 player->a_stream_caps = NULL;
4331 if (player->s_stream_caps) {
4332 gst_caps_unref(player->s_stream_caps);
4333 player->s_stream_caps = NULL;
4335 _mmplayer_track_destroy(player);
4337 if (player->sink_elements)
4338 g_list_free(player->sink_elements);
4339 player->sink_elements = NULL;
4341 if (player->bufmgr) {
4342 tbm_bufmgr_deinit(player->bufmgr);
4343 player->bufmgr = NULL;
4346 LOGW("finished destroy pipeline");
4354 __mmplayer_gst_realize(mmplayer_t *player)
4357 int ret = MM_ERROR_NONE;
4361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4363 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4365 ret = __mmplayer_gst_create_pipeline(player);
4367 LOGE("failed to create pipeline");
4371 /* set pipeline state to READY */
4372 /* NOTE : state change to READY must be performed sync. */
4373 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4374 ret = _mmplayer_gst_set_state(player,
4375 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4377 if (ret != MM_ERROR_NONE) {
4378 /* return error if failed to set state */
4379 LOGE("failed to set READY state");
4383 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4385 /* create dot before error-return. for debugging */
4386 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4394 __mmplayer_gst_unrealize(mmplayer_t *player)
4396 int ret = MM_ERROR_NONE;
4400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4402 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4403 MMPLAYER_PRINT_STATE(player);
4405 /* release miscellaneous information */
4406 __mmplayer_release_misc(player);
4408 /* destroy pipeline */
4409 ret = __mmplayer_gst_destroy_pipeline(player);
4410 if (ret != MM_ERROR_NONE) {
4411 LOGE("failed to destory pipeline");
4415 /* release miscellaneous information.
4416 these info needs to be released after pipeline is destroyed. */
4417 __mmplayer_release_misc_post(player);
4419 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4427 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4432 LOGW("set_message_callback is called with invalid player handle");
4433 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4436 player->msg_cb = callback;
4437 player->msg_cb_param = user_param;
4439 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4443 return MM_ERROR_NONE;
4447 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4449 int ret = MM_ERROR_NONE;
4454 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4455 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4456 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4458 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4460 if (strstr(uri, "es_buff://")) {
4461 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4462 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4463 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4464 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4466 tmp = g_ascii_strdown(uri, strlen(uri));
4467 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4468 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4470 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4472 } else if (strstr(uri, "mms://")) {
4473 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4474 } else if ((path = strstr(uri, "mem://"))) {
4475 ret = __mmplayer_set_mem_uri(data, path, param);
4477 ret = __mmplayer_set_file_uri(data, uri);
4480 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4481 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4482 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4483 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4485 /* dump parse result */
4486 SECURE_LOGW("incoming uri : %s", uri);
4487 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4488 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4496 __mmplayer_can_do_interrupt(mmplayer_t *player)
4498 if (!player || !player->pipeline || !player->attrs) {
4499 LOGW("not initialized");
4503 if (player->audio_decoded_cb) {
4504 LOGW("not support in pcm extraction mode");
4508 /* check if seeking */
4509 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4510 MMMessageParamType msg_param;
4511 memset(&msg_param, 0, sizeof(MMMessageParamType));
4512 msg_param.code = MM_ERROR_PLAYER_SEEK;
4513 player->seek_state = MMPLAYER_SEEK_NONE;
4514 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4518 /* check other thread */
4519 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4520 LOGW("locked already, cmd state : %d", player->cmd);
4522 /* check application command */
4523 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4524 LOGW("playing.. should wait cmd lock then, will be interrupted");
4526 /* lock will be released at mrp_resource_release_cb() */
4527 MMPLAYER_CMD_LOCK(player);
4530 LOGW("nothing to do");
4533 LOGW("can interrupt immediately");
4537 FAILED: /* with CMD UNLOCKED */
4540 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4545 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4548 mmplayer_t *player = NULL;
4549 MMMessageParamType msg = {0, };
4551 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4556 LOGE("user_data is null");
4559 player = (mmplayer_t *)user_data;
4561 if (!__mmplayer_can_do_interrupt(player)) {
4562 LOGW("no need to interrupt, so leave");
4563 /* FIXME: there is no way to avoid releasing resource. */
4567 player->interrupted_by_resource = TRUE;
4569 /* get last play position */
4570 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4571 msg.union_type = MM_MSG_UNION_TIME;
4572 msg.time.elapsed = pos;
4573 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4575 LOGW("failed to get play position.");
4578 LOGD("video resource conflict so, resource will be freed by unrealizing");
4579 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4580 LOGE("failed to unrealize");
4582 /* lock is called in __mmplayer_can_do_interrupt() */
4583 MMPLAYER_CMD_UNLOCK(player);
4585 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4586 player->hw_resource[res_idx] = NULL;
4590 return TRUE; /* release all the resources */
4594 __mmplayer_initialize_video_roi(mmplayer_t *player)
4596 player->video_roi.scale_x = 0.0;
4597 player->video_roi.scale_y = 0.0;
4598 player->video_roi.scale_width = 1.0;
4599 player->video_roi.scale_height = 1.0;
4603 _mmplayer_create_player(MMHandleType handle)
4605 int ret = MM_ERROR_PLAYER_INTERNAL;
4606 bool enabled = false;
4608 mmplayer_t *player = MM_PLAYER_CAST(handle);
4612 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4614 /* initialize player state */
4615 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4616 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4617 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4618 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4620 /* check current state */
4621 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4623 /* construct attributes */
4624 player->attrs = _mmplayer_construct_attribute(handle);
4626 if (!player->attrs) {
4627 LOGE("Failed to construct attributes");
4631 /* initialize gstreamer with configured parameter */
4632 if (!__mmplayer_init_gstreamer(player)) {
4633 LOGE("Initializing gstreamer failed");
4634 _mmplayer_deconstruct_attribute(handle);
4638 /* create lock. note that g_tread_init() has already called in gst_init() */
4639 g_mutex_init(&player->fsink_lock);
4641 /* create update tag lock */
4642 g_mutex_init(&player->update_tag_lock);
4644 /* create gapless play mutex */
4645 g_mutex_init(&player->gapless_play_thread_mutex);
4647 /* create gapless play cond */
4648 g_cond_init(&player->gapless_play_thread_cond);
4650 /* create gapless play thread */
4651 player->gapless_play_thread =
4652 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4653 if (!player->gapless_play_thread) {
4654 LOGE("failed to create gapless play thread");
4655 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4656 g_mutex_clear(&player->gapless_play_thread_mutex);
4657 g_cond_clear(&player->gapless_play_thread_cond);
4661 player->bus_msg_q = g_queue_new();
4662 if (!player->bus_msg_q) {
4663 LOGE("failed to create queue for bus_msg");
4664 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4668 ret = _mmplayer_initialize_video_capture(player);
4669 if (ret != MM_ERROR_NONE) {
4670 LOGE("failed to initialize video capture");
4674 /* initialize resource manager */
4675 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4676 __resource_release_cb, player, &player->resource_manager)
4677 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4678 LOGE("failed to initialize resource manager");
4679 ret = MM_ERROR_PLAYER_INTERNAL;
4683 /* create video bo lock and cond */
4684 g_mutex_init(&player->video_bo_mutex);
4685 g_cond_init(&player->video_bo_cond);
4687 /* create subtitle info lock and cond */
4688 g_mutex_init(&player->subtitle_info_mutex);
4689 g_cond_init(&player->subtitle_info_cond);
4691 player->streaming_type = STREAMING_SERVICE_NONE;
4693 /* give default value of audio effect setting */
4694 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4695 player->sound.rg_enable = false;
4696 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4698 player->play_subtitle = FALSE;
4699 player->has_closed_caption = FALSE;
4700 player->pending_resume = FALSE;
4701 if (player->ini.dump_element_keyword[0][0] == '\0')
4702 player->ini.set_dump_element_flag = FALSE;
4704 player->ini.set_dump_element_flag = TRUE;
4706 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4707 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4708 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4710 /* Set video360 settings to their defaults for just-created player.
4713 player->is_360_feature_enabled = FALSE;
4714 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4715 LOGI("spherical feature info: %d", enabled);
4717 player->is_360_feature_enabled = TRUE;
4719 LOGE("failed to get spherical feature info");
4722 player->is_content_spherical = FALSE;
4723 player->is_video360_enabled = TRUE;
4724 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4725 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4726 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4727 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4728 player->video360_zoom = 1.0f;
4729 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4730 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4732 __mmplayer_initialize_video_roi(player);
4734 /* set player state to null */
4735 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4736 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4740 return MM_ERROR_NONE;
4744 g_mutex_clear(&player->fsink_lock);
4745 /* free update tag lock */
4746 g_mutex_clear(&player->update_tag_lock);
4747 g_queue_free(player->bus_msg_q);
4748 player->bus_msg_q = NULL;
4749 /* free gapless play thread */
4750 if (player->gapless_play_thread) {
4751 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4752 player->gapless_play_thread_exit = TRUE;
4753 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4754 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4756 g_thread_join(player->gapless_play_thread);
4757 player->gapless_play_thread = NULL;
4759 g_mutex_clear(&player->gapless_play_thread_mutex);
4760 g_cond_clear(&player->gapless_play_thread_cond);
4763 /* release attributes */
4764 _mmplayer_deconstruct_attribute(handle);
4772 __mmplayer_init_gstreamer(mmplayer_t *player)
4774 static gboolean initialized = FALSE;
4775 static const int max_argc = 50;
4777 gchar **argv = NULL;
4778 gchar **argv2 = NULL;
4784 LOGD("gstreamer already initialized.");
4789 argc = malloc(sizeof(int));
4790 argv = malloc(sizeof(gchar *) * max_argc);
4791 argv2 = malloc(sizeof(gchar *) * max_argc);
4793 if (!argc || !argv || !argv2)
4796 memset(argv, 0, sizeof(gchar *) * max_argc);
4797 memset(argv2, 0, sizeof(gchar *) * max_argc);
4801 argv[0] = g_strdup("mmplayer");
4804 for (i = 0; i < 5; i++) {
4805 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4806 if (strlen(player->ini.gst_param[i]) > 0) {
4807 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4812 /* we would not do fork for scanning plugins */
4813 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4816 /* check disable registry scan */
4817 if (player->ini.skip_rescan) {
4818 argv[*argc] = g_strdup("--gst-disable-registry-update");
4822 /* check disable segtrap */
4823 if (player->ini.disable_segtrap) {
4824 argv[*argc] = g_strdup("--gst-disable-segtrap");
4828 LOGD("initializing gstreamer with following parameter");
4829 LOGD("argc : %d", *argc);
4832 for (i = 0; i < arg_count; i++) {
4834 LOGD("argv[%d] : %s", i, argv2[i]);
4837 /* initializing gstreamer */
4838 if (!gst_init_check(argc, &argv, &err)) {
4839 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4846 for (i = 0; i < arg_count; i++) {
4848 LOGD("release - argv[%d] : %s", i, argv2[i]);
4850 MMPLAYER_FREEIF(argv2[i]);
4853 MMPLAYER_FREEIF(argv);
4854 MMPLAYER_FREEIF(argv2);
4855 MMPLAYER_FREEIF(argc);
4865 for (i = 0; i < arg_count; i++) {
4866 LOGD("free[%d] : %s", i, argv2[i]);
4867 MMPLAYER_FREEIF(argv2[i]);
4870 MMPLAYER_FREEIF(argv);
4871 MMPLAYER_FREEIF(argv2);
4872 MMPLAYER_FREEIF(argc);
4878 __mmplayer_check_async_state_transition(mmplayer_t *player)
4880 GstState element_state = GST_STATE_VOID_PENDING;
4881 GstState element_pending_state = GST_STATE_VOID_PENDING;
4882 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4883 GstElement *element = NULL;
4884 gboolean async = FALSE;
4886 /* check player handle */
4887 MMPLAYER_RETURN_IF_FAIL(player &&
4889 player->pipeline->mainbin &&
4890 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4893 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4895 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4896 LOGD("don't need to check the pipeline state");
4900 MMPLAYER_PRINT_STATE(player);
4902 /* wait for state transition */
4903 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4904 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4906 if (ret == GST_STATE_CHANGE_FAILURE) {
4907 LOGE(" [%s] state : %s pending : %s",
4908 GST_ELEMENT_NAME(element),
4909 gst_element_state_get_name(element_state),
4910 gst_element_state_get_name(element_pending_state));
4912 /* dump state of all element */
4913 _mmplayer_dump_pipeline_state(player);
4918 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4923 _mmplayer_destroy(MMHandleType handle)
4925 mmplayer_t *player = MM_PLAYER_CAST(handle);
4929 /* check player handle */
4930 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4932 /* destroy can called at anytime */
4933 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4935 /* check async state transition */
4936 __mmplayer_check_async_state_transition(player);
4938 /* release gapless play thread */
4939 if (player->gapless_play_thread) {
4940 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4941 player->gapless_play_thread_exit = TRUE;
4942 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4943 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4945 LOGD("waitting for gapless play thread exit");
4946 g_thread_join(player->gapless_play_thread);
4947 g_mutex_clear(&player->gapless_play_thread_mutex);
4948 g_cond_clear(&player->gapless_play_thread_cond);
4949 LOGD("gapless play thread released");
4952 _mmplayer_release_video_capture(player);
4954 /* de-initialize resource manager */
4955 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4956 player->resource_manager))
4957 LOGE("failed to deinitialize resource manager");
4959 /* release miscellaneous information */
4960 __mmplayer_release_misc(player);
4962 /* release pipeline */
4963 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4964 LOGE("failed to destory pipeline");
4965 return MM_ERROR_PLAYER_INTERNAL;
4968 g_queue_free(player->bus_msg_q);
4970 /* release subtitle info lock and cond */
4971 g_mutex_clear(&player->subtitle_info_mutex);
4972 g_cond_clear(&player->subtitle_info_cond);
4974 __mmplayer_release_dump_list(player->dump_list);
4976 /* release miscellaneous information.
4977 these info needs to be released after pipeline is destroyed. */
4978 __mmplayer_release_misc_post(player);
4980 /* release attributes */
4981 _mmplayer_deconstruct_attribute(handle);
4983 if (player->uri_info.uri_list) {
4984 GList *uri_list = player->uri_info.uri_list;
4985 for (; uri_list; uri_list = g_list_next(uri_list)) {
4986 gchar *uri = uri_list->data;
4987 MMPLAYER_FREEIF(uri);
4989 g_list_free(player->uri_info.uri_list);
4990 player->uri_info.uri_list = NULL;
4994 g_mutex_clear(&player->fsink_lock);
4997 g_mutex_clear(&player->update_tag_lock);
4999 /* release video bo lock and cond */
5000 g_mutex_clear(&player->video_bo_mutex);
5001 g_cond_clear(&player->video_bo_cond);
5005 return MM_ERROR_NONE;
5009 _mmplayer_realize(MMHandleType hplayer)
5011 mmplayer_t *player = (mmplayer_t *)hplayer;
5012 int ret = MM_ERROR_NONE;
5015 MMHandleType attrs = 0;
5016 int video_codec_type = 0;
5017 int audio_codec_type = 0;
5018 int default_codec_type = 0;
5021 /* check player handle */
5022 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5024 /* check current state */
5025 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5027 attrs = MMPLAYER_GET_ATTRS(player);
5029 LOGE("fail to get attributes.");
5030 return MM_ERROR_PLAYER_INTERNAL;
5032 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5033 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5035 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5036 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5038 if (ret != MM_ERROR_NONE) {
5039 LOGE("failed to parse profile");
5044 if (uri && (strstr(uri, "es_buff://"))) {
5045 if (strstr(uri, "es_buff://push_mode"))
5046 player->es_player_push_mode = TRUE;
5048 player->es_player_push_mode = FALSE;
5051 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5052 LOGW("mms protocol is not supported format.");
5053 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5056 if (MMPLAYER_IS_STREAMING(player))
5057 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5059 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5061 player->smooth_streaming = FALSE;
5062 player->videodec_linked = 0;
5063 player->audiodec_linked = 0;
5064 player->textsink_linked = 0;
5065 player->is_external_subtitle_present = FALSE;
5066 player->is_external_subtitle_added_now = FALSE;
5067 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5068 player->video360_metadata.is_spherical = -1;
5069 player->is_openal_plugin_used = FALSE;
5070 player->demux_pad_index = 0;
5071 player->subtitle_language_list = NULL;
5072 player->is_subtitle_force_drop = FALSE;
5074 _mmplayer_track_initialize(player);
5075 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5077 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5078 gint prebuffer_ms = 0, rebuffer_ms = 0;
5080 player->streamer = _mm_player_streaming_create();
5081 _mm_player_streaming_initialize(player->streamer, TRUE);
5083 mm_attrs_multiple_get(player->attrs, NULL,
5084 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5085 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5087 if (prebuffer_ms > 0) {
5088 prebuffer_ms = MAX(prebuffer_ms, 1000);
5089 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5092 if (rebuffer_ms > 0) {
5093 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5094 rebuffer_ms = MAX(rebuffer_ms, 1000);
5095 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5098 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5099 player->streamer->buffering_req.rebuffer_time);
5102 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5103 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5104 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5106 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5108 if (audio_codec_type != default_codec_type) {
5109 LOGD("audio dec sorting is required");
5110 player->need_audio_dec_sorting = TRUE;
5113 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5114 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5115 LOGD("video dec sorting is required");
5116 player->need_video_dec_sorting = TRUE;
5119 /* realize pipeline */
5120 ret = __mmplayer_gst_realize(player);
5121 if (ret != MM_ERROR_NONE)
5122 LOGE("fail to realize the player.");
5124 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5132 _mmplayer_unrealize(MMHandleType hplayer)
5134 mmplayer_t *player = (mmplayer_t *)hplayer;
5135 int ret = MM_ERROR_NONE;
5139 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5141 MMPLAYER_CMD_UNLOCK(player);
5142 _mmplayer_bus_watcher_remove(player);
5143 /* destroy the gst bus msg thread which is created during realize.
5144 this funct have to be called before getting cmd lock. */
5145 _mmplayer_bus_msg_thread_destroy(player);
5146 MMPLAYER_CMD_LOCK(player);
5148 /* check current state */
5149 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5151 /* check async state transition */
5152 __mmplayer_check_async_state_transition(player);
5154 /* unrealize pipeline */
5155 ret = __mmplayer_gst_unrealize(player);
5157 if (!player->interrupted_by_resource) {
5158 int rm_ret = MM_ERROR_NONE;
5159 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5161 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5162 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5163 if (rm_ret != MM_ERROR_NONE)
5164 LOGE("failed to release [%d] resources", res_idx);
5173 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5175 mmplayer_t *player = (mmplayer_t *)hplayer;
5177 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5179 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5183 _mmplayer_get_state(MMHandleType hplayer, int *state)
5185 mmplayer_t *player = (mmplayer_t *)hplayer;
5187 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5189 *state = MMPLAYER_CURRENT_STATE(player);
5191 return MM_ERROR_NONE;
5195 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5197 GstElement *vol_element = NULL;
5198 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5201 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5202 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5204 /* check pipeline handle */
5205 if (!player->pipeline || !player->pipeline->audiobin) {
5206 LOGD("'%s' will be applied when audiobin is created", prop_name);
5208 /* NOTE : stored value will be used in create_audiobin
5209 * returning MM_ERROR_NONE here makes application to able to
5210 * set audio volume or mute at anytime.
5212 return MM_ERROR_NONE;
5215 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5216 volume_elem_id = MMPLAYER_A_SINK;
5218 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5220 LOGE("failed to get vol element %d", volume_elem_id);
5221 return MM_ERROR_PLAYER_INTERNAL;
5224 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5226 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5227 LOGE("there is no '%s' property", prop_name);
5228 return MM_ERROR_PLAYER_INTERNAL;
5231 if (!strcmp(prop_name, "volume")) {
5232 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5233 } else if (!strcmp(prop_name, "mute")) {
5234 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5236 LOGE("invalid property %s", prop_name);
5237 return MM_ERROR_PLAYER_INTERNAL;
5240 return MM_ERROR_NONE;
5244 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5246 int ret = MM_ERROR_NONE;
5247 mmplayer_t *player = (mmplayer_t *)hplayer;
5250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5252 LOGD("volume = %f", volume);
5254 /* invalid factor range or not */
5255 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5256 LOGE("Invalid volume value");
5257 return MM_ERROR_INVALID_ARGUMENT;
5260 player->sound.volume = volume;
5262 ret = __mmplayer_gst_set_volume_property(player, "volume");
5269 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5271 mmplayer_t *player = (mmplayer_t *)hplayer;
5275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5276 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5278 *volume = player->sound.volume;
5280 LOGD("current vol = %f", *volume);
5283 return MM_ERROR_NONE;
5287 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5289 int ret = MM_ERROR_NONE;
5290 mmplayer_t *player = (mmplayer_t *)hplayer;
5293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5295 LOGD("mute = %d", mute);
5297 player->sound.mute = mute;
5299 ret = __mmplayer_gst_set_volume_property(player, "mute");
5306 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5308 mmplayer_t *player = (mmplayer_t *)hplayer;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5313 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5315 *mute = player->sound.mute;
5317 LOGD("current mute = %d", *mute);
5321 return MM_ERROR_NONE;
5325 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5327 mmplayer_t *player = (mmplayer_t *)hplayer;
5331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5333 player->audio_stream_changed_cb = callback;
5334 player->audio_stream_changed_cb_user_param = user_param;
5335 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5339 return MM_ERROR_NONE;
5343 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5345 mmplayer_t *player = (mmplayer_t *)hplayer;
5349 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5351 player->audio_decoded_cb = callback;
5352 player->audio_decoded_cb_user_param = user_param;
5353 player->audio_extract_opt = opt;
5354 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5358 return MM_ERROR_NONE;
5362 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5364 mmplayer_t *player = (mmplayer_t *)hplayer;
5368 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5370 if (callback && !player->bufmgr)
5371 player->bufmgr = tbm_bufmgr_init(-1);
5373 player->set_mode.video_export = (callback) ? true : false;
5374 player->video_decoded_cb = callback;
5375 player->video_decoded_cb_user_param = user_param;
5377 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5381 return MM_ERROR_NONE;
5385 _mmplayer_start(MMHandleType hplayer)
5387 mmplayer_t *player = (mmplayer_t *)hplayer;
5388 gint ret = MM_ERROR_NONE;
5392 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5394 /* check current state */
5395 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5397 /* start pipeline */
5398 ret = _mmplayer_gst_start(player);
5399 if (ret != MM_ERROR_NONE)
5400 LOGE("failed to start player.");
5402 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5403 LOGD("force playing start even during buffering");
5404 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5412 /* NOTE: post "not supported codec message" to application
5413 * when one codec is not found during AUTOPLUGGING in MSL.
5414 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5415 * And, if any codec is not found, don't send message here.
5416 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5419 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5421 MMMessageParamType msg_param;
5422 memset(&msg_param, 0, sizeof(MMMessageParamType));
5423 gboolean post_msg_direct = FALSE;
5427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5429 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5430 player->not_supported_codec, player->can_support_codec);
5432 if (player->not_found_demuxer) {
5433 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5434 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5436 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5437 MMPLAYER_FREEIF(msg_param.data);
5439 return MM_ERROR_NONE;
5442 if (player->not_supported_codec) {
5443 if (player->can_support_codec) {
5444 // There is one codec to play
5445 post_msg_direct = TRUE;
5447 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5448 post_msg_direct = TRUE;
5451 if (post_msg_direct) {
5452 MMMessageParamType msg_param;
5453 memset(&msg_param, 0, sizeof(MMMessageParamType));
5455 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5456 LOGW("not found AUDIO codec, posting error code to application.");
5458 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5459 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5460 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5461 LOGW("not found VIDEO codec, posting error code to application.");
5463 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5464 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5467 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5469 MMPLAYER_FREEIF(msg_param.data);
5471 return MM_ERROR_NONE;
5473 // no any supported codec case
5474 LOGW("not found any codec, posting error code to application.");
5476 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5477 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5478 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5480 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5481 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5484 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5486 MMPLAYER_FREEIF(msg_param.data);
5492 return MM_ERROR_NONE;
5495 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5497 GstState element_state = GST_STATE_VOID_PENDING;
5498 GstState element_pending_state = GST_STATE_VOID_PENDING;
5499 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5500 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5502 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5504 MMPLAYER_RECONFIGURE_LOCK(player);
5505 if (!player->gapless.reconfigure) {
5506 MMPLAYER_RECONFIGURE_UNLOCK(player);
5510 LOGI("reconfigure is under process");
5511 MMPLAYER_RECONFIGURE_WAIT(player);
5512 MMPLAYER_RECONFIGURE_UNLOCK(player);
5513 LOGI("reconfigure is completed.");
5515 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5516 &element_state, &element_pending_state, timeout * GST_SECOND);
5517 if (result == GST_STATE_CHANGE_FAILURE)
5518 LOGW("failed to get pipeline state in %d sec", timeout);
5523 /* NOTE : it should be able to call 'stop' anytime*/
5525 _mmplayer_stop(MMHandleType hplayer)
5527 mmplayer_t *player = (mmplayer_t *)hplayer;
5528 int ret = MM_ERROR_NONE;
5532 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5534 /* check current state */
5535 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5537 /* need to wait till the rebuilding pipeline is completed */
5538 __mmplayer_check_pipeline_reconfigure_state(player);
5539 MMPLAYER_RECONFIGURE_LOCK(player);
5540 __mmplayer_reset_gapless_state(player);
5541 MMPLAYER_RECONFIGURE_UNLOCK(player);
5543 /* NOTE : application should not wait for EOS after calling STOP */
5544 _mmplayer_cancel_eos_timer(player);
5547 player->seek_state = MMPLAYER_SEEK_NONE;
5550 ret = _mmplayer_gst_stop(player);
5552 if (ret != MM_ERROR_NONE)
5553 LOGE("failed to stop player.");
5561 _mmplayer_pause(MMHandleType hplayer)
5563 mmplayer_t *player = (mmplayer_t *)hplayer;
5564 gint64 pos_nsec = 0;
5565 gboolean async = FALSE;
5566 gint ret = MM_ERROR_NONE;
5570 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5572 /* check current state */
5573 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5575 /* check pipline reconfigure state */
5576 __mmplayer_check_pipeline_reconfigure_state(player);
5578 switch (MMPLAYER_CURRENT_STATE(player)) {
5579 case MM_PLAYER_STATE_READY:
5581 /* check prepare async or not.
5582 * In the case of streaming playback, it's recommned to avoid blocking wait.
5584 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5585 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5587 /* Changing back sync of rtspsrc to async */
5588 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5589 LOGD("async prepare working mode for rtsp");
5595 case MM_PLAYER_STATE_PLAYING:
5597 /* NOTE : store current point to overcome some bad operation
5598 *(returning zero when getting current position in paused state) of some
5601 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5602 LOGW("getting current position failed in paused");
5604 player->last_position = pos_nsec;
5606 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5607 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5608 This causes problem is position calculation during normal pause resume scenarios also.
5609 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5610 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5611 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5612 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5618 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5619 LOGD("doing async pause in case of ms buff src");
5623 /* pause pipeline */
5624 ret = _mmplayer_gst_pause(player, async);
5626 if (ret != MM_ERROR_NONE)
5627 LOGE("failed to pause player. ret : 0x%x", ret);
5629 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5630 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5631 LOGE("failed to update display_rotation");
5639 /* in case of streaming, pause could take long time.*/
5641 _mmplayer_abort_pause(MMHandleType hplayer)
5643 mmplayer_t *player = (mmplayer_t *)hplayer;
5644 int ret = MM_ERROR_NONE;
5648 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5650 player->pipeline->mainbin,
5651 MM_ERROR_PLAYER_NOT_INITIALIZED);
5653 LOGD("set the pipeline state to READY");
5655 /* set state to READY */
5656 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5657 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5658 if (ret != MM_ERROR_NONE) {
5659 LOGE("fail to change state to READY");
5660 return MM_ERROR_PLAYER_INTERNAL;
5663 LOGD("succeeded in changing state to READY");
5668 _mmplayer_resume(MMHandleType hplayer)
5670 mmplayer_t *player = (mmplayer_t *)hplayer;
5671 int ret = MM_ERROR_NONE;
5672 gboolean async = FALSE;
5676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5678 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5679 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5680 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5684 /* Changing back sync mode rtspsrc to async */
5685 LOGD("async resume for rtsp case");
5689 /* check current state */
5690 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5692 ret = _mmplayer_gst_resume(player, async);
5693 if (ret != MM_ERROR_NONE)
5694 LOGE("failed to resume player.");
5696 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5697 LOGD("force resume even during buffering");
5698 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5707 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5709 mmplayer_t *player = (mmplayer_t *)hplayer;
5710 gint64 pos_nsec = 0;
5711 int ret = MM_ERROR_NONE;
5713 signed long long start = 0, stop = 0;
5714 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5718 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5720 /* The sound of video is not supported under 0.0 and over 2.0. */
5721 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5722 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5725 _mmplayer_set_mute(hplayer, mute);
5727 if (player->playback_rate == rate)
5728 return MM_ERROR_NONE;
5730 /* If the position is reached at start potion during fast backward, EOS is posted.
5731 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5733 player->playback_rate = rate;
5735 current_state = MMPLAYER_CURRENT_STATE(player);
5737 if (current_state != MM_PLAYER_STATE_PAUSED)
5738 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5740 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5742 if ((current_state == MM_PLAYER_STATE_PAUSED)
5743 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5744 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5745 pos_nsec = player->last_position;
5750 stop = GST_CLOCK_TIME_NONE;
5752 start = GST_CLOCK_TIME_NONE;
5756 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5757 player->playback_rate,
5759 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5760 GST_SEEK_TYPE_SET, start,
5761 GST_SEEK_TYPE_SET, stop)) {
5762 LOGE("failed to set speed playback");
5763 return MM_ERROR_PLAYER_SEEK;
5766 LOGD("succeeded to set speed playback as %0.1f", rate);
5770 return MM_ERROR_NONE;;
5774 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5776 mmplayer_t *player = (mmplayer_t *)hplayer;
5777 int ret = MM_ERROR_NONE;
5781 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5783 /* check pipline reconfigure state */
5784 __mmplayer_check_pipeline_reconfigure_state(player);
5786 ret = _mmplayer_gst_set_position(player, position, FALSE);
5794 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5796 mmplayer_t *player = (mmplayer_t *)hplayer;
5797 int ret = MM_ERROR_NONE;
5799 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5800 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5802 if (g_strrstr(player->type, "video/mpegts"))
5803 __mmplayer_update_duration_value(player);
5805 *duration = player->duration;
5810 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5812 mmplayer_t *player = (mmplayer_t *)hplayer;
5813 int ret = MM_ERROR_NONE;
5815 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5817 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5823 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5825 mmplayer_t *player = (mmplayer_t *)hplayer;
5826 int ret = MM_ERROR_NONE;
5830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5832 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5840 __mmplayer_is_midi_type(gchar *str_caps)
5842 if ((g_strrstr(str_caps, "audio/midi")) ||
5843 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5844 (g_strrstr(str_caps, "application/x-smaf")) ||
5845 (g_strrstr(str_caps, "audio/x-imelody")) ||
5846 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5847 (g_strrstr(str_caps, "audio/xmf")) ||
5848 (g_strrstr(str_caps, "audio/mxmf"))) {
5857 __mmplayer_is_only_mp3_type(gchar *str_caps)
5859 if (g_strrstr(str_caps, "application/x-id3") ||
5860 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5866 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5868 GstStructure *caps_structure = NULL;
5869 gint samplerate = 0;
5873 MMPLAYER_RETURN_IF_FAIL(player && caps);
5875 caps_structure = gst_caps_get_structure(caps, 0);
5877 /* set stream information */
5878 gst_structure_get_int(caps_structure, "rate", &samplerate);
5879 gst_structure_get_int(caps_structure, "channels", &channels);
5881 mm_player_set_attribute((MMHandleType)player, NULL,
5882 "content_audio_samplerate", samplerate,
5883 "content_audio_channels", channels, NULL);
5885 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5889 __mmplayer_update_content_type_info(mmplayer_t *player)
5892 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5894 if (__mmplayer_is_midi_type(player->type)) {
5895 player->bypass_audio_effect = TRUE;
5899 if (!player->streamer) {
5900 LOGD("no need to check streaming type");
5904 if (g_strrstr(player->type, "application/x-hls")) {
5905 /* If it can't know exact type when it parses uri because of redirection case,
5906 * it will be fixed by typefinder or when doing autoplugging.
5908 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5909 player->streamer->is_adaptive_streaming = TRUE;
5910 } else if (g_strrstr(player->type, "application/dash+xml")) {
5911 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5912 player->streamer->is_adaptive_streaming = TRUE;
5915 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5916 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5917 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5919 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5920 if (player->streamer->is_adaptive_streaming)
5921 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5923 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5927 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5932 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5933 GstCaps *caps, gpointer data)
5935 mmplayer_t *player = (mmplayer_t *)data;
5940 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5942 /* store type string */
5943 MMPLAYER_FREEIF(player->type);
5944 player->type = gst_caps_to_string(caps);
5946 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5947 player, player->type, probability, gst_caps_get_size(caps));
5949 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5950 (g_strrstr(player->type, "audio/x-raw-int"))) {
5951 LOGE("not support media format");
5953 if (player->msg_posted == FALSE) {
5954 MMMessageParamType msg_param;
5955 memset(&msg_param, 0, sizeof(MMMessageParamType));
5957 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5958 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5960 /* don't post more if one was sent already */
5961 player->msg_posted = TRUE;
5966 __mmplayer_update_content_type_info(player);
5968 pad = gst_element_get_static_pad(tf, "src");
5970 LOGE("fail to get typefind src pad.");
5974 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5975 gboolean async = FALSE;
5976 LOGE("failed to autoplug %s", player->type);
5978 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5980 if (async && player->msg_posted == FALSE)
5981 __mmplayer_handle_missed_plugin(player);
5985 gst_object_unref(GST_OBJECT(pad));
5993 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5995 GstElement *decodebin = NULL;
5999 /* create decodebin */
6000 decodebin = gst_element_factory_make("decodebin", NULL);
6003 LOGE("fail to create decodebin");
6007 /* raw pad handling signal */
6008 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6009 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6011 /* no-more-pad pad handling signal */
6012 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6013 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6015 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6016 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6018 /* This signal is emitted when a pad for which there is no further possible
6019 decoding is added to the decodebin.*/
6020 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6021 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6023 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6024 before looking for any elements that can handle that stream.*/
6025 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6026 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6028 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6029 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6030 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6032 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6033 before looking for any elements that can handle that stream.*/
6034 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6035 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6037 /* This signal is emitted once decodebin has finished decoding all the data.*/
6038 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6039 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6041 /* This signal is emitted when a element is added to the bin.*/
6042 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6043 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6050 __mmplayer_gst_make_queue2(mmplayer_t *player)
6052 GstElement *queue2 = NULL;
6053 gint64 dur_bytes = 0L;
6054 mmplayer_gst_element_t *mainbin = NULL;
6055 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6058 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6060 mainbin = player->pipeline->mainbin;
6062 queue2 = gst_element_factory_make("queue2", "queue2");
6064 LOGE("failed to create buffering queue element");
6068 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6069 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6071 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6073 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6074 * skip the pull mode(file or ring buffering) setting. */
6075 if (dur_bytes > 0) {
6076 if (!g_strrstr(player->type, "video/mpegts")) {
6077 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6078 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6084 _mm_player_streaming_set_queue2(player->streamer,
6088 (guint64)dur_bytes); /* no meaning at the moment */
6094 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6096 mmplayer_gst_element_t *mainbin = NULL;
6097 GstElement *decodebin = NULL;
6098 GstElement *queue2 = NULL;
6099 GstPad *sinkpad = NULL;
6100 GstPad *qsrcpad = NULL;
6103 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6105 mainbin = player->pipeline->mainbin;
6107 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6109 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6110 LOGW("need to check: muxed buffer is not null");
6113 queue2 = __mmplayer_gst_make_queue2(player);
6115 LOGE("failed to make queue2");
6119 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6120 LOGE("failed to add buffering queue");
6124 sinkpad = gst_element_get_static_pad(queue2, "sink");
6125 qsrcpad = gst_element_get_static_pad(queue2, "src");
6127 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6128 LOGE("failed to link [%s:%s]-[%s:%s]",
6129 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6133 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6134 LOGE("failed to sync queue2 state with parent");
6138 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6139 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6143 gst_object_unref(GST_OBJECT(sinkpad));
6147 /* create decodebin */
6148 decodebin = _mmplayer_gst_make_decodebin(player);
6150 LOGE("failed to make decodebin");
6154 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6155 LOGE("failed to add decodebin");
6159 /* to force caps on the decodebin element and avoid reparsing stuff by
6160 * typefind. It also avoids a deadlock in the way typefind activates pads in
6161 * the state change */
6162 g_object_set(decodebin, "sink-caps", caps, NULL);
6164 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6166 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6167 LOGE("failed to link [%s:%s]-[%s:%s]",
6168 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6172 gst_object_unref(GST_OBJECT(sinkpad));
6174 gst_object_unref(GST_OBJECT(qsrcpad));
6177 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6178 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6180 /* set decodebin property about buffer in streaming playback. *
6181 * in case of HLS/DASH, it does not need to have big buffer *
6182 * because it is kind of adaptive streaming. */
6183 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6184 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6185 gint high_percent = 0;
6187 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6188 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6190 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6192 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6194 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6195 "high-percent", high_percent,
6196 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6197 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6198 "max-size-buffers", 0, NULL); // disable or automatic
6201 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6202 LOGE("failed to sync decodebin state with parent");
6213 gst_object_unref(GST_OBJECT(sinkpad));
6216 gst_object_unref(GST_OBJECT(qsrcpad));
6219 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6220 * You need to explicitly set elements to the NULL state before
6221 * dropping the final reference, to allow them to clean up.
6223 gst_element_set_state(queue2, GST_STATE_NULL);
6225 /* And, it still has a parent "player".
6226 * You need to let the parent manage the object instead of unreffing the object directly.
6228 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6229 gst_object_unref(queue2);
6234 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6235 * You need to explicitly set elements to the NULL state before
6236 * dropping the final reference, to allow them to clean up.
6238 gst_element_set_state(decodebin, GST_STATE_NULL);
6240 /* And, it still has a parent "player".
6241 * You need to let the parent manage the object instead of unreffing the object directly.
6244 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6245 gst_object_unref(decodebin);
6253 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6257 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6258 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6260 LOGD("class : %s, mime : %s", factory_class, mime);
6262 /* add missing plugin */
6263 /* NOTE : msl should check missing plugin for image mime type.
6264 * Some motion jpeg clips can have playable audio track.
6265 * So, msl have to play audio after displaying popup written video format not supported.
6267 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6268 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6269 LOGD("not found demuxer");
6270 player->not_found_demuxer = TRUE;
6271 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6277 if (!g_strrstr(factory_class, "Demuxer")) {
6278 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6279 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6280 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6282 /* check that clip have multi tracks or not */
6283 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6284 LOGD("video plugin is already linked");
6286 LOGW("add VIDEO to missing plugin");
6287 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6288 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6290 } else if (g_str_has_prefix(mime, "audio")) {
6291 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6292 LOGD("audio plugin is already linked");
6294 LOGW("add AUDIO to missing plugin");
6295 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6296 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6304 return MM_ERROR_NONE;
6308 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6310 mmplayer_t *player = (mmplayer_t *)data;
6314 MMPLAYER_RETURN_IF_FAIL(player);
6316 /* remove fakesink. */
6317 if (!_mmplayer_gst_remove_fakesink(player,
6318 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6319 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6320 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6321 * source element are not same. To overcome this situation, this function will called
6322 * several places and several times. Therefore, this is not an error case.
6327 LOGD("[handle: %p] pipeline has completely constructed", player);
6329 if ((player->msg_posted == FALSE) &&
6330 (player->cmd >= MMPLAYER_COMMAND_START))
6331 __mmplayer_handle_missed_plugin(player);
6333 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6337 __mmplayer_check_profile(void)
6340 static int profile_tv = -1;
6342 if (__builtin_expect(profile_tv != -1, 1))
6345 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6346 switch (*profileName) {
6361 __mmplayer_get_next_uri(mmplayer_t *player)
6363 mmplayer_parse_profile_t profile;
6365 guint num_of_list = 0;
6368 num_of_list = g_list_length(player->uri_info.uri_list);
6369 uri_idx = player->uri_info.uri_idx;
6371 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6372 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6373 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6375 LOGW("next uri does not exist");
6379 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6380 LOGE("failed to parse profile");
6384 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6385 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6386 LOGW("uri type is not supported(%d)", profile.uri_type);
6390 LOGD("success to find next uri %d", uri_idx);
6394 if (!uri || uri_idx == num_of_list) {
6395 LOGE("failed to find next uri");
6399 player->uri_info.uri_idx = uri_idx;
6400 if (mm_player_set_attribute((MMHandleType)player, NULL,
6401 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6402 LOGE("failed to set attribute");
6406 SECURE_LOGD("next playback uri: %s", uri);
6411 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6413 #define REPEAT_COUNT_INFINITE -1
6414 #define REPEAT_COUNT_MIN 2
6415 #define ORIGINAL_URI_ONLY 1
6417 MMHandleType attrs = 0;
6421 guint num_of_uri = 0;
6422 int profile_tv = -1;
6426 LOGD("checking for gapless play option");
6428 if (player->build_audio_offload) {
6429 LOGE("offload path is not supportable.");
6433 if (player->pipeline->textbin) {
6434 LOGE("subtitle path is enabled. gapless play is not supported.");
6438 attrs = MMPLAYER_GET_ATTRS(player);
6440 LOGE("fail to get attributes.");
6444 mm_attrs_multiple_get(player->attrs, NULL,
6445 "content_video_found", &video,
6446 "profile_play_count", &count,
6447 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6449 /* gapless playback is not supported in case of video at TV profile. */
6450 profile_tv = __mmplayer_check_profile();
6451 if (profile_tv && video) {
6452 LOGW("not support video gapless playback");
6456 /* check repeat count in case of audio */
6458 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6459 LOGW("gapless is disabled");
6463 num_of_uri = g_list_length(player->uri_info.uri_list);
6465 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6467 if (num_of_uri == ORIGINAL_URI_ONLY) {
6468 /* audio looping path */
6469 if (count >= REPEAT_COUNT_MIN) {
6470 /* decrease play count */
6471 /* we succeeded to rewind. update play count and then wait for next EOS */
6473 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6474 } else if (count != REPEAT_COUNT_INFINITE) {
6475 LOGD("there is no next uri and no repeat");
6478 LOGD("looping cnt %d", count);
6480 /* gapless playback path */
6481 if (!__mmplayer_get_next_uri(player)) {
6482 LOGE("failed to get next uri");
6489 LOGE("unable to play gapless path. EOS will be posted soon");
6494 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6496 mmplayer_selector_t *selector = &player->selector[type];
6497 mmplayer_gst_element_t *sinkbin = NULL;
6498 main_element_id_e selectorId = MMPLAYER_M_NUM;
6499 main_element_id_e sinkId = MMPLAYER_M_NUM;
6500 GstPad *srcpad = NULL;
6501 GstPad *sinkpad = NULL;
6502 gboolean send_notice = FALSE;
6505 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6507 LOGD("type %d", type);
6510 case MM_PLAYER_TRACK_TYPE_AUDIO:
6511 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6512 sinkId = MMPLAYER_A_BIN;
6513 sinkbin = player->pipeline->audiobin;
6515 case MM_PLAYER_TRACK_TYPE_VIDEO:
6516 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6517 sinkId = MMPLAYER_V_BIN;
6518 sinkbin = player->pipeline->videobin;
6521 case MM_PLAYER_TRACK_TYPE_TEXT:
6522 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6523 sinkId = MMPLAYER_T_BIN;
6524 sinkbin = player->pipeline->textbin;
6527 LOGE("requested type is not supportable");
6532 if (player->pipeline->mainbin[selectorId].gst) {
6535 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6537 if (selector->event_probe_id != 0)
6538 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6539 selector->event_probe_id = 0;
6541 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6542 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6544 if (srcpad && sinkpad) {
6545 /* after getting drained signal there is no data flows, so no need to do pad_block */
6546 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6547 gst_pad_unlink(srcpad, sinkpad);
6549 /* send custom event to sink pad to handle it at video sink */
6551 LOGD("send custom event to sinkpad");
6552 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6553 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6554 gst_pad_send_event(sinkpad, event);
6558 gst_object_unref(sinkpad);
6561 gst_object_unref(srcpad);
6564 LOGD("selector release");
6566 /* release and unref requests pad from the selector */
6567 for (n = 0; n < selector->channels->len; n++) {
6568 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6569 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6571 g_ptr_array_set_size(selector->channels, 0);
6573 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6574 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6576 player->pipeline->mainbin[selectorId].gst = NULL;
6584 __mmplayer_deactivate_old_path(mmplayer_t *player)
6587 MMPLAYER_RETURN_IF_FAIL(player);
6589 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6590 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6591 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6592 LOGE("deactivate selector error");
6596 _mmplayer_track_destroy(player);
6597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6599 if (player->streamer) {
6600 _mm_player_streaming_initialize(player->streamer, FALSE);
6601 _mm_player_streaming_destroy(player->streamer);
6602 player->streamer = NULL;
6605 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6611 if (!player->msg_posted) {
6612 MMMessageParamType msg = {0,};
6615 msg.code = MM_ERROR_PLAYER_INTERNAL;
6616 LOGE("gapless_uri_play> deactivate error");
6618 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6619 player->msg_posted = TRUE;
6625 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6627 int result = MM_ERROR_NONE;
6628 mmplayer_t *player = (mmplayer_t *)hplayer;
6631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6632 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6634 if (mm_player_set_attribute(hplayer, NULL,
6635 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6636 LOGE("failed to set attribute");
6637 result = MM_ERROR_PLAYER_INTERNAL;
6639 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6640 LOGE("failed to add the original uri in the uri list.");
6648 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6650 mmplayer_t *player = (mmplayer_t *)hplayer;
6651 guint num_of_list = 0;
6655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6656 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6658 if (player->pipeline && player->pipeline->textbin) {
6659 LOGE("subtitle path is enabled.");
6660 return MM_ERROR_PLAYER_INVALID_STATE;
6663 num_of_list = g_list_length(player->uri_info.uri_list);
6665 if (is_first_path) {
6666 if (num_of_list == 0) {
6667 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6668 SECURE_LOGD("add original path : %s", uri);
6670 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6671 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6673 SECURE_LOGD("change original path : %s", uri);
6676 MMHandleType attrs = 0;
6677 attrs = MMPLAYER_GET_ATTRS(player);
6679 if (num_of_list == 0) {
6680 char *original_uri = NULL;
6683 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6685 if (!original_uri) {
6686 LOGE("there is no original uri.");
6687 return MM_ERROR_PLAYER_INVALID_STATE;
6690 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6691 player->uri_info.uri_idx = 0;
6693 SECURE_LOGD("add original path at first : %s", original_uri);
6697 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6698 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6702 return MM_ERROR_NONE;
6706 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6708 mmplayer_t *player = (mmplayer_t *)hplayer;
6709 char *next_uri = NULL;
6710 guint num_of_list = 0;
6713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6715 num_of_list = g_list_length(player->uri_info.uri_list);
6717 if (num_of_list > 0) {
6718 gint uri_idx = player->uri_info.uri_idx;
6720 if (uri_idx < num_of_list-1)
6725 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6726 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6728 *uri = g_strdup(next_uri);
6732 return MM_ERROR_NONE;
6736 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6737 GstCaps *caps, gpointer data)
6739 mmplayer_t *player = (mmplayer_t *)data;
6740 const gchar *klass = NULL;
6741 const gchar *mime = NULL;
6742 gchar *caps_str = NULL;
6744 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6745 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6746 caps_str = gst_caps_to_string(caps);
6748 LOGW("unknown type of caps : %s from %s",
6749 caps_str, GST_ELEMENT_NAME(elem));
6751 MMPLAYER_FREEIF(caps_str);
6753 /* There is no available codec. */
6754 __mmplayer_check_not_supported_codec(player, klass, mime);
6758 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6759 GstCaps *caps, gpointer data)
6761 mmplayer_t *player = (mmplayer_t *)data;
6762 const char *mime = NULL;
6763 gboolean ret = TRUE;
6765 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6766 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6768 if (g_str_has_prefix(mime, "audio")) {
6769 GstStructure *caps_structure = NULL;
6770 gint samplerate = 0;
6772 gchar *caps_str = NULL;
6774 caps_structure = gst_caps_get_structure(caps, 0);
6775 gst_structure_get_int(caps_structure, "rate", &samplerate);
6776 gst_structure_get_int(caps_structure, "channels", &channels);
6778 if ((channels > 0 && samplerate == 0)) {
6779 LOGD("exclude audio...");
6783 caps_str = gst_caps_to_string(caps);
6784 /* set it directly because not sent by TAG */
6785 if (g_strrstr(caps_str, "mobile-xmf"))
6786 mm_player_set_attribute((MMHandleType)player, NULL,
6787 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6789 MMPLAYER_FREEIF(caps_str);
6790 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6791 LOGD("already video linked");
6794 LOGD("found new stream");
6801 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6803 gboolean ret = FALSE;
6804 GDBusConnection *conn = NULL;
6806 GVariant *result = NULL;
6807 const gchar *dbus_device_type = NULL;
6808 const gchar *dbus_ret = NULL;
6811 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6813 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6818 result = g_dbus_connection_call_sync(conn,
6819 "org.pulseaudio.Server",
6820 "/org/pulseaudio/StreamManager",
6821 "org.pulseaudio.StreamManager",
6822 "GetCurrentMediaRoutingPath",
6823 g_variant_new("(s)", "out"),
6824 G_VARIANT_TYPE("(ss)"),
6825 G_DBUS_CALL_FLAGS_NONE,
6829 if (!result || err) {
6830 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6835 /* device type is listed in stream-map.json at mmfw-sysconf */
6836 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6838 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6839 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6842 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6843 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6844 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6845 LOGD("audio offload is supportable");
6851 LOGD("audio offload is not supportable");
6854 g_variant_unref(result);
6856 g_object_unref(conn);
6861 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6863 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6864 gint64 position = 0;
6866 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6867 player->pipeline && player->pipeline->mainbin);
6869 MMPLAYER_CMD_LOCK(player);
6870 current_state = MMPLAYER_CURRENT_STATE(player);
6872 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6873 LOGW("getting current position failed in paused");
6875 _mmplayer_unrealize((MMHandleType)player);
6876 _mmplayer_realize((MMHandleType)player);
6878 _mmplayer_set_position((MMHandleType)player, position);
6880 /* async not to be blocked in streaming case */
6881 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6883 _mmplayer_pause((MMHandleType)player);
6885 if (current_state == MM_PLAYER_STATE_PLAYING)
6886 _mmplayer_start((MMHandleType)player);
6887 MMPLAYER_CMD_UNLOCK(player);
6889 LOGD("rebuilding audio pipeline is completed.");
6892 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6894 mmplayer_t *player = (mmplayer_t *)user_data;
6895 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6896 gboolean is_supportable = FALSE;
6898 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6899 LOGW("failed to get device type");
6901 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6903 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6904 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6905 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6906 LOGD("ignore this dev connected info");
6910 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6911 if (player->build_audio_offload == is_supportable) {
6912 LOGD("keep current pipeline without re-building");
6916 /* rebuild pipeline */
6917 LOGD("re-build pipeline - offload: %d", is_supportable);
6918 player->build_audio_offload = FALSE;
6919 __mmplayer_rebuild_audio_pipeline(player);
6925 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6927 unsigned int id = 0;
6929 if (player->audio_device_cb_id != 0) {
6930 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6934 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6935 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6936 LOGD("added device connected cb (%u)", id);
6937 player->audio_device_cb_id = id;
6939 LOGW("failed to add device connected cb");
6946 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6948 mmplayer_t *player = (mmplayer_t *)hplayer;
6951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6952 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6954 *activated = player->build_audio_offload;
6956 LOGD("offload activated : %d", (int)*activated);
6959 return MM_ERROR_NONE;
6963 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6966 this function need to be updated according to the supported media format
6967 @see player->ini.audio_offload_media_format */
6969 if (__mmplayer_is_only_mp3_type(player->type)) {
6970 LOGD("offload supportable media format type");
6978 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6980 gboolean ret = FALSE;
6981 GstElementFactory *factory = NULL;
6984 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6986 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6987 if (!__mmplayer_is_offload_supported_type(player))
6990 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6991 LOGD("there is no audio offload sink");
6995 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6996 LOGW("there is no audio device type to support offload");
7000 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7002 LOGW("there is no installed audio offload sink element");
7005 gst_object_unref(factory);
7007 if (__mmplayer_acquire_hw_resource(player,
7008 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7009 LOGE("failed to acquire audio offload decoder resource");
7013 if (!__mmplayer_add_audio_device_connected_cb(player))
7016 if (!__mmplayer_is_audio_offload_device_type(player))
7019 LOGD("audio offload can be built");
7024 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7030 static GstAutoplugSelectResult
7031 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7033 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7034 int audio_offload = 0;
7036 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7037 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7039 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7040 LOGD("expose audio path to build offload output path");
7041 player->build_audio_offload = TRUE;
7042 /* update codec info */
7043 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7044 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7045 player->audiodec_linked = 1;
7047 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7051 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7052 And need to consider the multi-track audio content.
7053 There is no HW audio decoder in public. */
7055 /* set stream information */
7056 if (!player->audiodec_linked)
7057 __mmplayer_set_audio_attrs(player, caps);
7059 /* update codec info */
7060 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7061 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7062 player->audiodec_linked = 1;
7064 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7066 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7067 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7069 /* mark video decoder for acquire */
7070 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7071 LOGW("video decoder resource is already acquired, skip it.");
7072 ret = GST_AUTOPLUG_SELECT_SKIP;
7076 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7077 LOGE("failed to acquire video decoder resource");
7078 ret = GST_AUTOPLUG_SELECT_SKIP;
7081 player->interrupted_by_resource = FALSE;
7084 /* update codec info */
7085 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7086 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7087 player->videodec_linked = 1;
7095 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7096 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7098 #define DEFAULT_IDX 0xFFFF
7099 #define MIN_FACTORY_NUM 2
7100 mmplayer_t *player = (mmplayer_t *)data;
7101 GValueArray *new_factories = NULL;
7102 GValue val = { 0, };
7103 GstElementFactory *factory = NULL;
7104 const gchar *klass = NULL;
7105 gchar *factory_name = NULL;
7106 guint hw_dec_idx = DEFAULT_IDX;
7107 guint first_sw_dec_idx = DEFAULT_IDX;
7108 guint last_sw_dec_idx = DEFAULT_IDX;
7109 guint new_pos = DEFAULT_IDX;
7110 guint rm_pos = DEFAULT_IDX;
7111 int audio_codec_type;
7112 int video_codec_type;
7113 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7115 if (factories->n_values < MIN_FACTORY_NUM)
7118 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7119 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7122 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7124 for (int i = 0 ; i < factories->n_values ; i++) {
7125 gchar *hw_dec_info = NULL;
7126 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7128 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7130 LOGW("failed to get factory object");
7133 klass = gst_element_factory_get_klass(factory);
7134 factory_name = GST_OBJECT_NAME(factory);
7137 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7139 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7140 if (!player->need_audio_dec_sorting) {
7141 LOGD("sorting is not required");
7144 codec_type = audio_codec_type;
7145 hw_dec_info = player->ini.audiocodec_element_hw;
7146 sw_dec_info = player->ini.audiocodec_element_sw;
7147 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7148 if (!player->need_video_dec_sorting) {
7149 LOGD("sorting is not required");
7152 codec_type = video_codec_type;
7153 hw_dec_info = player->ini.videocodec_element_hw;
7154 sw_dec_info = player->ini.videocodec_element_sw;
7159 if (g_strrstr(factory_name, hw_dec_info)) {
7162 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7163 if (strstr(factory_name, sw_dec_info[j])) {
7164 last_sw_dec_idx = i;
7165 if (first_sw_dec_idx == DEFAULT_IDX) {
7166 first_sw_dec_idx = i;
7171 if (first_sw_dec_idx == DEFAULT_IDX)
7172 LOGW("unknown codec %s", factory_name);
7176 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7179 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7180 if (hw_dec_idx < first_sw_dec_idx)
7182 new_pos = first_sw_dec_idx;
7183 rm_pos = hw_dec_idx + 1;
7184 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7185 if (last_sw_dec_idx < hw_dec_idx)
7187 new_pos = last_sw_dec_idx + 1;
7188 rm_pos = hw_dec_idx;
7193 /* change position - insert H/W decoder according to the new position */
7194 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7196 LOGW("failed to get factory object");
7199 new_factories = g_value_array_copy(factories);
7200 g_value_init (&val, G_TYPE_OBJECT);
7201 g_value_set_object (&val, factory);
7202 g_value_array_insert(new_factories, new_pos, &val);
7203 g_value_unset (&val);
7204 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7206 for (int i = 0 ; i < new_factories->n_values ; i++) {
7207 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7209 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7210 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7212 LOGE("[Re-arranged] failed to get factory object");
7215 return new_factories;
7219 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7220 GstCaps *caps, GstElementFactory *factory, gpointer data)
7222 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7223 mmplayer_t *player = (mmplayer_t *)data;
7225 gchar *factory_name = NULL;
7226 gchar *caps_str = NULL;
7227 const gchar *klass = NULL;
7230 factory_name = GST_OBJECT_NAME(factory);
7231 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7232 caps_str = gst_caps_to_string(caps);
7234 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7236 /* store type string */
7237 if (player->type == NULL) {
7238 player->type = gst_caps_to_string(caps);
7239 __mmplayer_update_content_type_info(player);
7242 /* filtering exclude keyword */
7243 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7244 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7245 LOGW("skipping [%s] by exculde keyword [%s]",
7246 factory_name, player->ini.exclude_element_keyword[idx]);
7248 result = GST_AUTOPLUG_SELECT_SKIP;
7253 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7254 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7255 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7256 factory_name, player->ini.unsupported_codec_keyword[idx]);
7257 result = GST_AUTOPLUG_SELECT_SKIP;
7262 /* exclude webm format */
7263 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7264 * because webm format is not supportable.
7265 * If webm is disabled in "autoplug-continue", there is no state change
7266 * failure or error because the decodebin will expose the pad directly.
7267 * It make MSL invoke _prepare_async_callback.
7268 * So, we need to disable webm format in "autoplug-select" */
7269 if (caps_str && strstr(caps_str, "webm")) {
7270 LOGW("webm is not supported");
7271 result = GST_AUTOPLUG_SELECT_SKIP;
7275 /* check factory class for filtering */
7276 /* NOTE : msl don't need to use image plugins.
7277 * So, those plugins should be skipped for error handling.
7279 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7280 LOGD("skipping [%s] by not required", factory_name);
7281 result = GST_AUTOPLUG_SELECT_SKIP;
7285 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7286 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7287 // TO CHECK : subtitle if needed, add subparse exception.
7288 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7289 result = GST_AUTOPLUG_SELECT_SKIP;
7293 if (g_strrstr(factory_name, "mpegpsdemux")) {
7294 LOGD("skipping PS container - not support");
7295 result = GST_AUTOPLUG_SELECT_SKIP;
7299 if (g_strrstr(factory_name, "mssdemux"))
7300 player->smooth_streaming = TRUE;
7302 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7303 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7306 GstStructure *str = NULL;
7307 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7309 /* don't make video because of not required */
7310 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7311 (!player->set_mode.video_export)) {
7312 LOGD("no need video decoding, expose pad");
7313 result = GST_AUTOPLUG_SELECT_EXPOSE;
7317 /* get w/h for omx state-tune */
7318 /* FIXME: deprecated? */
7319 str = gst_caps_get_structure(caps, 0);
7320 gst_structure_get_int(str, "width", &width);
7323 if (player->v_stream_caps) {
7324 gst_caps_unref(player->v_stream_caps);
7325 player->v_stream_caps = NULL;
7328 player->v_stream_caps = gst_caps_copy(caps);
7329 LOGD("take caps for video state tune");
7330 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7334 if (g_strrstr(klass, "Codec/Decoder")) {
7335 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7336 if (result != GST_AUTOPLUG_SELECT_TRY) {
7337 LOGW("skip add decoder");
7343 MMPLAYER_FREEIF(caps_str);
7349 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7352 //mmplayer_t *player = (mmplayer_t *)data;
7353 GstCaps *caps = NULL;
7355 LOGD("[Decodebin2] pad-removed signal");
7357 caps = gst_pad_query_caps(new_pad, NULL);
7359 LOGW("query caps is NULL");
7363 gchar *caps_str = NULL;
7364 caps_str = gst_caps_to_string(caps);
7366 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7368 MMPLAYER_FREEIF(caps_str);
7369 gst_caps_unref(caps);
7373 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7375 mmplayer_t *player = (mmplayer_t *)data;
7376 GstIterator *iter = NULL;
7377 GValue item = { 0, };
7379 gboolean done = FALSE;
7380 gboolean is_all_drained = TRUE;
7383 MMPLAYER_RETURN_IF_FAIL(player);
7385 LOGD("__mmplayer_gst_decode_drained");
7387 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7388 LOGW("Fail to get cmd lock");
7392 if (!__mmplayer_verify_gapless_play_path(player)) {
7393 LOGD("decoding is finished.");
7394 MMPLAYER_CMD_UNLOCK(player);
7398 _mmplayer_set_reconfigure_state(player, TRUE);
7399 MMPLAYER_CMD_UNLOCK(player);
7401 /* check decodebin src pads whether they received EOS or not */
7402 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7405 switch (gst_iterator_next(iter, &item)) {
7406 case GST_ITERATOR_OK:
7407 pad = g_value_get_object(&item);
7408 if (pad && !GST_PAD_IS_EOS(pad)) {
7409 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7410 is_all_drained = FALSE;
7413 g_value_reset(&item);
7415 case GST_ITERATOR_RESYNC:
7416 gst_iterator_resync(iter);
7418 case GST_ITERATOR_ERROR:
7419 case GST_ITERATOR_DONE:
7424 g_value_unset(&item);
7425 gst_iterator_free(iter);
7427 if (!is_all_drained) {
7428 LOGD("Wait util the all pads get EOS.");
7433 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7434 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7436 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7437 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7438 __mmplayer_deactivate_old_path(player);
7444 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7446 mmplayer_t *player = (mmplayer_t *)data;
7447 const gchar *klass = NULL;
7448 gchar *factory_name = NULL;
7450 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7451 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7453 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7455 if (__mmplayer_add_dump_buffer_probe(player, element))
7456 LOGD("add buffer probe");
7458 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7459 gchar *selected = NULL;
7460 selected = g_strdup(GST_ELEMENT_NAME(element));
7461 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7464 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7465 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7466 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7468 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7469 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7471 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7472 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7473 "max-video-width", player->adaptive_info.limit.width,
7474 "max-video-height", player->adaptive_info.limit.height, NULL);
7476 } else if (g_strrstr(klass, "Demuxer")) {
7478 LOGD("plugged element is demuxer. take it");
7480 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7481 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7484 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7485 int surface_type = 0;
7487 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7490 // to support trust-zone only
7491 if (g_strrstr(factory_name, "asfdemux")) {
7492 LOGD("set file-location %s", player->profile.uri);
7493 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7494 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7495 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7496 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7497 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7498 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7499 (__mmplayer_is_only_mp3_type(player->type))) {
7500 LOGD("[mpegaudioparse] set streaming pull mode.");
7501 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7503 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7504 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7507 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7508 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7509 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7511 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7512 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7514 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7515 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7516 (MMPLAYER_IS_DASH_STREAMING(player))) {
7517 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7518 _mm_player_streaming_set_multiqueue(player->streamer, element);
7519 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7528 __mmplayer_release_misc(mmplayer_t *player)
7531 bool cur_mode = player->set_mode.rich_audio;
7534 MMPLAYER_RETURN_IF_FAIL(player);
7536 player->sent_bos = FALSE;
7537 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7539 player->seek_state = MMPLAYER_SEEK_NONE;
7541 player->total_bitrate = 0;
7542 player->total_maximum_bitrate = 0;
7544 player->not_found_demuxer = 0;
7546 player->last_position = 0;
7547 player->duration = 0;
7548 player->http_content_size = 0;
7549 player->not_supported_codec = MISSING_PLUGIN_NONE;
7550 player->can_support_codec = FOUND_PLUGIN_NONE;
7551 player->pending_seek.is_pending = false;
7552 player->pending_seek.pos = 0;
7553 player->msg_posted = FALSE;
7554 player->has_many_types = FALSE;
7555 player->is_subtitle_force_drop = FALSE;
7556 player->play_subtitle = FALSE;
7557 player->adjust_subtitle_pos = 0;
7558 player->has_closed_caption = FALSE;
7559 player->set_mode.video_export = false;
7560 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7561 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7563 player->set_mode.rich_audio = cur_mode;
7565 if (player->audio_device_cb_id > 0 &&
7566 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7567 LOGW("failed to remove audio device_connected_callback");
7568 player->audio_device_cb_id = 0;
7570 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7571 player->bitrate[i] = 0;
7572 player->maximum_bitrate[i] = 0;
7575 /* free memory related to audio effect */
7576 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7578 if (player->adaptive_info.var_list) {
7579 g_list_free_full(player->adaptive_info.var_list, g_free);
7580 player->adaptive_info.var_list = NULL;
7583 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7584 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7585 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7587 /* Reset video360 settings to their defaults in case if the pipeline is to be
7590 player->video360_metadata.is_spherical = -1;
7591 player->is_openal_plugin_used = FALSE;
7593 player->is_content_spherical = FALSE;
7594 player->is_video360_enabled = TRUE;
7595 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7596 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7597 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7598 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7599 player->video360_zoom = 1.0f;
7600 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7601 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7603 player->sound.rg_enable = false;
7605 __mmplayer_initialize_video_roi(player);
7610 __mmplayer_release_misc_post(mmplayer_t *player)
7612 char *original_uri = NULL;
7615 /* player->pipeline is already released before. */
7616 MMPLAYER_RETURN_IF_FAIL(player);
7618 player->video_decoded_cb = NULL;
7619 player->video_decoded_cb_user_param = NULL;
7620 player->video_stream_prerolled = false;
7622 player->audio_decoded_cb = NULL;
7623 player->audio_decoded_cb_user_param = NULL;
7624 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7626 player->audio_stream_changed_cb = NULL;
7627 player->audio_stream_changed_cb_user_param = NULL;
7629 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7631 /* clean found audio decoders */
7632 if (player->audio_decoders) {
7633 GList *a_dec = player->audio_decoders;
7634 for (; a_dec; a_dec = g_list_next(a_dec)) {
7635 gchar *name = a_dec->data;
7636 MMPLAYER_FREEIF(name);
7638 g_list_free(player->audio_decoders);
7639 player->audio_decoders = NULL;
7642 /* clean the uri list except original uri */
7643 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7644 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7646 LOGW("failed to get original uri info");
7648 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7649 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7651 GList *uri_list = player->uri_info.uri_list;
7652 for (; uri_list; uri_list = g_list_next(uri_list)) {
7653 gchar *uri = uri_list->data;
7654 if (original_uri != uri)
7655 MMPLAYER_FREEIF(uri);
7659 /* clear the audio stream buffer list */
7660 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7662 /* clear the video stream bo list */
7663 __mmplayer_video_stream_destroy_bo_list(player);
7664 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7666 if (player->profile.input_mem.buf) {
7667 free(player->profile.input_mem.buf);
7668 player->profile.input_mem.buf = NULL;
7670 player->profile.input_mem.len = 0;
7671 player->profile.input_mem.offset = 0;
7673 player->uri_info.uri_idx = 0;
7678 __mmplayer_check_subtitle(mmplayer_t *player)
7680 MMHandleType attrs = 0;
7681 char *subtitle_uri = NULL;
7685 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7687 /* get subtitle attribute */
7688 attrs = MMPLAYER_GET_ATTRS(player);
7692 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7693 if (!subtitle_uri || !strlen(subtitle_uri))
7696 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7697 player->is_external_subtitle_present = TRUE;
7705 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7707 MMPLAYER_RETURN_IF_FAIL(player);
7709 if (player->eos_timer) {
7710 LOGD("cancel eos timer");
7711 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7712 player->eos_timer = 0;
7719 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7723 MMPLAYER_RETURN_IF_FAIL(player);
7724 MMPLAYER_RETURN_IF_FAIL(sink);
7726 player->sink_elements = g_list_append(player->sink_elements, sink);
7732 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7736 MMPLAYER_RETURN_IF_FAIL(player);
7737 MMPLAYER_RETURN_IF_FAIL(sink);
7739 player->sink_elements = g_list_remove(player->sink_elements, sink);
7745 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7746 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7748 mmplayer_signal_item_t *item = NULL;
7751 MMPLAYER_RETURN_IF_FAIL(player);
7753 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7754 LOGE("invalid signal type [%d]", type);
7758 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7760 LOGE("cannot connect signal [%s]", signal);
7765 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7766 player->signals[type] = g_list_append(player->signals[type], item);
7772 /* NOTE : be careful with calling this api. please refer to below glib comment
7773 * glib comment : Note that there is a bug in GObject that makes this function much
7774 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7775 * will no longer be called, but, the signal handler is not currently disconnected.
7776 * If the instance is itself being freed at the same time than this doesn't matter,
7777 * since the signal will automatically be removed, but if instance persists,
7778 * then the signal handler will leak. You should not remove the signal yourself
7779 * because in a future versions of GObject, the handler will automatically be
7782 * It's possible to work around this problem in a way that will continue to work
7783 * with future versions of GObject by checking that the signal handler is still
7784 * connected before disconnected it:
7786 * if (g_signal_handler_is_connected(instance, id))
7787 * g_signal_handler_disconnect(instance, id);
7790 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7792 GList *sig_list = NULL;
7793 mmplayer_signal_item_t *item = NULL;
7797 MMPLAYER_RETURN_IF_FAIL(player);
7799 LOGD("release signals type : %d", type);
7801 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7802 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7803 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7804 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7805 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7806 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7810 sig_list = player->signals[type];
7812 for (; sig_list; sig_list = sig_list->next) {
7813 item = sig_list->data;
7815 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7816 if (g_signal_handler_is_connected(item->obj, item->sig))
7817 g_signal_handler_disconnect(item->obj, item->sig);
7820 MMPLAYER_FREEIF(item);
7823 g_list_free(player->signals[type]);
7824 player->signals[type] = NULL;
7832 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7834 mmplayer_t *player = 0;
7835 int prev_display_surface_type = 0;
7839 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7841 player = MM_PLAYER_CAST(handle);
7843 /* check video sinkbin is created */
7844 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7845 LOGW("Videosink is already created");
7846 return MM_ERROR_NONE;
7849 LOGD("videosink element is not yet ready");
7851 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7852 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7854 return MM_ERROR_INVALID_ARGUMENT;
7857 /* load previous attributes */
7858 if (player->attrs) {
7859 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7860 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7861 if (prev_display_surface_type == surface_type) {
7862 LOGD("incoming display surface type is same as previous one, do nothing..");
7864 return MM_ERROR_NONE;
7867 LOGE("failed to load attributes");
7869 return MM_ERROR_PLAYER_INTERNAL;
7872 /* videobin is not created yet, so we just set attributes related to display surface */
7873 LOGD("store display attribute for given surface type(%d)", surface_type);
7874 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7875 "display_overlay", wl_surface_id, NULL);
7878 return MM_ERROR_NONE;
7881 /* Note : if silent is true, then subtitle would not be displayed. :*/
7883 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7885 mmplayer_t *player = (mmplayer_t *)hplayer;
7889 /* check player handle */
7890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7892 player->set_mode.subtitle_off = silent;
7894 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7898 return MM_ERROR_NONE;
7902 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7904 mmplayer_gst_element_t *mainbin = NULL;
7905 mmplayer_gst_element_t *textbin = NULL;
7906 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7907 GstState current_state = GST_STATE_VOID_PENDING;
7908 GstState element_state = GST_STATE_VOID_PENDING;
7909 GstState element_pending_state = GST_STATE_VOID_PENDING;
7911 GstEvent *event = NULL;
7912 int result = MM_ERROR_NONE;
7914 GstClock *curr_clock = NULL;
7915 GstClockTime base_time, start_time, curr_time;
7920 /* check player handle */
7921 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7923 player->pipeline->mainbin &&
7924 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7926 mainbin = player->pipeline->mainbin;
7927 textbin = player->pipeline->textbin;
7929 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7931 // sync clock with current pipeline
7932 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7933 curr_time = gst_clock_get_time(curr_clock);
7935 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7936 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7938 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7939 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7941 if (current_state > GST_STATE_READY) {
7942 // sync state with current pipeline
7943 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7944 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7945 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7947 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7948 if (GST_STATE_CHANGE_FAILURE == ret) {
7949 LOGE("fail to state change.");
7950 result = MM_ERROR_PLAYER_INTERNAL;
7954 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7955 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7958 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7959 gst_object_unref(curr_clock);
7962 // seek to current position
7963 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7964 result = MM_ERROR_PLAYER_INVALID_STATE;
7965 LOGE("gst_element_query_position failed, invalid state");
7969 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7970 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);
7972 _mmplayer_gst_send_event_to_sink(player, event);
7974 result = MM_ERROR_PLAYER_INTERNAL;
7975 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7979 /* sync state with current pipeline */
7980 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7981 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7982 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7984 return MM_ERROR_NONE;
7987 /* release text pipeline resource */
7988 player->textsink_linked = 0;
7990 /* release signal */
7991 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7993 /* release textbin with it's childs */
7994 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7995 MMPLAYER_FREEIF(player->pipeline->textbin);
7996 player->pipeline->textbin = NULL;
7998 /* release subtitle elem */
7999 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8000 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8006 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8008 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8009 GstState current_state = GST_STATE_VOID_PENDING;
8011 MMHandleType attrs = 0;
8012 mmplayer_gst_element_t *mainbin = NULL;
8013 mmplayer_gst_element_t *textbin = NULL;
8015 gchar *subtitle_uri = NULL;
8016 int result = MM_ERROR_NONE;
8017 const gchar *charset = NULL;
8021 /* check player handle */
8022 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8024 player->pipeline->mainbin &&
8025 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8026 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8028 mainbin = player->pipeline->mainbin;
8029 textbin = player->pipeline->textbin;
8031 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8032 if (current_state < GST_STATE_READY) {
8033 result = MM_ERROR_PLAYER_INVALID_STATE;
8034 LOGE("Pipeline is not in proper state");
8038 attrs = MMPLAYER_GET_ATTRS(player);
8040 LOGE("cannot get content attribute");
8041 result = MM_ERROR_PLAYER_INTERNAL;
8045 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8046 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8047 LOGE("subtitle uri is not proper filepath");
8048 result = MM_ERROR_PLAYER_INVALID_URI;
8052 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8053 LOGE("failed to get storage info of subtitle path");
8054 result = MM_ERROR_PLAYER_INVALID_URI;
8058 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8059 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8061 if (!strcmp(filepath, subtitle_uri)) {
8062 LOGD("subtitle path is not changed");
8065 if (mm_player_set_attribute((MMHandleType)player, NULL,
8066 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8067 LOGE("failed to set attribute");
8072 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8073 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8074 player->subtitle_language_list = NULL;
8075 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8077 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8078 if (ret != GST_STATE_CHANGE_SUCCESS) {
8079 LOGE("failed to change state of textbin to READY");
8080 result = MM_ERROR_PLAYER_INTERNAL;
8084 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8085 if (ret != GST_STATE_CHANGE_SUCCESS) {
8086 LOGE("failed to change state of subparse to READY");
8087 result = MM_ERROR_PLAYER_INTERNAL;
8091 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8092 if (ret != GST_STATE_CHANGE_SUCCESS) {
8093 LOGE("failed to change state of filesrc to READY");
8094 result = MM_ERROR_PLAYER_INTERNAL;
8098 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8100 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8102 charset = _mmplayer_get_charset(filepath);
8104 LOGD("detected charset is %s", charset);
8105 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8108 result = _mmplayer_sync_subtitle_pipeline(player);
8115 /* API to switch between external subtitles */
8117 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8119 int result = MM_ERROR_NONE;
8120 mmplayer_t *player = (mmplayer_t *)hplayer;
8125 /* check player handle */
8126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8128 /* filepath can be null in idle state */
8130 /* check file path */
8131 if ((path = strstr(filepath, "file://")))
8132 result = _mmplayer_exist_file_path(path + 7);
8134 result = _mmplayer_exist_file_path(filepath);
8136 if (result != MM_ERROR_NONE) {
8137 LOGE("invalid subtitle path 0x%X", result);
8138 return result; /* file not found or permission denied */
8142 if (!player->pipeline) {
8144 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8145 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8146 LOGE("failed to set attribute");
8147 return MM_ERROR_PLAYER_INTERNAL;
8150 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8151 /* check filepath */
8152 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8154 if (!__mmplayer_check_subtitle(player)) {
8155 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8156 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8157 LOGE("failed to set attribute");
8158 return MM_ERROR_PLAYER_INTERNAL;
8161 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8162 LOGE("fail to create text pipeline");
8163 return MM_ERROR_PLAYER_INTERNAL;
8166 result = _mmplayer_sync_subtitle_pipeline(player);
8168 result = __mmplayer_change_external_subtitle_language(player, filepath);
8171 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8172 player->is_external_subtitle_added_now = TRUE;
8174 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8175 if (!player->subtitle_language_list) {
8176 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8177 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8178 LOGW("subtitle language list is not updated yet");
8180 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8188 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8190 int result = MM_ERROR_NONE;
8191 gchar *change_pad_name = NULL;
8192 GstPad *sinkpad = NULL;
8193 mmplayer_gst_element_t *mainbin = NULL;
8194 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8195 GstCaps *caps = NULL;
8196 gint total_track_num = 0;
8200 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8201 MM_ERROR_PLAYER_NOT_INITIALIZED);
8203 LOGD("Change Track(%d) to %d", type, index);
8205 mainbin = player->pipeline->mainbin;
8207 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8208 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8209 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8210 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8212 /* Changing Video Track is not supported. */
8213 LOGE("Track Type Error");
8217 if (mainbin[elem_idx].gst == NULL) {
8218 result = MM_ERROR_PLAYER_NO_OP;
8219 LOGD("Req track doesn't exist");
8223 total_track_num = player->selector[type].total_track_num;
8224 if (total_track_num <= 0) {
8225 result = MM_ERROR_PLAYER_NO_OP;
8226 LOGD("Language list is not available");
8230 if ((index < 0) || (index >= total_track_num)) {
8231 result = MM_ERROR_INVALID_ARGUMENT;
8232 LOGD("Not a proper index : %d", index);
8236 /*To get the new pad from the selector*/
8237 change_pad_name = g_strdup_printf("sink_%u", index);
8238 if (change_pad_name == NULL) {
8239 result = MM_ERROR_PLAYER_INTERNAL;
8240 LOGD("Pad does not exists");
8244 LOGD("new active pad name: %s", change_pad_name);
8246 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8247 if (sinkpad == NULL) {
8248 LOGD("sinkpad is NULL");
8249 result = MM_ERROR_PLAYER_INTERNAL;
8253 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8254 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8256 caps = gst_pad_get_current_caps(sinkpad);
8257 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8260 gst_object_unref(sinkpad);
8262 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8263 __mmplayer_set_audio_attrs(player, caps);
8266 MMPLAYER_FREEIF(change_pad_name);
8271 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8273 int result = MM_ERROR_NONE;
8274 mmplayer_t *player = NULL;
8275 mmplayer_gst_element_t *mainbin = NULL;
8277 gint current_active_index = 0;
8279 GstState current_state = GST_STATE_VOID_PENDING;
8280 GstEvent *event = NULL;
8285 player = (mmplayer_t *)hplayer;
8286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8288 if (!player->pipeline) {
8289 LOGE("Track %d pre setting -> %d", type, index);
8291 player->selector[type].active_pad_index = index;
8295 mainbin = player->pipeline->mainbin;
8297 current_active_index = player->selector[type].active_pad_index;
8299 /*If index is same as running index no need to change the pad*/
8300 if (current_active_index == index)
8303 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8304 result = MM_ERROR_PLAYER_INVALID_STATE;
8308 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8309 if (current_state < GST_STATE_PAUSED) {
8310 result = MM_ERROR_PLAYER_INVALID_STATE;
8311 LOGW("Pipeline not in porper state");
8315 result = __mmplayer_change_selector_pad(player, type, index);
8316 if (result != MM_ERROR_NONE) {
8317 LOGE("change selector pad error");
8321 player->selector[type].active_pad_index = index;
8323 if (current_state == GST_STATE_PLAYING) {
8324 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8325 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8326 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8328 _mmplayer_gst_send_event_to_sink(player, event);
8330 result = MM_ERROR_PLAYER_INTERNAL;
8340 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8342 mmplayer_t *player = (mmplayer_t *)hplayer;
8346 /* check player handle */
8347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8349 *silent = player->set_mode.subtitle_off;
8351 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8355 return MM_ERROR_NONE;
8359 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8361 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8362 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8364 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8365 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8369 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8370 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8371 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8372 mmplayer_dump_t *dump_s;
8373 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8374 if (dump_s == NULL) {
8375 LOGE("malloc fail");
8379 dump_s->dump_element_file = NULL;
8380 dump_s->dump_pad = NULL;
8381 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8383 if (dump_s->dump_pad) {
8384 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8385 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]);
8386 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8387 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);
8388 /* add list for removed buffer probe and close FILE */
8389 player->dump_list = g_list_append(player->dump_list, dump_s);
8390 LOGD("%s sink pad added buffer probe for dump", factory_name);
8393 MMPLAYER_FREEIF(dump_s);
8394 LOGE("failed to get %s sink pad added", factory_name);
8401 static GstPadProbeReturn
8402 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8404 FILE *dump_data = (FILE *)u_data;
8406 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8407 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8409 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8411 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8413 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8415 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8417 gst_buffer_unmap(buffer, &probe_info);
8419 return GST_PAD_PROBE_OK;
8423 __mmplayer_release_dump_list(GList *dump_list)
8425 GList *d_list = dump_list;
8430 for (; d_list; d_list = g_list_next(d_list)) {
8431 mmplayer_dump_t *dump_s = d_list->data;
8432 if (dump_s->dump_pad) {
8433 if (dump_s->probe_handle_id)
8434 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8435 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8437 if (dump_s->dump_element_file) {
8438 fclose(dump_s->dump_element_file);
8439 dump_s->dump_element_file = NULL;
8441 MMPLAYER_FREEIF(dump_s);
8443 g_list_free(dump_list);
8448 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8450 mmplayer_t *player = (mmplayer_t *)hplayer;
8454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8455 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8457 *exist = (bool)player->has_closed_caption;
8461 return MM_ERROR_NONE;
8465 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8470 LOGD("unref internal gst buffer %p", buffer);
8472 gst_buffer_unref((GstBuffer *)buffer);
8479 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8481 mmplayer_t *player = (mmplayer_t *)hplayer;
8485 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8486 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8488 if (MMPLAYER_IS_STREAMING(player))
8489 *timeout = (int)player->ini.live_state_change_timeout;
8491 *timeout = (int)player->ini.localplayback_state_change_timeout;
8493 LOGD("timeout = %d", *timeout);
8496 return MM_ERROR_NONE;
8500 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8504 MMPLAYER_RETURN_IF_FAIL(player);
8506 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8508 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8509 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8510 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8511 player->storage_info[i].id = -1;
8512 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8514 if (path_type != MMPLAYER_PATH_MAX)
8523 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8525 int ret = MM_ERROR_NONE;
8526 mmplayer_t *player = (mmplayer_t *)hplayer;
8527 MMMessageParamType msg_param = {0, };
8530 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8532 LOGW("state changed storage %d:%d", id, state);
8534 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8535 return MM_ERROR_NONE;
8537 /* FIXME: text path should be handled seperately. */
8538 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8539 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8540 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8541 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8542 LOGW("external storage is removed");
8544 if (player->msg_posted == FALSE) {
8545 memset(&msg_param, 0, sizeof(MMMessageParamType));
8546 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8547 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8548 player->msg_posted = TRUE;
8551 /* unrealize the player */
8552 ret = _mmplayer_unrealize(hplayer);
8553 if (ret != MM_ERROR_NONE)
8554 LOGE("failed to unrealize");
8562 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8564 int ret = MM_ERROR_NONE;
8565 mmplayer_t *player = (mmplayer_t *)hplayer;
8566 int idx = 0, total = 0;
8567 gchar *result = NULL, *tmp = NULL;
8570 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8571 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8573 total = *num = g_list_length(player->adaptive_info.var_list);
8575 LOGW("There is no stream variant info.");
8579 result = g_strdup("");
8580 for (idx = 0 ; idx < total ; idx++) {
8581 stream_variant_t *v_data = NULL;
8582 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8585 gchar data[64] = {0};
8586 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8588 tmp = g_strconcat(result, data, NULL);
8592 LOGW("There is no variant data in %d", idx);
8597 *var_info = (char *)result;
8599 LOGD("variant info %d:%s", *num, *var_info);
8605 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8607 int ret = MM_ERROR_NONE;
8608 mmplayer_t *player = (mmplayer_t *)hplayer;
8611 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8613 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8615 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8616 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8617 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8619 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8620 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8621 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8622 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8624 /* FIXME: seek to current position for applying new variant limitation */
8633 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8635 int ret = MM_ERROR_NONE;
8636 mmplayer_t *player = (mmplayer_t *)hplayer;
8639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8640 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8642 *bandwidth = player->adaptive_info.limit.bandwidth;
8643 *width = player->adaptive_info.limit.width;
8644 *height = player->adaptive_info.limit.height;
8646 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8653 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8655 int ret = MM_ERROR_NONE;
8656 mmplayer_t *player = (mmplayer_t *)hplayer;
8659 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8660 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8661 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8663 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8665 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8666 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8667 else /* live case */
8668 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8670 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8677 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8679 #define IDX_FIRST_SW_CODEC 0
8680 mmplayer_t *player = (mmplayer_t *)hplayer;
8681 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8684 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8686 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8687 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8688 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8690 switch (stream_type) {
8691 case MM_PLAYER_STREAM_TYPE_AUDIO:
8692 /* to support audio codec selection, codec info have to be added in ini file as below.
8693 audio codec element hw = xxxx
8694 audio codec element sw = avdec
8695 and in case of audio hw codec is supported and selected,
8696 audio filter elements should be applied depending on the hw capabilities.
8698 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8699 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8700 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8701 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8702 LOGE("There is no audio codec info for codec_type %d", codec_type);
8703 return MM_ERROR_PLAYER_NO_OP;
8706 case MM_PLAYER_STREAM_TYPE_VIDEO:
8707 /* to support video codec selection, codec info have to be added in ini file as below.
8708 video codec element hw = omx
8709 video codec element sw = avdec */
8710 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8711 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8712 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8713 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8714 LOGE("There is no video codec info for codec_type %d", codec_type);
8715 return MM_ERROR_PLAYER_NO_OP;
8719 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8720 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8724 LOGD("update %s codec_type to %d", attr_name, codec_type);
8725 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8728 return MM_ERROR_NONE;
8732 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8734 mmplayer_t *player = (mmplayer_t *)hplayer;
8735 GstElement *rg_vol_element = NULL;
8739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8741 player->sound.rg_enable = enabled;
8743 /* just hold rgvolume enable value if pipeline is not ready */
8744 if (!player->pipeline || !player->pipeline->audiobin) {
8745 LOGD("pipeline is not ready. holding rgvolume enable value");
8746 return MM_ERROR_NONE;
8749 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8751 if (!rg_vol_element) {
8752 LOGD("rgvolume element is not created");
8753 return MM_ERROR_PLAYER_INTERNAL;
8757 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8759 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8763 return MM_ERROR_NONE;
8767 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8769 mmplayer_t *player = (mmplayer_t *)hplayer;
8770 GstElement *rg_vol_element = NULL;
8771 gboolean enable = FALSE;
8775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8776 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8778 /* just hold enable_rg value if pipeline is not ready */
8779 if (!player->pipeline || !player->pipeline->audiobin) {
8780 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8781 *enabled = player->sound.rg_enable;
8782 return MM_ERROR_NONE;
8785 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8787 if (!rg_vol_element) {
8788 LOGD("rgvolume element is not created");
8789 return MM_ERROR_PLAYER_INTERNAL;
8792 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8793 *enabled = (bool)enable;
8797 return MM_ERROR_NONE;
8801 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8803 mmplayer_t *player = (mmplayer_t *)hplayer;
8804 MMHandleType attrs = 0;
8806 int ret = MM_ERROR_NONE;
8810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8812 attrs = MMPLAYER_GET_ATTRS(player);
8813 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8815 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8817 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8818 return MM_ERROR_PLAYER_INTERNAL;
8821 player->video_roi.scale_x = scale_x;
8822 player->video_roi.scale_y = scale_y;
8823 player->video_roi.scale_width = scale_width;
8824 player->video_roi.scale_height = scale_height;
8826 /* check video sinkbin is created */
8827 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8828 return MM_ERROR_NONE;
8830 if (!gst_video_overlay_set_video_roi_area(
8831 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8832 scale_x, scale_y, scale_width, scale_height))
8833 ret = MM_ERROR_PLAYER_INTERNAL;
8835 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8836 scale_x, scale_y, scale_width, scale_height);
8844 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8846 mmplayer_t *player = (mmplayer_t *)hplayer;
8847 int ret = MM_ERROR_NONE;
8851 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8852 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8854 *scale_x = player->video_roi.scale_x;
8855 *scale_y = player->video_roi.scale_y;
8856 *scale_width = player->video_roi.scale_width;
8857 *scale_height = player->video_roi.scale_height;
8859 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8860 *scale_x, *scale_y, *scale_width, *scale_height);
8866 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8868 mmplayer_t *player = (mmplayer_t *)hplayer;
8872 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8874 player->client_pid = pid;
8876 LOGD("client pid[%d] %p", pid, player);
8880 return MM_ERROR_NONE;
8884 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8886 mmplayer_t *player = (mmplayer_t *)hplayer;
8887 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8888 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8892 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8893 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8896 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8898 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8900 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8901 return MM_ERROR_NONE;
8903 /* in case of audio codec default type is HW */
8905 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8906 if (player->ini.support_audio_effect)
8907 return MM_ERROR_NONE;
8908 elem_id = MMPLAYER_A_FILTER;
8910 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8911 if (player->ini.support_replaygain_control)
8912 return MM_ERROR_NONE;
8913 elem_id = MMPLAYER_A_RGVOL;
8915 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8916 if (player->ini.support_pitch_control)
8917 return MM_ERROR_NONE;
8918 elem_id = MMPLAYER_A_PITCH;
8920 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8921 if (player->ini.support_audio_effect)
8922 return MM_ERROR_NONE;
8924 /* default case handling is not required */
8927 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8928 LOGW("audio control option [%d] is not available", opt);
8931 /* setting pcm exporting option is allowed before READY state */
8932 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8933 return MM_ERROR_PLAYER_INVALID_STATE;
8935 /* check whether the audio filter exist or not after READY state,
8936 because the sw codec could be added during auto-plugging in some cases */
8937 if (!player->pipeline ||
8938 !player->pipeline->audiobin ||
8939 !player->pipeline->audiobin[elem_id].gst) {
8940 LOGW("there is no audio elem [%d]", elem_id);
8945 LOGD("audio control opt %d, available %d", opt, *available);
8949 return MM_ERROR_NONE;
8953 __mmplayer_update_duration_value(mmplayer_t *player)
8955 gboolean ret = FALSE;
8956 gint64 dur_nsec = 0;
8957 LOGD("try to update duration");
8959 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8960 player->duration = dur_nsec;
8961 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8965 if (player->duration < 0) {
8966 LOGW("duration is Non-Initialized !!!");
8967 player->duration = 0;
8970 /* update streaming service type */
8971 player->streaming_type = _mmplayer_get_stream_service_type(player);
8973 /* check duration is OK */
8974 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8975 /* FIXIT : find another way to get duration here. */
8976 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8982 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8984 /* update audio params
8985 NOTE : We need original audio params and it can be only obtained from src pad of audio
8986 decoder. Below code only valid when we are not using 'resampler' just before
8987 'audioconverter'. */
8988 GstCaps *caps_a = NULL;
8990 gint samplerate = 0, channels = 0;
8991 GstStructure *p = NULL;
8992 GstElement *aconv = NULL;
8994 LOGD("try to update audio attrs");
8996 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8998 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8999 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9000 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9001 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9003 LOGE("there is no audio converter");
9007 pad = gst_element_get_static_pad(aconv, "sink");
9010 LOGW("failed to get pad from audio converter");
9014 caps_a = gst_pad_get_current_caps(pad);
9016 LOGW("not ready to get audio caps");
9017 gst_object_unref(pad);
9021 p = gst_caps_get_structure(caps_a, 0);
9023 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9025 gst_structure_get_int(p, "rate", &samplerate);
9026 gst_structure_get_int(p, "channels", &channels);
9028 mm_player_set_attribute((MMHandleType)player, NULL,
9029 "content_audio_samplerate", samplerate,
9030 "content_audio_channels", channels, NULL);
9032 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9034 gst_caps_unref(caps_a);
9035 gst_object_unref(pad);
9041 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9043 LOGD("try to update video attrs");
9045 GstCaps *caps_v = NULL;
9049 GstStructure *p = NULL;
9051 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9052 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9054 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9056 LOGD("no videosink sink pad");
9060 caps_v = gst_pad_get_current_caps(pad);
9061 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9062 if (!caps_v && player->v_stream_caps) {
9063 caps_v = player->v_stream_caps;
9064 gst_caps_ref(caps_v);
9068 LOGD("no negitiated caps from videosink");
9069 gst_object_unref(pad);
9073 p = gst_caps_get_structure(caps_v, 0);
9074 gst_structure_get_int(p, "width", &width);
9075 gst_structure_get_int(p, "height", &height);
9077 mm_player_set_attribute((MMHandleType)player, NULL,
9078 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9080 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9082 SECURE_LOGD("width : %d height : %d", width, height);
9084 gst_caps_unref(caps_v);
9085 gst_object_unref(pad);
9088 mm_player_set_attribute((MMHandleType)player, NULL,
9089 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9090 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9097 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9099 gboolean ret = FALSE;
9100 guint64 data_size = 0;
9104 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9105 if (!player->duration)
9108 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9109 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9110 if (stat(path, &sb) == 0)
9111 data_size = (guint64)sb.st_size;
9113 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9114 data_size = player->http_content_size;
9117 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9120 guint64 bitrate = 0;
9121 guint64 msec_dur = 0;
9123 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9125 bitrate = data_size * 8 * 1000 / msec_dur;
9126 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9127 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9128 mm_player_set_attribute((MMHandleType)player, NULL,
9129 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9132 LOGD("player duration is less than 0");
9136 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9137 if (player->total_bitrate) {
9138 mm_player_set_attribute((MMHandleType)player, NULL,
9139 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9148 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9150 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9151 data->uri_type = uri_type;
9155 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9157 int ret = MM_ERROR_PLAYER_INVALID_URI;
9159 char *buffer = NULL;
9160 char *seperator = strchr(path, ',');
9161 char ext[100] = {0,}, size[100] = {0,};
9164 if ((buffer = strstr(path, "ext="))) {
9165 buffer += strlen("ext=");
9167 if (strlen(buffer)) {
9168 strncpy(ext, buffer, 99);
9170 if ((seperator = strchr(ext, ','))
9171 || (seperator = strchr(ext, ' '))
9172 || (seperator = strchr(ext, '\0'))) {
9173 seperator[0] = '\0';
9178 if ((buffer = strstr(path, "size="))) {
9179 buffer += strlen("size=");
9181 if (strlen(buffer) > 0) {
9182 strncpy(size, buffer, 99);
9184 if ((seperator = strchr(size, ','))
9185 || (seperator = strchr(size, ' '))
9186 || (seperator = strchr(size, '\0'))) {
9187 seperator[0] = '\0';
9190 mem_size = atoi(size);
9195 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9197 if (mem_size && param) {
9198 if (data->input_mem.buf)
9199 free(data->input_mem.buf);
9200 data->input_mem.buf = malloc(mem_size);
9202 if (data->input_mem.buf) {
9203 memcpy(data->input_mem.buf, param, mem_size);
9204 data->input_mem.len = mem_size;
9205 ret = MM_ERROR_NONE;
9207 LOGE("failed to alloc mem %d", mem_size);
9208 ret = MM_ERROR_PLAYER_INTERNAL;
9211 data->input_mem.offset = 0;
9212 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9219 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9221 gchar *location = NULL;
9224 int ret = MM_ERROR_NONE;
9226 if ((path = strstr(uri, "file://"))) {
9227 location = g_filename_from_uri(uri, NULL, &err);
9228 if (!location || (err != NULL)) {
9229 LOGE("Invalid URI '%s' for filesrc: %s", path,
9230 (err != NULL) ? err->message : "unknown error");
9234 MMPLAYER_FREEIF(location);
9236 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9237 return MM_ERROR_PLAYER_INVALID_URI;
9239 LOGD("path from uri: %s", location);
9242 path = (location != NULL) ? (location) : ((char *)uri);
9245 ret = _mmplayer_exist_file_path(path);
9247 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9248 if (ret == MM_ERROR_NONE) {
9249 if (_mmplayer_is_sdp_file(path)) {
9250 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9251 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9252 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9254 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9255 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9257 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9258 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9260 LOGE("invalid uri, could not play..");
9261 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9264 MMPLAYER_FREEIF(location);
9269 static mmplayer_video_decoded_data_info_t *
9270 __mmplayer_create_stream_from_pad(GstPad *pad)
9272 GstCaps *caps = NULL;
9273 GstStructure *structure = NULL;
9274 unsigned int fourcc = 0;
9275 const gchar *string_format = NULL;
9276 mmplayer_video_decoded_data_info_t *stream = NULL;
9278 MMPixelFormatType format;
9281 caps = gst_pad_get_current_caps(pad);
9283 LOGE("Caps is NULL.");
9288 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9290 structure = gst_caps_get_structure(caps, 0);
9291 gst_structure_get_int(structure, "width", &width);
9292 gst_structure_get_int(structure, "height", &height);
9293 string_format = gst_structure_get_string(structure, "format");
9296 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9297 format = _mmplayer_get_pixtype(fourcc);
9298 gst_video_info_from_caps(&info, caps);
9299 gst_caps_unref(caps);
9302 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9303 LOGE("Wrong condition!!");
9307 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9309 LOGE("failed to alloc mem for video data");
9313 stream->width = width;
9314 stream->height = height;
9315 stream->format = format;
9316 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9322 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9324 unsigned int pitch = 0;
9325 unsigned int size = 0;
9327 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9330 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9331 bo = gst_tizen_memory_get_bos(mem, index);
9333 stream->bo[index] = tbm_bo_ref(bo);
9335 LOGE("failed to get bo for index %d", index);
9338 for (index = 0; index < stream->plane_num; index++) {
9339 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9340 stream->stride[index] = pitch;
9342 stream->elevation[index] = size / pitch;
9344 stream->elevation[index] = stream->height;
9349 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9351 if (stream->format == MM_PIXEL_FORMAT_I420) {
9352 int ret = TBM_SURFACE_ERROR_NONE;
9353 tbm_surface_h surface;
9354 tbm_surface_info_s info;
9356 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9358 ret = tbm_surface_get_info(surface, &info);
9359 if (ret != TBM_SURFACE_ERROR_NONE) {
9360 tbm_surface_destroy(surface);
9364 tbm_surface_destroy(surface);
9365 stream->stride[0] = info.planes[0].stride;
9366 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9367 stream->stride[1] = info.planes[1].stride;
9368 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9369 stream->stride[2] = info.planes[2].stride;
9370 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9371 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9372 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9373 stream->stride[0] = stream->width * 4;
9374 stream->elevation[0] = stream->height;
9375 stream->bo_size = stream->stride[0] * stream->height;
9377 LOGE("Not support format %d", stream->format);
9385 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9387 tbm_bo_handle thandle;
9389 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9390 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9391 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9395 unsigned char *src = NULL;
9396 unsigned char *dest = NULL;
9397 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9399 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9401 LOGE("fail to gst_memory_map");
9405 if (!mapinfo.data) {
9406 LOGE("data pointer is wrong");
9410 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9411 if (!stream->bo[0]) {
9412 LOGE("Fail to tbm_bo_alloc!!");
9416 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9418 LOGE("thandle pointer is wrong");
9422 if (stream->format == MM_PIXEL_FORMAT_I420) {
9423 src_stride[0] = GST_ROUND_UP_4(stream->width);
9424 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9425 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9426 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9429 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9430 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9432 for (i = 0; i < 3; i++) {
9433 src = mapinfo.data + src_offset[i];
9434 dest = thandle.ptr + dest_offset[i];
9439 for (j = 0; j < stream->height >> k; j++) {
9440 memcpy(dest, src, stream->width>>k);
9441 src += src_stride[i];
9442 dest += stream->stride[i];
9445 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9446 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9448 LOGE("Not support format %d", stream->format);
9452 tbm_bo_unmap(stream->bo[0]);
9453 gst_memory_unmap(mem, &mapinfo);
9459 tbm_bo_unmap(stream->bo[0]);
9462 gst_memory_unmap(mem, &mapinfo);
9468 __mmplayer_set_pause_state(mmplayer_t *player)
9470 if (player->sent_bos)
9473 /* rtsp case, get content attrs by GstMessage */
9474 if (MMPLAYER_IS_RTSP_STREAMING(player))
9477 /* it's first time to update all content attrs. */
9478 _mmplayer_update_content_attrs(player, ATTR_ALL);
9482 __mmplayer_set_playing_state(mmplayer_t *player)
9484 gchar *audio_codec = NULL;
9486 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9487 /* initialize because auto resume is done well. */
9488 player->resumed_by_rewind = FALSE;
9489 player->playback_rate = 1.0;
9492 if (player->sent_bos)
9495 /* try to get content metadata */
9497 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9498 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9499 * legacy mmfw-player api
9501 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9503 if ((player->cmd == MMPLAYER_COMMAND_START)
9504 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9505 __mmplayer_handle_missed_plugin(player);
9508 /* check audio codec field is set or not
9509 * we can get it from typefinder or codec's caps.
9511 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9513 /* The codec format can't be sent for audio only case like amr, mid etc.
9514 * Because, parser don't make related TAG.
9515 * So, if it's not set yet, fill it with found data.
9518 if (g_strrstr(player->type, "audio/midi"))
9519 audio_codec = "MIDI";
9520 else if (g_strrstr(player->type, "audio/x-amr"))
9521 audio_codec = "AMR";
9522 else if (g_strrstr(player->type, "audio/mpeg")
9523 && !g_strrstr(player->type, "mpegversion=(int)1"))
9524 audio_codec = "AAC";
9526 audio_codec = "unknown";
9528 if (mm_player_set_attribute((MMHandleType)player, NULL,
9529 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9530 LOGE("failed to set attribute");
9532 LOGD("set audio codec type with caps");