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(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);
694 __mmplayer_gapless_play_thread(gpointer data)
696 mmplayer_t *player = (mmplayer_t *)data;
697 mmplayer_gst_element_t *mainbin = NULL;
699 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
701 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
702 while (!player->gapless_play_thread_exit) {
703 LOGD("gapless play thread started. waiting for signal.");
704 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
706 LOGD("reconfigure pipeline for gapless play.");
708 if (player->gapless_play_thread_exit) {
709 if (player->gapless.reconfigure) {
710 player->gapless.reconfigure = false;
711 MMPLAYER_PLAYBACK_UNLOCK(player);
713 LOGD("exiting gapless play thread");
717 mainbin = player->pipeline->mainbin;
719 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
725 /* Initialize Player values */
726 __mmplayer_initialize_gapless_play(player);
728 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
730 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
736 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
738 GSource *source = NULL;
742 source = g_main_context_find_source_by_id(context, source_id);
743 if (source != NULL) {
744 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
745 g_source_destroy(source);
752 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
754 mmplayer_t *player = (mmplayer_t *)hplayer;
755 GstMessage *msg = NULL;
756 GQueue *queue = NULL;
759 MMPLAYER_RETURN_IF_FAIL(player);
761 /* disconnecting bus watch */
762 if (player->bus_watcher)
763 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
764 player->bus_watcher = 0;
766 /* destroy the gst bus msg thread */
767 if (player->bus_msg_thread) {
768 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
769 player->bus_msg_thread_exit = TRUE;
770 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
771 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
773 LOGD("gst bus msg thread exit.");
774 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
775 player->bus_msg_thread = NULL;
777 g_mutex_clear(&player->bus_msg_thread_mutex);
778 g_cond_clear(&player->bus_msg_thread_cond);
781 g_mutex_lock(&player->bus_msg_q_lock);
782 queue = player->bus_msg_q;
783 while (!g_queue_is_empty(queue)) {
784 msg = (GstMessage *)g_queue_pop_head(queue);
789 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
790 gst_message_unref(msg);
792 g_mutex_unlock(&player->bus_msg_q_lock);
798 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
800 GstElement *parent = NULL;
802 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
803 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
806 MMPLAYER_FSINK_LOCK(player);
808 /* get parent of fakesink */
809 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
811 LOGD("fakesink already removed");
815 gst_element_set_locked_state(fakesink->gst, TRUE);
817 /* setting the state to NULL never returns async
818 * so no need to wait for completion of state transiton
820 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
821 LOGE("fakesink state change failure!");
822 /* FIXIT : should I return here? or try to proceed to next? */
825 /* remove fakesink from it's parent */
826 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
827 LOGE("failed to remove fakesink");
829 gst_object_unref(parent);
834 gst_object_unref(parent);
836 LOGD("state-holder removed");
838 gst_element_set_locked_state(fakesink->gst, FALSE);
840 MMPLAYER_FSINK_UNLOCK(player);
845 gst_element_set_locked_state(fakesink->gst, FALSE);
847 MMPLAYER_FSINK_UNLOCK(player);
851 static GstPadProbeReturn
852 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
854 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
855 return GST_PAD_PROBE_OK;
859 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
861 gint64 stop_running_time = 0;
862 gint64 position_running_time = 0;
866 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
867 if ((player->gapless.update_segment[idx] == TRUE) ||
868 !(player->selector[idx].event_probe_id)) {
870 LOGW("[%d] skip", idx);
875 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
877 gst_segment_to_running_time(&player->gapless.segment[idx],
878 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
879 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
881 gst_segment_to_running_time(&player->gapless.segment[idx],
882 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
884 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
886 gst_segment_to_running_time(&player->gapless.segment[idx],
887 GST_FORMAT_TIME, player->duration);
890 position_running_time =
891 gst_segment_to_running_time(&player->gapless.segment[idx],
892 GST_FORMAT_TIME, player->gapless.segment[idx].position);
894 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
895 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
897 GST_TIME_ARGS(stop_running_time),
898 GST_TIME_ARGS(position_running_time),
899 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
900 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
902 position_running_time = MAX(position_running_time, stop_running_time);
903 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
904 GST_FORMAT_TIME, player->gapless.segment[idx].start);
905 position_running_time = MAX(0, position_running_time);
906 position = MAX(position, position_running_time);
910 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
911 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
912 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
914 player->gapless.start_time[stream_type] += position;
920 static GstPadProbeReturn
921 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
923 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
924 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
925 mmplayer_t *player = (mmplayer_t *)data;
926 GstCaps *caps = NULL;
927 GstStructure *str = NULL;
928 const gchar *name = NULL;
929 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
930 gboolean caps_ret = TRUE;
932 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
933 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
934 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
935 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
936 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
939 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
943 if (strstr(name, "audio")) {
944 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
945 } else if (strstr(name, "video")) {
946 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
948 /* text track is not supportable */
949 LOGE("invalid name %s", name);
953 switch (GST_EVENT_TYPE(event)) {
956 /* in case of gapless, drop eos event not to send it to sink */
957 if (player->gapless.reconfigure && !player->msg_posted) {
958 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
959 ret = GST_PAD_PROBE_DROP;
963 case GST_EVENT_STREAM_START:
965 __mmplayer_gst_selector_update_start_time(player, stream_type);
968 case GST_EVENT_FLUSH_STOP:
970 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
971 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
972 player->gapless.start_time[stream_type] = 0;
975 case GST_EVENT_SEGMENT:
980 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
981 gst_event_copy_segment(event, &segment);
983 if (segment.format != GST_FORMAT_TIME)
986 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
987 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
988 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
989 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
990 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
991 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
993 /* keep the all the segment ev to cover the seeking */
994 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
995 player->gapless.update_segment[stream_type] = TRUE;
997 if (!player->gapless.running)
1000 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1002 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1004 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1005 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1006 gst_event_unref(event);
1007 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1013 gdouble proportion = 0.0;
1014 GstClockTimeDiff diff = 0;
1015 GstClockTime timestamp = 0;
1016 gint64 running_time_diff = -1;
1017 GstQOSType type = 0;
1018 GstEvent *tmpev = NULL;
1020 running_time_diff = player->gapless.segment[stream_type].base;
1022 if (running_time_diff <= 0) /* don't need to adjust */
1025 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1026 gst_event_unref(event);
1028 if (timestamp < running_time_diff) {
1029 LOGW("QOS event from previous group");
1030 ret = GST_PAD_PROBE_DROP;
1035 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1036 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1037 stream_type, GST_TIME_ARGS(timestamp),
1038 GST_TIME_ARGS(running_time_diff),
1039 GST_TIME_ARGS(timestamp - running_time_diff));
1042 timestamp -= running_time_diff;
1044 /* That case is invalid for QoS events */
1045 if (diff < 0 && -diff > timestamp) {
1046 LOGW("QOS event from previous group");
1047 ret = GST_PAD_PROBE_DROP;
1051 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1052 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1062 gst_caps_unref(caps);
1066 /* create fakesink for audio or video path witout audiobin or videobin */
1068 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1070 GstElement *pipeline = NULL;
1071 GstElement *fakesink = NULL;
1072 GstPad *sinkpad = NULL;
1075 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1077 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1080 fakesink = gst_element_factory_make("fakesink", NULL);
1081 if (fakesink == NULL) {
1082 LOGE("failed to create fakesink");
1086 /* store it as it's sink element */
1087 __mmplayer_add_sink(player, fakesink);
1089 gst_bin_add(GST_BIN(pipeline), fakesink);
1092 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1094 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1096 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1097 LOGE("failed to link fakesink");
1098 gst_object_unref(GST_OBJECT(fakesink));
1102 if (strstr(name, "video")) {
1103 if (player->v_stream_caps) {
1104 gst_caps_unref(player->v_stream_caps);
1105 player->v_stream_caps = NULL;
1107 if (player->ini.set_dump_element_flag)
1108 __mmplayer_add_dump_buffer_probe(player, fakesink);
1111 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1112 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1116 gst_object_unref(GST_OBJECT(sinkpad));
1123 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1125 GstElement *pipeline = NULL;
1126 GstElement *selector = NULL;
1127 GstPad *srcpad = NULL;
1130 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1132 selector = gst_element_factory_make("input-selector", NULL);
1134 LOGE("failed to create input-selector");
1137 g_object_set(selector, "sync-streams", TRUE, NULL);
1139 player->pipeline->mainbin[elem_idx].id = elem_idx;
1140 player->pipeline->mainbin[elem_idx].gst = selector;
1142 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1144 srcpad = gst_element_get_static_pad(selector, "src");
1146 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1147 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1148 __mmplayer_gst_selector_blocked, NULL, NULL);
1149 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1150 __mmplayer_gst_selector_event_probe, player, NULL);
1152 gst_element_set_state(selector, GST_STATE_PAUSED);
1154 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1155 gst_bin_add(GST_BIN(pipeline), selector);
1157 gst_object_unref(GST_OBJECT(srcpad));
1164 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1166 mmplayer_t *player = (mmplayer_t *)data;
1167 GstElement *selector = NULL;
1168 GstCaps *caps = NULL;
1169 GstStructure *str = NULL;
1170 const gchar *name = NULL;
1171 GstPad *sinkpad = NULL;
1172 gboolean first_track = FALSE;
1173 gboolean caps_ret = TRUE;
1175 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1176 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1179 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1180 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1182 LOGD("pad-added signal handling");
1184 /* get mimetype from caps */
1185 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1189 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1191 LOGD("detected mimetype : %s", name);
1194 if (strstr(name, "video")) {
1196 gchar *caps_str = NULL;
1198 caps_str = gst_caps_to_string(caps);
1199 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1200 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1201 player->set_mode.video_zc = true;
1203 MMPLAYER_FREEIF(caps_str);
1205 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1206 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1208 LOGD("surface type : %d", stype);
1210 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1211 __mmplayer_gst_create_sinkbin(elem, pad, player);
1215 /* in case of exporting video frame, it requires the 360 video filter.
1216 * it will be handled in _no_more_pads(). */
1217 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1218 __mmplayer_gst_make_fakesink(player, pad, name);
1222 LOGD("video selector is required");
1223 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1224 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1225 } else if (strstr(name, "audio")) {
1226 gint samplerate = 0;
1229 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1230 if (player->build_audio_offload)
1231 player->no_more_pad = TRUE; /* remove state holder */
1232 __mmplayer_gst_create_sinkbin(elem, pad, player);
1236 gst_structure_get_int(str, "rate", &samplerate);
1237 gst_structure_get_int(str, "channels", &channels);
1239 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1240 __mmplayer_gst_make_fakesink(player, pad, name);
1244 LOGD("audio selector is required");
1245 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1246 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1248 } else if (strstr(name, "text")) {
1249 LOGD("text selector is required");
1250 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1251 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1253 LOGE("invalid caps info");
1257 /* check selector and create it */
1258 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1259 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1264 LOGD("input-selector is already created.");
1268 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1270 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1272 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1273 LOGE("failed to link selector");
1274 gst_object_unref(GST_OBJECT(selector));
1279 LOGD("this track will be activated");
1280 g_object_set(selector, "active-pad", sinkpad, NULL);
1283 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1289 gst_caps_unref(caps);
1292 gst_object_unref(GST_OBJECT(sinkpad));
1300 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1302 GstPad *srcpad = NULL;
1305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1307 LOGD("type %d", type);
1310 LOGD("there is no %d track", type);
1314 srcpad = gst_element_get_static_pad(selector, "src");
1316 LOGE("failed to get srcpad from selector");
1320 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1322 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1324 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1325 if (player->selector[type].block_id) {
1326 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1327 player->selector[type].block_id = 0;
1331 gst_object_unref(GST_OBJECT(srcpad));
1340 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1342 gint active_index = 0;
1345 MMPLAYER_RETURN_IF_FAIL(player);
1347 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1349 /* change track to active pad */
1350 active_index = player->selector[type].active_pad_index;
1351 if ((active_index != DEFAULT_TRACK) &&
1352 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1353 LOGW("failed to change %d type track to %d", type, active_index);
1354 player->selector[type].active_pad_index = DEFAULT_TRACK;
1358 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1359 mm_player_set_attribute((MMHandleType)player, NULL,
1360 "content_text_track_num", player->selector[type].total_track_num,
1361 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1368 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1371 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1373 if (!audio_selector) {
1374 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1376 /* in case the source is changed, output can be changed. */
1377 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1378 LOGD("remove previous audiobin if it exist");
1380 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1381 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1383 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1384 MMPLAYER_FREEIF(player->pipeline->audiobin);
1387 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1388 __mmplayer_pipeline_complete(NULL, player);
1393 /* apply the audio track information */
1394 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1396 /* create audio sink path */
1397 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1398 LOGE("failed to create audio sink path");
1407 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1410 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1412 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1413 LOGD("text path is not supproted");
1417 /* apply the text track information */
1418 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1420 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1421 player->has_closed_caption = TRUE;
1423 /* create text decode path */
1424 player->no_more_pad = TRUE;
1426 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1427 LOGE("failed to create text sink path");
1436 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1438 gint64 dur_bytes = 0L;
1441 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1442 player->pipeline->mainbin && player->streamer, FALSE);
1444 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1445 LOGE("fail to get duration.");
1447 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1448 * use file information was already set on Q2 when it was created. */
1449 _mm_player_streaming_set_queue2(player->streamer,
1450 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1451 TRUE, /* use_buffering */
1452 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1453 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1460 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1462 mmplayer_t *player = NULL;
1463 GstElement *video_selector = NULL;
1464 GstElement *audio_selector = NULL;
1465 GstElement *text_selector = NULL;
1468 player = (mmplayer_t *)data;
1470 LOGD("no-more-pad signal handling");
1472 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1473 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1474 LOGW("player is shutting down");
1478 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1479 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1480 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1481 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1482 LOGE("failed to set queue2 buffering");
1487 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1488 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1489 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1491 if (!video_selector && !audio_selector && !text_selector) {
1492 LOGW("there is no selector");
1493 player->no_more_pad = TRUE;
1497 /* create video path followed by video-select */
1498 if (video_selector && !audio_selector && !text_selector)
1499 player->no_more_pad = TRUE;
1501 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1504 /* create audio path followed by audio-select */
1505 if (audio_selector && !text_selector)
1506 player->no_more_pad = TRUE;
1508 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1511 /* create text path followed by text-select */
1512 __mmplayer_create_text_sink_path(player, text_selector);
1515 if (player->gapless.reconfigure) {
1516 player->gapless.reconfigure = FALSE;
1517 MMPLAYER_PLAYBACK_UNLOCK(player);
1524 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1526 gboolean ret = FALSE;
1527 GstElement *pipeline = NULL;
1528 GstPad *sinkpad = NULL;
1531 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1532 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1534 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1536 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1538 LOGE("failed to get pad from sinkbin");
1544 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1545 LOGE("failed to link sinkbin for reusing");
1546 goto EXIT; /* exit either pass or fail */
1550 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1551 LOGE("failed to set state(READY) to sinkbin");
1556 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1557 LOGE("failed to add sinkbin to pipeline");
1562 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1563 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1568 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1569 LOGE("failed to set state(PAUSED) to sinkbin");
1578 gst_object_unref(GST_OBJECT(sinkpad));
1586 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1588 mmplayer_t *player = NULL;
1589 GstCaps *caps = NULL;
1590 gchar *caps_str = NULL;
1591 GstStructure *str = NULL;
1592 const gchar *name = NULL;
1593 GstElement *sinkbin = NULL;
1594 gboolean reusing = FALSE;
1595 gboolean caps_ret = TRUE;
1596 gchar *sink_pad_name = "sink";
1599 player = (mmplayer_t *)data;
1602 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1603 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1605 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1609 caps_str = gst_caps_to_string(caps);
1611 LOGD("detected mimetype : %s", name);
1613 if (strstr(name, "audio")) {
1614 if (player->pipeline->audiobin == NULL) {
1615 const gchar *audio_format = gst_structure_get_string(str, "format");
1617 LOGD("original audio format %s", audio_format);
1618 mm_player_set_attribute((MMHandleType)player, NULL,
1619 "content_audio_format", audio_format, strlen(audio_format), NULL);
1622 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1623 LOGE("failed to create audiobin. continuing without audio");
1627 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1628 LOGD("creating audiobin success");
1631 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1632 LOGD("reusing audiobin");
1633 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1635 } else if (strstr(name, "video")) {
1636 /* 1. zero copy is updated at _decode_pad_added()
1637 * 2. NULL surface type is handled in _decode_pad_added() */
1638 LOGD("zero copy %d", player->set_mode.video_zc);
1639 if (player->pipeline->videobin == NULL) {
1640 int surface_type = 0;
1641 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1642 LOGD("display_surface_type (%d)", surface_type);
1644 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1645 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1646 LOGE("failed to acquire video overlay resource");
1650 player->interrupted_by_resource = FALSE;
1652 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1653 LOGE("failed to create videobin. continuing without video");
1657 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1658 LOGD("creating videosink bin success");
1661 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1662 LOGD("re-using videobin");
1663 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1665 } else if (strstr(name, "text")) {
1666 if (player->pipeline->textbin == NULL) {
1667 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1668 LOGE("failed to create text sink bin. continuing without text");
1672 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1673 player->textsink_linked = 1;
1674 LOGD("creating textsink bin success");
1676 if (!player->textsink_linked) {
1677 LOGD("re-using textbin");
1679 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1680 player->textsink_linked = 1;
1682 /* linked textbin exist which means that the external subtitle path exist already */
1683 LOGW("ignoring internal subtutle since external subtitle is available");
1686 sink_pad_name = "text_sink";
1688 LOGW("unknown mime type %s, ignoring it", name);
1692 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1695 LOGD("[handle: %p] success to create and link sink bin", player);
1697 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1698 * streaming task. if the task blocked, then buffer will not flow to the next element
1699 *(autoplugging element). so this is special hack for streaming. please try to remove it
1701 /* dec stream count. we can remove fakesink if it's zero */
1702 if (player->num_dynamic_pad)
1703 player->num_dynamic_pad--;
1705 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1707 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1708 __mmplayer_pipeline_complete(NULL, player);
1712 MMPLAYER_FREEIF(caps_str);
1715 gst_caps_unref(caps);
1721 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1723 int required_angle = 0; /* Angle required for straight view */
1724 int rotation_angle = 0;
1726 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1727 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1729 /* Counter clockwise */
1730 switch (orientation) {
1735 required_angle = 270;
1738 required_angle = 180;
1741 required_angle = 90;
1745 rotation_angle = display_angle + required_angle;
1746 if (rotation_angle >= 360)
1747 rotation_angle -= 360;
1749 /* chech if supported or not */
1750 if (rotation_angle % 90) {
1751 LOGD("not supported rotation angle = %d", rotation_angle);
1755 switch (rotation_angle) {
1757 *value = MM_DISPLAY_ROTATION_NONE;
1760 *value = MM_DISPLAY_ROTATION_90;
1763 *value = MM_DISPLAY_ROTATION_180;
1766 *value = MM_DISPLAY_ROTATION_270;
1770 LOGD("setting rotation property value : %d", *value);
1776 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1778 int display_rotation = 0;
1779 gchar *org_orient = NULL;
1780 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1783 LOGE("cannot get content attribute");
1784 return MM_ERROR_PLAYER_INTERNAL;
1787 if (display_angle) {
1788 /* update user roation */
1789 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1791 /* Counter clockwise */
1792 switch (display_rotation) {
1793 case MM_DISPLAY_ROTATION_NONE:
1796 case MM_DISPLAY_ROTATION_90:
1797 *display_angle = 90;
1799 case MM_DISPLAY_ROTATION_180:
1800 *display_angle = 180;
1802 case MM_DISPLAY_ROTATION_270:
1803 *display_angle = 270;
1806 LOGW("wrong angle type : %d", display_rotation);
1809 LOGD("check user angle: %d", *display_angle);
1813 /* Counter clockwise */
1814 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1817 if (!strcmp(org_orient, "rotate-90"))
1819 else if (!strcmp(org_orient, "rotate-180"))
1821 else if (!strcmp(org_orient, "rotate-270"))
1824 LOGD("original rotation is %s", org_orient);
1826 LOGD("content_video_orientation get fail");
1829 LOGD("check orientation: %d", *orientation);
1832 return MM_ERROR_NONE;
1835 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1837 int rotation_value = 0;
1838 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1839 int display_angle = 0;
1842 /* check video sinkbin is created */
1843 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1846 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1848 /* get rotation value to set */
1849 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1850 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1851 LOGD("set video param : rotate %d", rotation_value);
1854 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1856 MMHandleType attrs = 0;
1860 /* check video sinkbin is created */
1861 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1864 attrs = MMPLAYER_GET_ATTRS(player);
1865 MMPLAYER_RETURN_IF_FAIL(attrs);
1867 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1868 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1869 LOGD("set video param : visible %d", visible);
1872 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1874 MMHandleType attrs = 0;
1875 int display_method = 0;
1878 /* check video sinkbin is created */
1879 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1882 attrs = MMPLAYER_GET_ATTRS(player);
1883 MMPLAYER_RETURN_IF_FAIL(attrs);
1885 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1886 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1887 LOGD("set video param : method %d", display_method);
1890 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1892 MMHandleType attrs = 0;
1896 /* check video sinkbin is created */
1897 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1900 attrs = MMPLAYER_GET_ATTRS(player);
1901 MMPLAYER_RETURN_IF_FAIL(attrs);
1903 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1904 MMPLAYER_RETURN_IF_FAIL(handle);
1906 gst_video_overlay_set_video_roi_area(
1907 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1908 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1909 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1910 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1913 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1915 MMHandleType attrs = 0;
1920 int win_roi_width = 0;
1921 int win_roi_height = 0;
1924 /* check video sinkbin is created */
1925 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1928 attrs = MMPLAYER_GET_ATTRS(player);
1929 MMPLAYER_RETURN_IF_FAIL(attrs);
1931 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1932 MMPLAYER_RETURN_IF_FAIL(handle);
1934 /* It should be set after setting window */
1935 mm_attrs_multiple_get(attrs, NULL,
1936 "display_win_roi_x", &win_roi_x,
1937 "display_win_roi_y", &win_roi_y,
1938 "display_win_roi_width", &win_roi_width,
1939 "display_win_roi_height", &win_roi_height, NULL);
1941 /* After setting window handle, set display roi area */
1942 gst_video_overlay_set_display_roi_area(
1943 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1944 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1945 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1946 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1949 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1951 MMHandleType attrs = 0;
1954 /* check video sinkbin is created */
1955 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1958 attrs = MMPLAYER_GET_ATTRS(player);
1959 MMPLAYER_RETURN_IF_FAIL(attrs);
1961 /* common case if using overlay surface */
1962 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1963 MMPLAYER_RETURN_IF_FAIL(handle);
1965 /* default is using wl_surface_id */
1966 LOGD("set video param : wl_surface_id %d", handle);
1967 gst_video_overlay_set_wl_window_wl_surface_id(
1968 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1973 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1975 gboolean update_all_param = FALSE;
1979 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1980 LOGW("videosink is not ready yet");
1981 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1984 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1985 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1986 return MM_ERROR_PLAYER_INTERNAL;
1989 LOGD("param_name : %s", param_name);
1990 if (!g_strcmp0(param_name, "update_all_param"))
1991 update_all_param = TRUE;
1993 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1994 __mmplayer_video_param_set_display_overlay(player);
1995 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1996 __mmplayer_video_param_set_display_method(player);
1997 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1998 __mmplayer_video_param_set_display_visible(player);
1999 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2000 __mmplayer_video_param_set_display_rotation(player);
2001 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2002 __mmplayer_video_param_set_roi_area(player);
2003 if (update_all_param)
2004 __mmplayer_video_param_set_video_roi_area(player);
2008 return MM_ERROR_NONE;
2012 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2014 gboolean disable_overlay = FALSE;
2015 mmplayer_t *player = (mmplayer_t *)hplayer;
2018 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2019 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2020 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2021 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2023 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2024 LOGW("Display control is not supported");
2025 return MM_ERROR_PLAYER_INTERNAL;
2028 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2030 if (audio_only == (bool)disable_overlay) {
2031 LOGE("It's the same with current setting: (%d)", audio_only);
2032 return MM_ERROR_NONE;
2036 LOGE("disable overlay");
2037 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2039 /* release overlay resource */
2040 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2041 LOGE("failed to release overlay resource");
2045 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2046 LOGE("failed to acquire video overlay resource");
2049 player->interrupted_by_resource = FALSE;
2051 LOGD("enable overlay");
2052 __mmplayer_video_param_set_display_overlay(player);
2053 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2058 return MM_ERROR_NONE;
2062 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2064 mmplayer_t *player = (mmplayer_t *)hplayer;
2065 gboolean disable_overlay = FALSE;
2069 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2070 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2071 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2072 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2073 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2075 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2076 LOGW("Display control is not supported");
2077 return MM_ERROR_PLAYER_INTERNAL;
2080 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2082 *paudio_only = (bool)disable_overlay;
2084 LOGD("audio_only : %d", *paudio_only);
2088 return MM_ERROR_NONE;
2092 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2094 GList *bucket = element_bucket;
2095 mmplayer_gst_element_t *element = NULL;
2096 mmplayer_gst_element_t *prv_element = NULL;
2097 GstElement *tee_element = NULL;
2098 gint successful_link_count = 0;
2102 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2104 prv_element = (mmplayer_gst_element_t *)bucket->data;
2105 bucket = bucket->next;
2107 for (; bucket; bucket = bucket->next) {
2108 element = (mmplayer_gst_element_t *)bucket->data;
2110 if (element && element->gst) {
2111 if (prv_element && prv_element->gst) {
2112 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2114 prv_element->gst = tee_element;
2116 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2117 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2118 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2122 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2123 LOGD("linking [%s] to [%s] success",
2124 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2125 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2126 successful_link_count++;
2127 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2128 LOGD("keep audio-tee element for next audio pipeline branch");
2129 tee_element = prv_element->gst;
2132 LOGD("linking [%s] to [%s] failed",
2133 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2134 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2140 prv_element = element;
2145 return successful_link_count;
2149 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2151 GList *bucket = element_bucket;
2152 mmplayer_gst_element_t *element = NULL;
2153 int successful_add_count = 0;
2157 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2158 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2160 for (; bucket; bucket = bucket->next) {
2161 element = (mmplayer_gst_element_t *)bucket->data;
2163 if (element && element->gst) {
2164 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2165 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2166 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2167 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2170 successful_add_count++;
2176 return successful_add_count;
2180 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2182 mmplayer_t *player = (mmplayer_t *)data;
2183 GstCaps *caps = NULL;
2184 GstStructure *str = NULL;
2186 gboolean caps_ret = TRUE;
2190 MMPLAYER_RETURN_IF_FAIL(pad);
2191 MMPLAYER_RETURN_IF_FAIL(unused);
2192 MMPLAYER_RETURN_IF_FAIL(data);
2194 caps = gst_pad_get_current_caps(pad);
2198 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2202 LOGD("name = %s", name);
2204 if (strstr(name, "audio")) {
2205 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2207 if (player->audio_stream_changed_cb) {
2208 LOGE("call the audio stream changed cb");
2209 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2211 } else if (strstr(name, "video")) {
2212 if ((name = gst_structure_get_string(str, "format")))
2213 player->set_mode.video_zc = name[0] == 'S';
2215 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2216 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2218 LOGW("invalid caps info");
2223 gst_caps_unref(caps);
2231 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2236 MMPLAYER_RETURN_IF_FAIL(player);
2238 if (player->audio_stream_buff_list) {
2239 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2240 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2243 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2244 __mmplayer_audio_stream_send_data(player, tmp);
2246 MMPLAYER_FREEIF(tmp->pcm_data);
2247 MMPLAYER_FREEIF(tmp);
2250 g_list_free(player->audio_stream_buff_list);
2251 player->audio_stream_buff_list = NULL;
2258 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2260 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2263 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2265 audio_stream.bitrate = a_buffer->bitrate;
2266 audio_stream.channel = a_buffer->channel;
2267 audio_stream.channel_mask = a_buffer->channel_mask;
2268 audio_stream.data_size = a_buffer->data_size;
2269 audio_stream.data = a_buffer->pcm_data;
2270 audio_stream.pcm_format = a_buffer->pcm_format;
2272 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2274 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2280 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2282 mmplayer_t *player = (mmplayer_t *)data;
2283 const gchar *pcm_format = NULL;
2286 guint64 channel_mask = 0;
2287 void *a_data = NULL;
2289 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2290 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2294 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2296 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2297 a_data = mapinfo.data;
2298 a_size = mapinfo.size;
2300 GstCaps *caps = gst_pad_get_current_caps(pad);
2301 GstStructure *structure = gst_caps_get_structure(caps, 0);
2303 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2305 pcm_format = gst_structure_get_string(structure, "format");
2306 gst_structure_get_int(structure, "rate", &rate);
2307 gst_structure_get_int(structure, "channels", &channel);
2308 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2309 gst_caps_unref(GST_CAPS(caps));
2311 /* In case of the sync is false, use buffer list. *
2312 * The num of buffer list depends on the num of audio channels */
2313 if (player->audio_stream_buff_list) {
2314 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2315 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2317 if (channel_mask == tmp->channel_mask) {
2319 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2321 if (tmp->data_size + a_size < tmp->buff_size) {
2322 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2323 tmp->data_size += a_size;
2325 /* send data to client */
2326 __mmplayer_audio_stream_send_data(player, tmp);
2328 if (a_size > tmp->buff_size) {
2329 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2330 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2331 if (tmp->pcm_data == NULL) {
2332 LOGE("failed to realloc data.");
2335 tmp->buff_size = a_size;
2337 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2338 memcpy(tmp->pcm_data, a_data, a_size);
2339 tmp->data_size = a_size;
2344 LOGE("data is empty in list.");
2350 /* create new audio stream data for newly found audio channel */
2351 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2352 if (a_buffer == NULL) {
2353 LOGE("failed to alloc data.");
2356 a_buffer->bitrate = rate;
2357 a_buffer->channel = channel;
2358 a_buffer->channel_mask = channel_mask;
2359 a_buffer->data_size = a_size;
2360 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2362 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2363 /* If sync is FALSE, use buffer list to reduce the IPC. */
2364 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2365 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2366 if (a_buffer->pcm_data == NULL) {
2367 LOGE("failed to alloc data.");
2368 MMPLAYER_FREEIF(a_buffer);
2371 memcpy(a_buffer->pcm_data, a_data, a_size);
2373 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2375 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2377 /* If sync is TRUE, send data directly. */
2378 a_buffer->pcm_data = a_data;
2379 __mmplayer_audio_stream_send_data(player, a_buffer);
2380 MMPLAYER_FREEIF(a_buffer);
2384 gst_buffer_unmap(buffer, &mapinfo);
2389 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2391 mmplayer_t *player = (mmplayer_t *)data;
2392 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2393 GstPad *sinkpad = NULL;
2394 GstElement *queue = NULL, *sink = NULL;
2397 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2399 queue = gst_element_factory_make("queue", NULL);
2400 if (queue == NULL) {
2401 LOGD("fail make queue");
2405 sink = gst_element_factory_make("fakesink", NULL);
2407 LOGD("fail make fakesink");
2411 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2413 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2414 LOGW("failed to link queue & sink");
2418 sinkpad = gst_element_get_static_pad(queue, "sink");
2420 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2421 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2425 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2427 gst_object_unref(sinkpad);
2428 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2429 g_object_set(sink, "sync", TRUE, NULL);
2430 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2432 /* keep the first sink reference only */
2433 if (!audiobin[MMPLAYER_A_SINK].gst) {
2434 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2435 audiobin[MMPLAYER_A_SINK].gst = sink;
2439 _mmplayer_add_signal_connection(player,
2441 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2443 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2446 __mmplayer_add_sink(player, sink);
2448 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2449 LOGE("failed to sync state");
2453 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2454 LOGE("failed to sync state");
2462 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2464 gst_object_unref(GST_OBJECT(queue));
2468 gst_object_unref(GST_OBJECT(sink));
2472 gst_object_unref(GST_OBJECT(sinkpad));
2480 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2482 mmplayer_t *player = (mmplayer_t *)data;
2485 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2487 player->no_more_pad = TRUE;
2488 __mmplayer_pipeline_complete(NULL, player);
2495 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2497 #define MAX_PROPS_LEN 128
2498 mmplayer_gst_element_t *audiobin = NULL;
2499 gint latency_mode = 0;
2500 gchar *stream_type = NULL;
2501 gchar *latency = NULL;
2503 gchar stream_props[MAX_PROPS_LEN] = {0,};
2504 GstStructure *props = NULL;
2507 * It should be set after player creation through attribute.
2508 * But, it can not be changed during playing.
2511 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2513 audiobin = player->pipeline->audiobin;
2515 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2516 if (player->sound.mute) {
2517 LOGD("mute enabled");
2518 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2521 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2522 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2525 snprintf(stream_props, sizeof(stream_props) - 1,
2526 "props,application.process.id.origin=%d", player->client_pid);
2528 snprintf(stream_props, sizeof(stream_props) - 1,
2529 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2530 stream_type, stream_id, player->client_pid);
2532 props = gst_structure_from_string(stream_props, NULL);
2533 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2534 LOGI("props result[%s].", stream_props);
2535 gst_structure_free(props);
2537 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2539 switch (latency_mode) {
2540 case AUDIO_LATENCY_MODE_LOW:
2541 latency = g_strndup("low", 3);
2543 case AUDIO_LATENCY_MODE_MID:
2544 latency = g_strndup("mid", 3);
2546 case AUDIO_LATENCY_MODE_HIGH:
2547 latency = g_strndup("high", 4);
2551 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2553 LOGD("audiosink property - latency=%s", latency);
2555 MMPLAYER_FREEIF(latency);
2561 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2563 mmplayer_gst_element_t *audiobin = NULL;
2566 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2568 audiobin = player->pipeline->audiobin;
2570 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2571 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2572 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2574 if (player->video360_yaw_radians <= M_PI &&
2575 player->video360_yaw_radians >= -M_PI &&
2576 player->video360_pitch_radians <= M_PI_2 &&
2577 player->video360_pitch_radians >= -M_PI_2) {
2578 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2579 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2580 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2581 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2582 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2583 "source-orientation-y", player->video360_metadata.init_view_heading,
2584 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2591 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2593 mmplayer_gst_element_t *audiobin = NULL;
2594 GstPad *sink_pad = NULL;
2595 GstCaps *acaps = NULL;
2597 int pitch_control = 0;
2598 double pitch_value = 1.0;
2601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2602 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2604 audiobin = player->pipeline->audiobin;
2606 LOGD("make element for normal audio playback");
2608 /* audio bin structure for playback. {} means optional.
2609 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2611 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2612 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2615 /* for pitch control */
2616 mm_attrs_multiple_get(player->attrs, NULL,
2617 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2618 MM_PLAYER_PITCH_VALUE, &pitch_value,
2621 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2622 if (pitch_control && (player->videodec_linked == 0)) {
2623 GstElementFactory *factory;
2625 factory = gst_element_factory_find("pitch");
2627 gst_object_unref(factory);
2630 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2633 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2634 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2636 LOGW("there is no pitch element");
2641 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2643 /* replaygain volume */
2644 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2645 if (player->sound.rg_enable)
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2648 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2651 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2653 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2654 /* currently, only openalsink uses volume element */
2655 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2658 if (player->sound.mute) {
2659 LOGD("mute enabled");
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2664 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2666 /* audio effect element. if audio effect is enabled */
2667 if ((strcmp(player->ini.audioeffect_element, ""))
2669 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2672 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2674 if ((!player->bypass_audio_effect)
2675 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2676 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2677 if (!_mmplayer_audio_effect_custom_apply(player))
2678 LOGI("apply audio effect(custom) setting success");
2682 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2683 && (player->set_mode.rich_audio)) {
2684 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2688 /* create audio sink */
2689 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2690 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2691 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2693 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2694 if (player->is_360_feature_enabled &&
2695 player->is_content_spherical &&
2697 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2698 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2699 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2701 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2703 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2706 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2707 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2708 gst_caps_unref(acaps);
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2712 player->is_openal_plugin_used = TRUE;
2714 if (player->is_360_feature_enabled && player->is_content_spherical)
2715 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2719 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2720 (player->videodec_linked && player->ini.use_system_clock)) {
2721 LOGD("system clock will be used.");
2722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2725 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2726 __mmplayer_gst_set_pulsesink_property(player);
2727 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2728 __mmplayer_gst_set_openalsink_property(player);
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2734 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2735 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2736 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2737 gst_object_unref(GST_OBJECT(sink_pad));
2739 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2742 return MM_ERROR_NONE;
2744 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2746 return MM_ERROR_PLAYER_INTERNAL;
2750 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2752 mmplayer_gst_element_t *audiobin = NULL;
2753 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2755 gchar *dst_format = NULL;
2757 int dst_samplerate = 0;
2758 int dst_channels = 0;
2759 GstCaps *caps = NULL;
2760 char *caps_str = NULL;
2763 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2764 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2766 audiobin = player->pipeline->audiobin;
2768 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2770 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2772 [case 1] extract interleave audio pcm without playback
2773 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2774 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2776 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2778 [case 2] deinterleave for each channel without playback
2779 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2780 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2782 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2783 - fakesink (sync or not)
2786 [case 3] [case 1(sync only)] + playback
2787 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2789 * src - ... - tee - queue1 - playback path
2790 - queue2 - [case1 pipeline with sync]
2792 [case 4] [case 2(sync only)] + playback
2793 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2795 * src - ... - tee - queue1 - playback path
2796 - queue2 - [case2 pipeline with sync]
2800 /* 1. create tee and playback path
2801 'tee' should be added at first to copy the decoded stream
2803 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2804 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2805 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2807 /* tee - path 1 : for playback path */
2808 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2809 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2811 /* tee - path 2 : for extract path */
2812 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2813 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2816 /* if there is tee, 'tee - path 2' is linked here */
2818 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2823 /* 2. decide the extract pcm format */
2824 mm_attrs_multiple_get(player->attrs, NULL,
2825 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2826 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2827 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2830 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2831 dst_format, dst_len, dst_samplerate, dst_channels);
2833 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2834 mm_attrs_multiple_get(player->attrs, NULL,
2835 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2836 "content_audio_samplerate", &dst_samplerate,
2837 "content_audio_channels", &dst_channels,
2840 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2841 dst_format, dst_len, dst_samplerate, dst_channels);
2843 /* If there is no enough information, set it to platform default value. */
2844 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2845 LOGD("set platform default format");
2846 dst_format = DEFAULT_PCM_OUT_FORMAT;
2848 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2849 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2852 /* 3. create capsfilter */
2853 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2854 caps = gst_caps_new_simple("audio/x-raw",
2855 "format", G_TYPE_STRING, dst_format,
2856 "rate", G_TYPE_INT, dst_samplerate,
2857 "channels", G_TYPE_INT, dst_channels,
2860 caps_str = gst_caps_to_string(caps);
2861 LOGD("new caps : %s", caps_str);
2863 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2866 gst_caps_unref(caps);
2867 MMPLAYER_FREEIF(caps_str);
2869 /* 4-1. create deinterleave to extract pcm for each channel */
2870 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2871 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2872 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2874 /* audiosink will be added after getting signal for each channel */
2875 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2876 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2877 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2878 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2879 player->no_more_pad = FALSE;
2881 /* 4-2. create fakesink to extract interlevaed pcm */
2882 LOGD("add audio fakesink for interleaved audio");
2883 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2884 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2885 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2886 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2888 _mmplayer_add_signal_connection(player,
2889 G_OBJECT(audiobin[extract_sink_id].gst),
2890 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2892 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2895 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2899 return MM_ERROR_NONE;
2901 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2903 return MM_ERROR_PLAYER_INTERNAL;
2907 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2909 int ret = MM_ERROR_NONE;
2910 mmplayer_gst_element_t *audiobin = NULL;
2911 GList *element_bucket = NULL;
2914 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2915 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2917 audiobin = player->pipeline->audiobin;
2919 if (player->build_audio_offload) { /* skip all the audio filters */
2920 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2922 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2923 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2924 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2926 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2930 /* FIXME: need to mention the supportable condition at API reference */
2931 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2932 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2934 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2936 if (ret != MM_ERROR_NONE)
2939 LOGD("success to make audio bin element");
2940 *bucket = element_bucket;
2943 return MM_ERROR_NONE;
2946 LOGE("failed to make audio bin element");
2947 g_list_free(element_bucket);
2951 return MM_ERROR_PLAYER_INTERNAL;
2955 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2957 mmplayer_gst_element_t *first_element = NULL;
2958 mmplayer_gst_element_t *audiobin = NULL;
2960 GstPad *ghostpad = NULL;
2961 GList *element_bucket = NULL;
2965 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2968 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2970 LOGE("failed to allocate memory for audiobin");
2971 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2975 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2976 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2977 if (!audiobin[MMPLAYER_A_BIN].gst) {
2978 LOGE("failed to create audiobin");
2983 player->pipeline->audiobin = audiobin;
2985 /* create audio filters and audiosink */
2986 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2989 /* adding created elements to bin */
2990 LOGD("adding created elements to bin");
2991 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2994 /* linking elements in the bucket by added order. */
2995 LOGD("Linking elements in the bucket by added order.");
2996 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
2999 /* get first element's sinkpad for creating ghostpad */
3000 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3001 if (!first_element) {
3002 LOGE("failed to get first elem");
3006 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3008 LOGE("failed to get pad from first element of audiobin");
3012 ghostpad = gst_ghost_pad_new("sink", pad);
3014 LOGE("failed to create ghostpad");
3018 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3019 LOGE("failed to add ghostpad to audiobin");
3023 gst_object_unref(pad);
3025 g_list_free(element_bucket);
3028 return MM_ERROR_NONE;
3031 LOGD("ERROR : releasing audiobin");
3034 gst_object_unref(GST_OBJECT(pad));
3037 gst_object_unref(GST_OBJECT(ghostpad));
3040 g_list_free(element_bucket);
3042 /* release element which are not added to bin */
3043 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3044 /* NOTE : skip bin */
3045 if (audiobin[i].gst) {
3046 GstObject *parent = NULL;
3047 parent = gst_element_get_parent(audiobin[i].gst);
3050 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3051 audiobin[i].gst = NULL;
3053 gst_object_unref(GST_OBJECT(parent));
3057 /* release audiobin with it's childs */
3058 if (audiobin[MMPLAYER_A_BIN].gst)
3059 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3061 MMPLAYER_FREEIF(audiobin);
3063 player->pipeline->audiobin = NULL;
3065 return MM_ERROR_PLAYER_INTERNAL;
3069 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3071 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3075 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3077 int ret = MM_ERROR_NONE;
3079 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3080 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3082 MMPLAYER_VIDEO_BO_LOCK(player);
3084 if (player->video_bo_list) {
3085 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3086 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3087 if (tmp && tmp->bo == bo) {
3089 LOGD("release bo %p", bo);
3090 tbm_bo_unref(tmp->bo);
3091 MMPLAYER_VIDEO_BO_UNLOCK(player);
3092 MMPLAYER_VIDEO_BO_SIGNAL(player);
3097 /* hw codec is running or the list was reset for DRC. */
3098 LOGW("there is no bo list.");
3100 MMPLAYER_VIDEO_BO_UNLOCK(player);
3102 LOGW("failed to find bo %p", bo);
3107 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3112 MMPLAYER_RETURN_IF_FAIL(player);
3114 MMPLAYER_VIDEO_BO_LOCK(player);
3115 if (player->video_bo_list) {
3116 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3117 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3118 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3121 tbm_bo_unref(tmp->bo);
3125 g_list_free(player->video_bo_list);
3126 player->video_bo_list = NULL;
3128 player->video_bo_size = 0;
3129 MMPLAYER_VIDEO_BO_UNLOCK(player);
3136 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3139 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3140 gboolean ret = TRUE;
3142 /* check DRC, if it is, destroy the prev bo list to create again */
3143 if (player->video_bo_size != size) {
3144 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3145 __mmplayer_video_stream_destroy_bo_list(player);
3146 player->video_bo_size = size;
3149 MMPLAYER_VIDEO_BO_LOCK(player);
3151 if ((!player->video_bo_list) ||
3152 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3154 /* create bo list */
3156 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3158 if (player->video_bo_list) {
3159 /* if bo list did not created all, try it again. */
3160 idx = g_list_length(player->video_bo_list);
3161 LOGD("bo list exist(len: %d)", idx);
3164 for (; idx < player->ini.num_of_video_bo; idx++) {
3165 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3167 LOGE("Fail to alloc bo_info.");
3170 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3172 LOGE("Fail to tbm_bo_alloc.");
3173 MMPLAYER_FREEIF(bo_info);
3176 bo_info->used = FALSE;
3177 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3180 /* update video num buffers */
3181 LOGD("video_num_buffers : %d", idx);
3182 mm_player_set_attribute((MMHandleType)player, NULL,
3183 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3184 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3188 MMPLAYER_VIDEO_BO_UNLOCK(player);
3194 /* get bo from list*/
3195 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3196 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3197 if (tmp && (tmp->used == FALSE)) {
3198 LOGD("found bo %p to use", tmp->bo);
3200 MMPLAYER_VIDEO_BO_UNLOCK(player);
3201 return tbm_bo_ref(tmp->bo);
3205 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3206 MMPLAYER_VIDEO_BO_UNLOCK(player);
3210 if (player->ini.video_bo_timeout <= 0) {
3211 MMPLAYER_VIDEO_BO_WAIT(player);
3213 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3214 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3221 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3223 mmplayer_t *player = (mmplayer_t *)data;
3225 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3227 /* send prerolled pkt */
3228 player->video_stream_prerolled = false;
3230 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3232 /* not to send prerolled pkt again */
3233 player->video_stream_prerolled = true;
3237 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3239 mmplayer_t *player = (mmplayer_t *)data;
3240 mmplayer_video_decoded_data_info_t *stream = NULL;
3241 GstMemory *mem = NULL;
3244 MMPLAYER_RETURN_IF_FAIL(player);
3245 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3247 if (player->video_stream_prerolled) {
3248 player->video_stream_prerolled = false;
3249 LOGD("skip the prerolled pkt not to send it again");
3253 /* clear stream data structure */
3254 stream = __mmplayer_create_stream_from_pad(pad);
3256 LOGE("failed to alloc stream");
3260 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3262 /* set size and timestamp */
3263 mem = gst_buffer_peek_memory(buffer, 0);
3264 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3265 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3267 /* check zero-copy */
3268 if (player->set_mode.video_zc &&
3269 player->set_mode.video_export &&
3270 gst_is_tizen_memory(mem)) {
3271 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3272 stream->internal_buffer = gst_buffer_ref(buffer);
3273 } else { /* sw codec */
3274 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3277 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3281 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3282 LOGE("failed to send video decoded data.");
3289 LOGE("release video stream resource.");
3290 if (gst_is_tizen_memory(mem)) {
3292 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3294 tbm_bo_unref(stream->bo[i]);
3297 /* unref gst buffer */
3298 if (stream->internal_buffer)
3299 gst_buffer_unref(stream->internal_buffer);
3302 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3304 MMPLAYER_FREEIF(stream);
3309 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3311 mmplayer_gst_element_t *videobin = NULL;
3314 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3316 videobin = player->pipeline->videobin;
3318 /* Set spatial media metadata and/or user settings to the element.
3320 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3321 "projection-type", player->video360_metadata.projection_type, NULL);
3323 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3324 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3326 if (player->video360_metadata.full_pano_width_pixels &&
3327 player->video360_metadata.full_pano_height_pixels &&
3328 player->video360_metadata.cropped_area_image_width &&
3329 player->video360_metadata.cropped_area_image_height) {
3330 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3331 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3332 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3333 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3334 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3335 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3336 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3340 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3341 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3342 "horizontal-fov", player->video360_horizontal_fov,
3343 "vertical-fov", player->video360_vertical_fov, NULL);
3346 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3347 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3348 "zoom", 1.0f / player->video360_zoom, NULL);
3351 if (player->video360_yaw_radians <= M_PI &&
3352 player->video360_yaw_radians >= -M_PI &&
3353 player->video360_pitch_radians <= M_PI_2 &&
3354 player->video360_pitch_radians >= -M_PI_2) {
3355 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3356 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3357 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3358 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3359 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3360 "pose-yaw", player->video360_metadata.init_view_heading,
3361 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3364 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3365 "passthrough", !player->is_video360_enabled, NULL);
3372 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3374 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3375 GList *element_bucket = NULL;
3378 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3380 /* create video360 filter */
3381 if (player->is_360_feature_enabled && player->is_content_spherical) {
3382 LOGD("create video360 element");
3383 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3384 __mmplayer_gst_set_video360_property(player);
3388 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3389 LOGD("skip creating the videoconv and rotator");
3390 return MM_ERROR_NONE;
3393 /* in case of sw codec & overlay surface type, except 360 playback.
3394 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3395 LOGD("create video converter: %s", video_csc);
3396 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3399 *bucket = element_bucket;
3401 return MM_ERROR_NONE;
3403 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3404 g_list_free(element_bucket);
3408 return MM_ERROR_PLAYER_INTERNAL;
3412 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3414 gchar *factory_name = NULL;
3416 switch (surface_type) {
3417 case MM_DISPLAY_SURFACE_OVERLAY:
3418 if (strlen(player->ini.videosink_element_overlay) > 0)
3419 factory_name = player->ini.videosink_element_overlay;
3421 case MM_DISPLAY_SURFACE_REMOTE:
3422 case MM_DISPLAY_SURFACE_NULL:
3423 if (strlen(player->ini.videosink_element_fake) > 0)
3424 factory_name = player->ini.videosink_element_fake;
3427 LOGE("unidentified surface type");
3431 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3432 return factory_name;
3436 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3438 gchar *factory_name = NULL;
3439 mmplayer_gst_element_t *videobin = NULL;
3444 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3446 videobin = player->pipeline->videobin;
3447 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3449 attrs = MMPLAYER_GET_ATTRS(player);
3451 LOGE("cannot get content attribute");
3452 return MM_ERROR_PLAYER_INTERNAL;
3455 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3456 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3457 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3458 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3459 "use-tbm", use_tbm, NULL);
3462 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3463 return MM_ERROR_PLAYER_INTERNAL;
3465 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3468 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3469 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3472 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3474 LOGD("disable last-sample");
3475 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3478 if (player->set_mode.video_export) {
3480 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3481 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3482 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3484 _mmplayer_add_signal_connection(player,
3485 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3486 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3488 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3491 _mmplayer_add_signal_connection(player,
3492 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3493 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3495 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3499 if (videobin[MMPLAYER_V_SINK].gst) {
3500 GstPad *sink_pad = NULL;
3501 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3503 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3504 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3505 gst_object_unref(GST_OBJECT(sink_pad));
3507 LOGE("failed to get sink pad from videosink");
3511 return MM_ERROR_NONE;
3516 * - video overlay surface(arm/x86) : tizenwlsink
3519 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3522 GList *element_bucket = NULL;
3523 mmplayer_gst_element_t *first_element = NULL;
3524 mmplayer_gst_element_t *videobin = NULL;
3525 gchar *videosink_factory_name = NULL;
3528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3531 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3533 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3535 player->pipeline->videobin = videobin;
3538 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3539 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3540 if (!videobin[MMPLAYER_V_BIN].gst) {
3541 LOGE("failed to create videobin");
3545 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3548 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3549 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3551 /* additional setting for sink plug-in */
3552 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3553 LOGE("failed to set video property");
3557 /* store it as it's sink element */
3558 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3560 /* adding created elements to bin */
3561 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3562 LOGE("failed to add elements");
3566 /* Linking elements in the bucket by added order */
3567 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3568 LOGE("failed to link elements");
3572 /* get first element's sinkpad for creating ghostpad */
3573 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3574 if (!first_element) {
3575 LOGE("failed to get first element from bucket");
3579 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3581 LOGE("failed to get pad from first element");
3585 /* create ghostpad */
3586 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3587 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3588 LOGE("failed to add ghostpad to videobin");
3591 gst_object_unref(pad);
3593 /* done. free allocated variables */
3594 g_list_free(element_bucket);
3598 return MM_ERROR_NONE;
3601 LOGE("ERROR : releasing videobin");
3602 g_list_free(element_bucket);
3605 gst_object_unref(GST_OBJECT(pad));
3607 /* release videobin with it's childs */
3608 if (videobin[MMPLAYER_V_BIN].gst)
3609 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3611 MMPLAYER_FREEIF(videobin);
3612 player->pipeline->videobin = NULL;
3614 return MM_ERROR_PLAYER_INTERNAL;
3618 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3620 GList *element_bucket = NULL;
3621 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3623 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3624 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3625 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3626 "signal-handoffs", FALSE,
3629 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3630 _mmplayer_add_signal_connection(player,
3631 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3632 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3634 G_CALLBACK(__mmplayer_update_subtitle),
3637 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3638 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3640 if (!player->play_subtitle) {
3641 LOGD("add textbin sink as sink element of whole pipeline.");
3642 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3645 /* adding created elements to bin */
3646 LOGD("adding created elements to bin");
3647 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3648 LOGE("failed to add elements");
3652 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3653 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3654 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3656 /* linking elements in the bucket by added order. */
3657 LOGD("Linking elements in the bucket by added order.");
3658 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3659 LOGE("failed to link elements");
3663 /* done. free allocated variables */
3664 g_list_free(element_bucket);
3666 if (textbin[MMPLAYER_T_QUEUE].gst) {
3668 GstPad *ghostpad = NULL;
3670 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3672 LOGE("failed to get sink pad of text queue");
3676 ghostpad = gst_ghost_pad_new("text_sink", pad);
3677 gst_object_unref(pad);
3680 LOGE("failed to create ghostpad of textbin");
3684 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3685 LOGE("failed to add ghostpad to textbin");
3686 gst_object_unref(ghostpad);
3691 return MM_ERROR_NONE;
3694 g_list_free(element_bucket);
3696 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3697 LOGE("remove textbin sink from sink list");
3698 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3701 /* release element at __mmplayer_gst_create_text_sink_bin */
3702 return MM_ERROR_PLAYER_INTERNAL;
3706 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3708 mmplayer_gst_element_t *textbin = NULL;
3709 GList *element_bucket = NULL;
3710 int surface_type = 0;
3715 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3718 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3720 LOGE("failed to allocate memory for textbin");
3721 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3725 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3726 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3727 if (!textbin[MMPLAYER_T_BIN].gst) {
3728 LOGE("failed to create textbin");
3733 player->pipeline->textbin = textbin;
3736 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3737 LOGD("surface type for subtitle : %d", surface_type);
3738 switch (surface_type) {
3739 case MM_DISPLAY_SURFACE_OVERLAY:
3740 case MM_DISPLAY_SURFACE_NULL:
3741 case MM_DISPLAY_SURFACE_REMOTE:
3742 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3743 LOGE("failed to make plain text elements");
3754 return MM_ERROR_NONE;
3758 LOGD("ERROR : releasing textbin");
3760 g_list_free(element_bucket);
3762 /* release signal */
3763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3765 /* release element which are not added to bin */
3766 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3767 /* NOTE : skip bin */
3768 if (textbin[i].gst) {
3769 GstObject *parent = NULL;
3770 parent = gst_element_get_parent(textbin[i].gst);
3773 gst_object_unref(GST_OBJECT(textbin[i].gst));
3774 textbin[i].gst = NULL;
3776 gst_object_unref(GST_OBJECT(parent));
3781 /* release textbin with it's childs */
3782 if (textbin[MMPLAYER_T_BIN].gst)
3783 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3785 MMPLAYER_FREEIF(player->pipeline->textbin);
3786 player->pipeline->textbin = NULL;
3789 return MM_ERROR_PLAYER_INTERNAL;
3793 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3795 mmplayer_gst_element_t *mainbin = NULL;
3796 mmplayer_gst_element_t *textbin = NULL;
3797 MMHandleType attrs = 0;
3798 GstElement *subsrc = NULL;
3799 GstElement *subparse = NULL;
3800 gchar *subtitle_uri = NULL;
3801 const gchar *charset = NULL;
3807 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3809 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3811 mainbin = player->pipeline->mainbin;
3813 attrs = MMPLAYER_GET_ATTRS(player);
3815 LOGE("cannot get content attribute");
3816 return MM_ERROR_PLAYER_INTERNAL;
3819 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3820 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3821 LOGE("subtitle uri is not proper filepath.");
3822 return MM_ERROR_PLAYER_INVALID_URI;
3825 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3826 LOGE("failed to get storage info of subtitle path");
3827 return MM_ERROR_PLAYER_INVALID_URI;
3830 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3832 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3833 player->subtitle_language_list = NULL;
3834 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3836 /* create the subtitle source */
3837 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3839 LOGE("failed to create filesrc element");
3842 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3844 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3845 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3847 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3848 LOGW("failed to add queue");
3849 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3850 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3851 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3856 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3858 LOGE("failed to create subparse element");
3862 charset = _mmplayer_get_charset(subtitle_uri);
3864 LOGD("detected charset is %s", charset);
3865 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3868 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3869 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3871 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3872 LOGW("failed to add subparse");
3873 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3874 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3875 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3879 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3880 LOGW("failed to link subsrc and subparse");
3884 player->play_subtitle = TRUE;
3885 player->adjust_subtitle_pos = 0;
3887 LOGD("play subtitle using subtitle file");
3889 if (player->pipeline->textbin == NULL) {
3890 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3891 LOGE("failed to create text sink bin. continuing without text");
3895 textbin = player->pipeline->textbin;
3897 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3898 LOGW("failed to add textbin");
3900 /* release signal */
3901 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3903 /* release textbin with it's childs */
3904 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3905 MMPLAYER_FREEIF(player->pipeline->textbin);
3906 player->pipeline->textbin = textbin = NULL;
3910 LOGD("link text input selector and textbin ghost pad");
3912 player->textsink_linked = 1;
3913 player->external_text_idx = 0;
3914 LOGI("textsink is linked");
3916 textbin = player->pipeline->textbin;
3917 LOGD("text bin has been created. reuse it.");
3918 player->external_text_idx = 1;
3921 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3922 LOGW("failed to link subparse and textbin");
3926 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3928 LOGE("failed to get sink pad from textsink to probe data");
3932 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3933 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3935 gst_object_unref(pad);
3938 /* create dot. for debugging */
3939 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3942 return MM_ERROR_NONE;
3945 /* release text pipeline resource */
3946 player->textsink_linked = 0;
3948 /* release signal */
3949 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3951 if (player->pipeline->textbin) {
3952 LOGE("remove textbin");
3954 /* release textbin with it's childs */
3955 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3956 MMPLAYER_FREEIF(player->pipeline->textbin);
3957 player->pipeline->textbin = NULL;
3961 /* release subtitle elem */
3962 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3963 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3965 return MM_ERROR_PLAYER_INTERNAL;
3969 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3971 mmplayer_t *player = (mmplayer_t *)data;
3972 MMMessageParamType msg = {0, };
3973 GstClockTime duration = 0;
3974 gpointer text = NULL;
3975 guint text_size = 0;
3976 gboolean ret = TRUE;
3977 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3981 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3982 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3984 if (player->is_subtitle_force_drop) {
3985 LOGW("subtitle is dropped forcedly.");
3989 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3990 text = mapinfo.data;
3991 text_size = mapinfo.size;
3993 if (player->set_mode.subtitle_off) {
3994 LOGD("subtitle is OFF.");
3998 if (!text || (text_size == 0)) {
3999 LOGD("There is no subtitle to be displayed.");
4003 msg.data = (void *)text;
4005 duration = GST_BUFFER_DURATION(buffer);
4007 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4008 if (player->duration > GST_BUFFER_PTS(buffer))
4009 duration = player->duration - GST_BUFFER_PTS(buffer);
4012 LOGI("subtitle duration is invalid, subtitle duration change "
4013 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4015 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4017 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4019 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4020 gst_buffer_unmap(buffer, &mapinfo);
4027 static GstPadProbeReturn
4028 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4030 mmplayer_t *player = (mmplayer_t *)u_data;
4031 GstClockTime cur_timestamp = 0;
4032 gint64 adjusted_timestamp = 0;
4033 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4035 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4037 if (player->set_mode.subtitle_off) {
4038 LOGD("subtitle is OFF.");
4042 if (player->adjust_subtitle_pos == 0) {
4043 LOGD("nothing to do");
4047 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4048 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4050 if (adjusted_timestamp < 0) {
4051 LOGD("adjusted_timestamp under zero");
4056 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4057 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4058 GST_TIME_ARGS(cur_timestamp),
4059 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4061 return GST_PAD_PROBE_OK;
4065 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4069 /* check player and subtitlebin are created */
4070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4071 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4073 if (position == 0) {
4074 LOGD("nothing to do");
4076 return MM_ERROR_NONE;
4079 /* check current postion */
4080 player->adjust_subtitle_pos = position;
4082 LOGD("save adjust_subtitle_pos in player");
4086 return MM_ERROR_NONE;
4090 * This function is to create audio or video pipeline for playing.
4092 * @param player [in] handle of player
4094 * @return This function returns zero on success.
4099 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4101 int ret = MM_ERROR_NONE;
4102 mmplayer_gst_element_t *mainbin = NULL;
4103 MMHandleType attrs = 0;
4106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4108 /* get profile attribute */
4109 attrs = MMPLAYER_GET_ATTRS(player);
4111 LOGE("failed to get content attribute");
4115 /* create pipeline handles */
4116 if (player->pipeline) {
4117 LOGE("pipeline should be released before create new one");
4121 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4123 /* create mainbin */
4124 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4125 if (mainbin == NULL)
4128 /* create pipeline */
4129 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4130 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4131 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4132 LOGE("failed to create pipeline");
4137 player->pipeline->mainbin = mainbin;
4139 /* create the source and decoder elements */
4140 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4141 ret = _mmplayer_gst_build_es_pipeline(player);
4143 ret = _mmplayer_gst_build_pipeline(player);
4145 if (ret != MM_ERROR_NONE) {
4146 LOGE("failed to create some elements");
4150 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4151 if (__mmplayer_check_subtitle(player)
4152 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4153 LOGE("failed to create text pipeline");
4156 ret = _mmplayer_gst_add_bus_watch(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to add bus watch");
4163 return MM_ERROR_NONE;
4166 __mmplayer_gst_destroy_pipeline(player);
4167 return MM_ERROR_PLAYER_INTERNAL;
4171 __mmplayer_reset_gapless_state(mmplayer_t *player)
4174 MMPLAYER_RETURN_IF_FAIL(player
4176 && player->pipeline->audiobin
4177 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4179 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4186 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4189 int ret = MM_ERROR_NONE;
4193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4195 /* cleanup stuffs */
4196 MMPLAYER_FREEIF(player->type);
4197 player->no_more_pad = FALSE;
4198 player->num_dynamic_pad = 0;
4199 player->demux_pad_index = 0;
4201 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4202 player->subtitle_language_list = NULL;
4203 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4205 __mmplayer_reset_gapless_state(player);
4207 if (player->streamer) {
4208 _mm_player_streaming_initialize(player->streamer, FALSE);
4209 _mm_player_streaming_destroy(player->streamer);
4210 player->streamer = NULL;
4213 /* cleanup unlinked mime type */
4214 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4215 MMPLAYER_FREEIF(player->unlinked_video_mime);
4216 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4218 /* cleanup running stuffs */
4219 _mmplayer_cancel_eos_timer(player);
4221 /* cleanup gst stuffs */
4222 if (player->pipeline) {
4223 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4224 GstTagList *tag_list = player->pipeline->tag_list;
4226 /* first we need to disconnect all signal hander */
4227 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4230 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4231 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4232 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4233 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4234 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4235 gst_object_unref(bus);
4237 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4238 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4239 if (ret != MM_ERROR_NONE) {
4240 LOGE("fail to change state to NULL");
4241 return MM_ERROR_PLAYER_INTERNAL;
4244 LOGW("succeeded in changing state to NULL");
4246 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4249 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4250 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4252 /* free avsysaudiosink
4253 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4254 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4256 MMPLAYER_FREEIF(audiobin);
4257 MMPLAYER_FREEIF(videobin);
4258 MMPLAYER_FREEIF(textbin);
4259 MMPLAYER_FREEIF(mainbin);
4263 gst_tag_list_unref(tag_list);
4265 MMPLAYER_FREEIF(player->pipeline);
4267 MMPLAYER_FREEIF(player->album_art);
4269 if (player->v_stream_caps) {
4270 gst_caps_unref(player->v_stream_caps);
4271 player->v_stream_caps = NULL;
4274 if (player->a_stream_caps) {
4275 gst_caps_unref(player->a_stream_caps);
4276 player->a_stream_caps = NULL;
4279 if (player->s_stream_caps) {
4280 gst_caps_unref(player->s_stream_caps);
4281 player->s_stream_caps = NULL;
4283 _mmplayer_track_destroy(player);
4285 if (player->sink_elements)
4286 g_list_free(player->sink_elements);
4287 player->sink_elements = NULL;
4289 if (player->bufmgr) {
4290 tbm_bufmgr_deinit(player->bufmgr);
4291 player->bufmgr = NULL;
4294 LOGW("finished destroy pipeline");
4302 __mmplayer_gst_realize(mmplayer_t *player)
4305 int ret = MM_ERROR_NONE;
4309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4311 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4313 ret = __mmplayer_gst_create_pipeline(player);
4315 LOGE("failed to create pipeline");
4319 /* set pipeline state to READY */
4320 /* NOTE : state change to READY must be performed sync. */
4321 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4322 ret = _mmplayer_gst_set_state(player,
4323 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4325 if (ret != MM_ERROR_NONE) {
4326 /* return error if failed to set state */
4327 LOGE("failed to set READY state");
4331 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4333 /* create dot before error-return. for debugging */
4334 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4342 __mmplayer_gst_unrealize(mmplayer_t *player)
4344 int ret = MM_ERROR_NONE;
4348 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4350 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4351 MMPLAYER_PRINT_STATE(player);
4353 /* release miscellaneous information */
4354 __mmplayer_release_misc(player);
4356 /* destroy pipeline */
4357 ret = __mmplayer_gst_destroy_pipeline(player);
4358 if (ret != MM_ERROR_NONE) {
4359 LOGE("failed to destory pipeline");
4363 /* release miscellaneous information.
4364 these info needs to be released after pipeline is destroyed. */
4365 __mmplayer_release_misc_post(player);
4367 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4375 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4380 LOGW("set_message_callback is called with invalid player handle");
4381 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4384 player->msg_cb = callback;
4385 player->msg_cb_param = user_param;
4387 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4391 return MM_ERROR_NONE;
4395 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4397 int ret = MM_ERROR_NONE;
4402 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4403 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4404 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4406 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4408 if (strstr(uri, "es_buff://")) {
4409 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4410 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4411 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4412 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4414 tmp = g_ascii_strdown(uri, strlen(uri));
4415 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4416 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4418 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4420 } else if (strstr(uri, "mms://")) {
4421 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4422 } else if ((path = strstr(uri, "mem://"))) {
4423 ret = __mmplayer_set_mem_uri(data, path, param);
4425 ret = __mmplayer_set_file_uri(data, uri);
4428 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4429 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4430 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4431 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4433 /* dump parse result */
4434 SECURE_LOGW("incoming uri : %s", uri);
4435 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4436 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4444 __mmplayer_can_do_interrupt(mmplayer_t *player)
4446 if (!player || !player->pipeline || !player->attrs) {
4447 LOGW("not initialized");
4451 if (player->audio_decoded_cb) {
4452 LOGW("not support in pcm extraction mode");
4456 /* check if seeking */
4457 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4458 MMMessageParamType msg_param;
4459 memset(&msg_param, 0, sizeof(MMMessageParamType));
4460 msg_param.code = MM_ERROR_PLAYER_SEEK;
4461 player->seek_state = MMPLAYER_SEEK_NONE;
4462 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4466 /* check other thread */
4467 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4468 LOGW("locked already, cmd state : %d", player->cmd);
4470 /* check application command */
4471 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4472 LOGW("playing.. should wait cmd lock then, will be interrupted");
4474 /* lock will be released at mrp_resource_release_cb() */
4475 MMPLAYER_CMD_LOCK(player);
4478 LOGW("nothing to do");
4481 LOGW("can interrupt immediately");
4485 FAILED: /* with CMD UNLOCKED */
4488 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4493 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4496 mmplayer_t *player = NULL;
4497 MMMessageParamType msg = {0, };
4499 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4504 LOGE("user_data is null");
4507 player = (mmplayer_t *)user_data;
4509 if (!__mmplayer_can_do_interrupt(player)) {
4510 LOGW("no need to interrupt, so leave");
4511 /* FIXME: there is no way to avoid releasing resource. */
4515 player->interrupted_by_resource = TRUE;
4517 /* get last play position */
4518 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4519 msg.union_type = MM_MSG_UNION_TIME;
4520 msg.time.elapsed = pos;
4521 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4523 LOGW("failed to get play position.");
4526 LOGD("video resource conflict so, resource will be freed by unrealizing");
4527 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4528 LOGE("failed to unrealize");
4530 /* lock is called in __mmplayer_can_do_interrupt() */
4531 MMPLAYER_CMD_UNLOCK(player);
4533 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4534 player->hw_resource[res_idx] = NULL;
4538 return TRUE; /* release all the resources */
4542 __mmplayer_initialize_video_roi(mmplayer_t *player)
4544 player->video_roi.scale_x = 0.0;
4545 player->video_roi.scale_y = 0.0;
4546 player->video_roi.scale_width = 1.0;
4547 player->video_roi.scale_height = 1.0;
4551 _mmplayer_create_player(MMHandleType handle)
4553 int ret = MM_ERROR_PLAYER_INTERNAL;
4554 bool enabled = false;
4556 mmplayer_t *player = MM_PLAYER_CAST(handle);
4560 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4562 /* initialize player state */
4563 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4564 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4565 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4566 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4568 /* check current state */
4569 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4571 /* construct attributes */
4572 player->attrs = _mmplayer_construct_attribute(handle);
4574 if (!player->attrs) {
4575 LOGE("Failed to construct attributes");
4579 /* initialize gstreamer with configured parameter */
4580 if (!__mmplayer_init_gstreamer(player)) {
4581 LOGE("Initializing gstreamer failed");
4582 _mmplayer_deconstruct_attribute(handle);
4586 /* create lock. note that g_tread_init() has already called in gst_init() */
4587 g_mutex_init(&player->fsink_lock);
4589 /* create update tag lock */
4590 g_mutex_init(&player->update_tag_lock);
4592 /* create gapless play mutex */
4593 g_mutex_init(&player->gapless_play_thread_mutex);
4595 /* create gapless play cond */
4596 g_cond_init(&player->gapless_play_thread_cond);
4598 /* create gapless play thread */
4599 player->gapless_play_thread =
4600 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4601 if (!player->gapless_play_thread) {
4602 LOGE("failed to create gapless play thread");
4603 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4604 g_mutex_clear(&player->gapless_play_thread_mutex);
4605 g_cond_clear(&player->gapless_play_thread_cond);
4609 player->bus_msg_q = g_queue_new();
4610 if (!player->bus_msg_q) {
4611 LOGE("failed to create queue for bus_msg");
4612 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4616 ret = _mmplayer_initialize_video_capture(player);
4617 if (ret != MM_ERROR_NONE) {
4618 LOGE("failed to initialize video capture");
4622 /* initialize resource manager */
4623 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4624 __resource_release_cb, player, &player->resource_manager)
4625 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4626 LOGE("failed to initialize resource manager");
4627 ret = MM_ERROR_PLAYER_INTERNAL;
4631 /* create video bo lock and cond */
4632 g_mutex_init(&player->video_bo_mutex);
4633 g_cond_init(&player->video_bo_cond);
4635 /* create subtitle info lock and cond */
4636 g_mutex_init(&player->subtitle_info_mutex);
4637 g_cond_init(&player->subtitle_info_cond);
4639 player->streaming_type = STREAMING_SERVICE_NONE;
4641 /* give default value of audio effect setting */
4642 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4643 player->sound.rg_enable = false;
4644 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4646 player->play_subtitle = FALSE;
4647 player->has_closed_caption = FALSE;
4648 player->pending_resume = FALSE;
4649 if (player->ini.dump_element_keyword[0][0] == '\0')
4650 player->ini.set_dump_element_flag = FALSE;
4652 player->ini.set_dump_element_flag = TRUE;
4654 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4655 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4656 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4658 /* Set video360 settings to their defaults for just-created player.
4661 player->is_360_feature_enabled = FALSE;
4662 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4663 LOGI("spherical feature info: %d", enabled);
4665 player->is_360_feature_enabled = TRUE;
4667 LOGE("failed to get spherical feature info");
4670 player->is_content_spherical = FALSE;
4671 player->is_video360_enabled = TRUE;
4672 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4673 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4674 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4675 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4676 player->video360_zoom = 1.0f;
4677 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4678 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4680 __mmplayer_initialize_video_roi(player);
4682 /* set player state to null */
4683 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4684 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4688 return MM_ERROR_NONE;
4692 g_mutex_clear(&player->fsink_lock);
4693 /* free update tag lock */
4694 g_mutex_clear(&player->update_tag_lock);
4695 g_queue_free(player->bus_msg_q);
4696 player->bus_msg_q = NULL;
4697 /* free gapless play thread */
4698 if (player->gapless_play_thread) {
4699 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4700 player->gapless_play_thread_exit = TRUE;
4701 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4702 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4704 g_thread_join(player->gapless_play_thread);
4705 player->gapless_play_thread = NULL;
4707 g_mutex_clear(&player->gapless_play_thread_mutex);
4708 g_cond_clear(&player->gapless_play_thread_cond);
4711 /* release attributes */
4712 _mmplayer_deconstruct_attribute(handle);
4720 __mmplayer_init_gstreamer(mmplayer_t *player)
4722 static gboolean initialized = FALSE;
4723 static const int max_argc = 50;
4725 gchar **argv = NULL;
4726 gchar **argv2 = NULL;
4732 LOGD("gstreamer already initialized.");
4737 argc = malloc(sizeof(int));
4738 argv = malloc(sizeof(gchar *) * max_argc);
4739 argv2 = malloc(sizeof(gchar *) * max_argc);
4741 if (!argc || !argv || !argv2)
4744 memset(argv, 0, sizeof(gchar *) * max_argc);
4745 memset(argv2, 0, sizeof(gchar *) * max_argc);
4749 argv[0] = g_strdup("mmplayer");
4752 for (i = 0; i < 5; i++) {
4753 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4754 if (strlen(player->ini.gst_param[i]) > 0) {
4755 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4760 /* we would not do fork for scanning plugins */
4761 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4764 /* check disable registry scan */
4765 if (player->ini.skip_rescan) {
4766 argv[*argc] = g_strdup("--gst-disable-registry-update");
4770 /* check disable segtrap */
4771 if (player->ini.disable_segtrap) {
4772 argv[*argc] = g_strdup("--gst-disable-segtrap");
4776 LOGD("initializing gstreamer with following parameter");
4777 LOGD("argc : %d", *argc);
4780 for (i = 0; i < arg_count; i++) {
4782 LOGD("argv[%d] : %s", i, argv2[i]);
4785 /* initializing gstreamer */
4786 if (!gst_init_check(argc, &argv, &err)) {
4787 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4794 for (i = 0; i < arg_count; i++) {
4796 LOGD("release - argv[%d] : %s", i, argv2[i]);
4798 MMPLAYER_FREEIF(argv2[i]);
4801 MMPLAYER_FREEIF(argv);
4802 MMPLAYER_FREEIF(argv2);
4803 MMPLAYER_FREEIF(argc);
4813 for (i = 0; i < arg_count; i++) {
4814 LOGD("free[%d] : %s", i, argv2[i]);
4815 MMPLAYER_FREEIF(argv2[i]);
4818 MMPLAYER_FREEIF(argv);
4819 MMPLAYER_FREEIF(argv2);
4820 MMPLAYER_FREEIF(argc);
4826 __mmplayer_check_async_state_transition(mmplayer_t *player)
4828 GstState element_state = GST_STATE_VOID_PENDING;
4829 GstState element_pending_state = GST_STATE_VOID_PENDING;
4830 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4831 GstElement *element = NULL;
4832 gboolean async = FALSE;
4834 /* check player handle */
4835 MMPLAYER_RETURN_IF_FAIL(player &&
4837 player->pipeline->mainbin &&
4838 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4841 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4843 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4844 LOGD("don't need to check the pipeline state");
4848 MMPLAYER_PRINT_STATE(player);
4850 /* wait for state transition */
4851 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4852 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4854 if (ret == GST_STATE_CHANGE_FAILURE) {
4855 LOGE(" [%s] state : %s pending : %s",
4856 GST_ELEMENT_NAME(element),
4857 gst_element_state_get_name(element_state),
4858 gst_element_state_get_name(element_pending_state));
4860 /* dump state of all element */
4861 _mmplayer_dump_pipeline_state(player);
4866 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4871 _mmplayer_destroy(MMHandleType handle)
4873 mmplayer_t *player = MM_PLAYER_CAST(handle);
4877 /* check player handle */
4878 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4880 /* destroy can called at anytime */
4881 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4883 /* check async state transition */
4884 __mmplayer_check_async_state_transition(player);
4886 /* release gapless play thread */
4887 if (player->gapless_play_thread) {
4888 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4889 player->gapless_play_thread_exit = TRUE;
4890 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4891 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4893 LOGD("waitting for gapless play thread exit");
4894 g_thread_join(player->gapless_play_thread);
4895 g_mutex_clear(&player->gapless_play_thread_mutex);
4896 g_cond_clear(&player->gapless_play_thread_cond);
4897 LOGD("gapless play thread released");
4900 _mmplayer_release_video_capture(player);
4902 /* de-initialize resource manager */
4903 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4904 player->resource_manager))
4905 LOGE("failed to deinitialize resource manager");
4907 /* release pipeline */
4908 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4909 LOGE("failed to destory pipeline");
4910 return MM_ERROR_PLAYER_INTERNAL;
4913 g_queue_free(player->bus_msg_q);
4915 /* release subtitle info lock and cond */
4916 g_mutex_clear(&player->subtitle_info_mutex);
4917 g_cond_clear(&player->subtitle_info_cond);
4919 __mmplayer_release_dump_list(player->dump_list);
4921 /* release miscellaneous information */
4922 __mmplayer_release_misc(player);
4924 /* release miscellaneous information.
4925 these info needs to be released after pipeline is destroyed. */
4926 __mmplayer_release_misc_post(player);
4928 /* release attributes */
4929 _mmplayer_deconstruct_attribute(handle);
4932 g_mutex_clear(&player->fsink_lock);
4935 g_mutex_clear(&player->update_tag_lock);
4937 /* release video bo lock and cond */
4938 g_mutex_clear(&player->video_bo_mutex);
4939 g_cond_clear(&player->video_bo_cond);
4943 return MM_ERROR_NONE;
4947 _mmplayer_realize(MMHandleType hplayer)
4949 mmplayer_t *player = (mmplayer_t *)hplayer;
4950 int ret = MM_ERROR_NONE;
4953 MMHandleType attrs = 0;
4954 int video_codec_type = 0;
4955 int audio_codec_type = 0;
4956 int default_codec_type = 0;
4959 /* check player handle */
4960 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4962 /* check current state */
4963 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4965 attrs = MMPLAYER_GET_ATTRS(player);
4967 LOGE("fail to get attributes.");
4968 return MM_ERROR_PLAYER_INTERNAL;
4970 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4971 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4973 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4974 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4976 if (ret != MM_ERROR_NONE) {
4977 LOGE("failed to parse profile");
4982 if (uri && (strstr(uri, "es_buff://"))) {
4983 if (strstr(uri, "es_buff://push_mode"))
4984 player->es_player_push_mode = TRUE;
4986 player->es_player_push_mode = FALSE;
4989 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4990 LOGW("mms protocol is not supported format.");
4991 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4994 if (MMPLAYER_IS_STREAMING(player))
4995 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4997 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4999 player->smooth_streaming = FALSE;
5000 player->videodec_linked = 0;
5001 player->audiodec_linked = 0;
5002 player->textsink_linked = 0;
5003 player->is_external_subtitle_present = FALSE;
5004 player->is_external_subtitle_added_now = FALSE;
5005 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5006 player->video360_metadata.is_spherical = -1;
5007 player->is_openal_plugin_used = FALSE;
5008 player->demux_pad_index = 0;
5009 player->subtitle_language_list = NULL;
5010 player->is_subtitle_force_drop = FALSE;
5012 _mmplayer_track_initialize(player);
5013 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5015 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5016 gint prebuffer_ms = 0, rebuffer_ms = 0;
5018 player->streamer = _mm_player_streaming_create();
5019 _mm_player_streaming_initialize(player->streamer, TRUE);
5021 mm_attrs_multiple_get(player->attrs, NULL,
5022 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5023 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5025 if (prebuffer_ms > 0) {
5026 prebuffer_ms = MAX(prebuffer_ms, 1000);
5027 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5030 if (rebuffer_ms > 0) {
5031 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5032 rebuffer_ms = MAX(rebuffer_ms, 1000);
5033 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5036 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5037 player->streamer->buffering_req.rebuffer_time);
5040 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
5041 if (!strcmp(player->ini.audiocodec_default_type, "hw"))
5042 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
5044 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
5046 if (audio_codec_type != default_codec_type) {
5047 LOGD("audio dec sorting is required");
5048 player->need_audio_dec_sorting = TRUE;
5051 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
5052 if (video_codec_type != MM_PLAYER_CODEC_TYPE_DEFAULT) {
5053 LOGD("video dec sorting is required");
5054 player->need_video_dec_sorting = TRUE;
5057 /* realize pipeline */
5058 ret = __mmplayer_gst_realize(player);
5059 if (ret != MM_ERROR_NONE)
5060 LOGE("fail to realize the player.");
5062 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5070 _mmplayer_unrealize(MMHandleType hplayer)
5072 mmplayer_t *player = (mmplayer_t *)hplayer;
5073 int ret = MM_ERROR_NONE;
5077 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5079 MMPLAYER_CMD_UNLOCK(player);
5080 /* destroy the gst bus msg thread which is created during realize.
5081 this funct have to be called before getting cmd lock. */
5082 _mmplayer_bus_msg_thread_destroy(player);
5083 MMPLAYER_CMD_LOCK(player);
5085 /* check current state */
5086 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5088 /* check async state transition */
5089 __mmplayer_check_async_state_transition(player);
5091 /* unrealize pipeline */
5092 ret = __mmplayer_gst_unrealize(player);
5094 if (!player->interrupted_by_resource) {
5095 int rm_ret = MM_ERROR_NONE;
5096 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5098 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5099 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5100 if (rm_ret != MM_ERROR_NONE)
5101 LOGE("failed to release [%d] resources", res_idx);
5110 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5112 mmplayer_t *player = (mmplayer_t *)hplayer;
5114 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5116 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5120 _mmplayer_get_state(MMHandleType hplayer, int *state)
5122 mmplayer_t *player = (mmplayer_t *)hplayer;
5124 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5126 *state = MMPLAYER_CURRENT_STATE(player);
5128 return MM_ERROR_NONE;
5132 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5134 GstElement *vol_element = NULL;
5135 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5138 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5139 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5141 /* check pipeline handle */
5142 if (!player->pipeline || !player->pipeline->audiobin) {
5143 LOGD("'%s' will be applied when audiobin is created", prop_name);
5145 /* NOTE : stored value will be used in create_audiobin
5146 * returning MM_ERROR_NONE here makes application to able to
5147 * set audio volume or mute at anytime.
5149 return MM_ERROR_NONE;
5152 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5153 volume_elem_id = MMPLAYER_A_SINK;
5155 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5157 LOGE("failed to get vol element %d", volume_elem_id);
5158 return MM_ERROR_PLAYER_INTERNAL;
5161 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5163 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5164 LOGE("there is no '%s' property", prop_name);
5165 return MM_ERROR_PLAYER_INTERNAL;
5168 if (!strcmp(prop_name, "volume")) {
5169 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5170 } else if (!strcmp(prop_name, "mute")) {
5171 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5173 LOGE("invalid property %s", prop_name);
5174 return MM_ERROR_PLAYER_INTERNAL;
5177 return MM_ERROR_NONE;
5181 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5183 int ret = MM_ERROR_NONE;
5184 mmplayer_t *player = (mmplayer_t *)hplayer;
5187 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5189 LOGD("volume = %f", volume);
5191 /* invalid factor range or not */
5192 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5193 LOGE("Invalid volume value");
5194 return MM_ERROR_INVALID_ARGUMENT;
5197 player->sound.volume = volume;
5199 ret = __mmplayer_gst_set_volume_property(player, "volume");
5206 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5208 mmplayer_t *player = (mmplayer_t *)hplayer;
5212 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5213 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5215 *volume = player->sound.volume;
5217 LOGD("current vol = %f", *volume);
5220 return MM_ERROR_NONE;
5224 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5226 int ret = MM_ERROR_NONE;
5227 mmplayer_t *player = (mmplayer_t *)hplayer;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5232 LOGD("mute = %d", mute);
5234 player->sound.mute = mute;
5236 ret = __mmplayer_gst_set_volume_property(player, "mute");
5243 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5245 mmplayer_t *player = (mmplayer_t *)hplayer;
5249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5250 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5252 *mute = player->sound.mute;
5254 LOGD("current mute = %d", *mute);
5258 return MM_ERROR_NONE;
5262 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5264 mmplayer_t *player = (mmplayer_t *)hplayer;
5268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5270 player->audio_stream_changed_cb = callback;
5271 player->audio_stream_changed_cb_user_param = user_param;
5272 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 player->audio_decoded_cb = callback;
5289 player->audio_decoded_cb_user_param = user_param;
5290 player->audio_extract_opt = opt;
5291 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5295 return MM_ERROR_NONE;
5299 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5301 mmplayer_t *player = (mmplayer_t *)hplayer;
5305 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5307 if (callback && !player->bufmgr)
5308 player->bufmgr = tbm_bufmgr_init(-1);
5310 player->set_mode.video_export = (callback) ? true : false;
5311 player->video_decoded_cb = callback;
5312 player->video_decoded_cb_user_param = user_param;
5314 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5318 return MM_ERROR_NONE;
5322 _mmplayer_start(MMHandleType hplayer)
5324 mmplayer_t *player = (mmplayer_t *)hplayer;
5325 gint ret = MM_ERROR_NONE;
5329 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5331 /* check current state */
5332 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5334 /* start pipeline */
5335 ret = _mmplayer_gst_start(player);
5336 if (ret != MM_ERROR_NONE)
5337 LOGE("failed to start player.");
5339 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5340 LOGD("force playing start even during buffering");
5341 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5349 /* NOTE: post "not supported codec message" to application
5350 * when one codec is not found during AUTOPLUGGING in MSL.
5351 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5352 * And, if any codec is not found, don't send message here.
5353 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5356 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5358 MMMessageParamType msg_param;
5359 memset(&msg_param, 0, sizeof(MMMessageParamType));
5360 gboolean post_msg_direct = FALSE;
5364 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5366 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5367 player->not_supported_codec, player->can_support_codec);
5369 if (player->not_found_demuxer) {
5370 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5371 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5373 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5374 MMPLAYER_FREEIF(msg_param.data);
5376 return MM_ERROR_NONE;
5379 if (player->not_supported_codec) {
5380 if (player->can_support_codec) {
5381 // There is one codec to play
5382 post_msg_direct = TRUE;
5384 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5385 post_msg_direct = TRUE;
5388 if (post_msg_direct) {
5389 MMMessageParamType msg_param;
5390 memset(&msg_param, 0, sizeof(MMMessageParamType));
5392 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5393 LOGW("not found AUDIO codec, posting error code to application.");
5395 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5396 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5397 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5398 LOGW("not found VIDEO codec, posting error code to application.");
5400 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5401 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5404 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5406 MMPLAYER_FREEIF(msg_param.data);
5408 return MM_ERROR_NONE;
5410 // no any supported codec case
5411 LOGW("not found any codec, posting error code to application.");
5413 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5414 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5415 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5417 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5418 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5421 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5423 MMPLAYER_FREEIF(msg_param.data);
5429 return MM_ERROR_NONE;
5433 __mmplayer_check_pipeline(mmplayer_t *player)
5435 GstState element_state = GST_STATE_VOID_PENDING;
5436 GstState element_pending_state = GST_STATE_VOID_PENDING;
5438 int ret = MM_ERROR_NONE;
5440 if (!player->gapless.reconfigure)
5443 LOGW("pipeline is under construction.");
5445 MMPLAYER_PLAYBACK_LOCK(player);
5446 MMPLAYER_PLAYBACK_UNLOCK(player);
5448 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5450 /* wait for state transition */
5451 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5452 if (ret == GST_STATE_CHANGE_FAILURE)
5453 LOGE("failed to change pipeline state within %d sec", timeout);
5456 /* NOTE : it should be able to call 'stop' anytime*/
5458 _mmplayer_stop(MMHandleType hplayer)
5460 mmplayer_t *player = (mmplayer_t *)hplayer;
5461 int ret = MM_ERROR_NONE;
5465 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5467 /* check current state */
5468 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5470 /* check pipline building state */
5471 __mmplayer_check_pipeline(player);
5472 __mmplayer_reset_gapless_state(player);
5474 /* NOTE : application should not wait for EOS after calling STOP */
5475 _mmplayer_cancel_eos_timer(player);
5478 player->seek_state = MMPLAYER_SEEK_NONE;
5481 ret = _mmplayer_gst_stop(player);
5483 if (ret != MM_ERROR_NONE)
5484 LOGE("failed to stop player.");
5492 _mmplayer_pause(MMHandleType hplayer)
5494 mmplayer_t *player = (mmplayer_t *)hplayer;
5495 gint64 pos_nsec = 0;
5496 gboolean async = FALSE;
5497 gint ret = MM_ERROR_NONE;
5501 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5503 /* check current state */
5504 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5506 /* check pipline building state */
5507 __mmplayer_check_pipeline(player);
5509 switch (MMPLAYER_CURRENT_STATE(player)) {
5510 case MM_PLAYER_STATE_READY:
5512 /* check prepare async or not.
5513 * In the case of streaming playback, it's recommned to avoid blocking wait.
5515 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5516 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5518 /* Changing back sync of rtspsrc to async */
5519 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5520 LOGD("async prepare working mode for rtsp");
5526 case MM_PLAYER_STATE_PLAYING:
5528 /* NOTE : store current point to overcome some bad operation
5529 *(returning zero when getting current position in paused state) of some
5532 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5533 LOGW("getting current position failed in paused");
5535 player->last_position = pos_nsec;
5537 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5538 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5539 This causes problem is position calculation during normal pause resume scenarios also.
5540 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5541 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5542 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5543 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5549 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5550 LOGD("doing async pause in case of ms buff src");
5554 /* pause pipeline */
5555 ret = _mmplayer_gst_pause(player, async);
5557 if (ret != MM_ERROR_NONE)
5558 LOGE("failed to pause player. ret : 0x%x", ret);
5560 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5561 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5562 LOGE("failed to update display_rotation");
5570 /* in case of streaming, pause could take long time.*/
5572 _mmplayer_abort_pause(MMHandleType hplayer)
5574 mmplayer_t *player = (mmplayer_t *)hplayer;
5575 int ret = MM_ERROR_NONE;
5579 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5581 player->pipeline->mainbin,
5582 MM_ERROR_PLAYER_NOT_INITIALIZED);
5584 LOGD("set the pipeline state to READY");
5586 /* set state to READY */
5587 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5588 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5589 if (ret != MM_ERROR_NONE) {
5590 LOGE("fail to change state to READY");
5591 return MM_ERROR_PLAYER_INTERNAL;
5594 LOGD("succeeded in changing state to READY");
5599 _mmplayer_resume(MMHandleType hplayer)
5601 mmplayer_t *player = (mmplayer_t *)hplayer;
5602 int ret = MM_ERROR_NONE;
5603 gboolean async = FALSE;
5607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5609 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5610 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5611 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5615 /* Changing back sync mode rtspsrc to async */
5616 LOGD("async resume for rtsp case");
5620 /* check current state */
5621 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5623 ret = _mmplayer_gst_resume(player, async);
5624 if (ret != MM_ERROR_NONE)
5625 LOGE("failed to resume player.");
5627 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5628 LOGD("force resume even during buffering");
5629 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5638 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5640 mmplayer_t *player = (mmplayer_t *)hplayer;
5641 gint64 pos_nsec = 0;
5642 int ret = MM_ERROR_NONE;
5644 signed long long start = 0, stop = 0;
5645 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5648 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5649 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5651 /* The sound of video is not supported under 0.0 and over 2.0. */
5652 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5653 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5656 _mmplayer_set_mute(hplayer, mute);
5658 if (player->playback_rate == rate)
5659 return MM_ERROR_NONE;
5661 /* If the position is reached at start potion during fast backward, EOS is posted.
5662 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5664 player->playback_rate = rate;
5666 current_state = MMPLAYER_CURRENT_STATE(player);
5668 if (current_state != MM_PLAYER_STATE_PAUSED)
5669 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5671 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5673 if ((current_state == MM_PLAYER_STATE_PAUSED)
5674 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5675 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5676 pos_nsec = player->last_position;
5681 stop = GST_CLOCK_TIME_NONE;
5683 start = GST_CLOCK_TIME_NONE;
5687 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5688 player->playback_rate,
5690 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5691 GST_SEEK_TYPE_SET, start,
5692 GST_SEEK_TYPE_SET, stop)) {
5693 LOGE("failed to set speed playback");
5694 return MM_ERROR_PLAYER_SEEK;
5697 LOGD("succeeded to set speed playback as %0.1f", rate);
5701 return MM_ERROR_NONE;;
5705 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5707 mmplayer_t *player = (mmplayer_t *)hplayer;
5708 int ret = MM_ERROR_NONE;
5712 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5714 /* check pipline building state */
5715 __mmplayer_check_pipeline(player);
5717 ret = _mmplayer_gst_set_position(player, position, FALSE);
5725 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5727 mmplayer_t *player = (mmplayer_t *)hplayer;
5728 int ret = MM_ERROR_NONE;
5730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5731 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5733 if (g_strrstr(player->type, "video/mpegts"))
5734 __mmplayer_update_duration_value(player);
5736 *duration = player->duration;
5741 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5743 mmplayer_t *player = (mmplayer_t *)hplayer;
5744 int ret = MM_ERROR_NONE;
5746 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5748 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5754 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5756 mmplayer_t *player = (mmplayer_t *)hplayer;
5757 int ret = MM_ERROR_NONE;
5761 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5763 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5771 __mmplayer_is_midi_type(gchar *str_caps)
5773 if ((g_strrstr(str_caps, "audio/midi")) ||
5774 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5775 (g_strrstr(str_caps, "application/x-smaf")) ||
5776 (g_strrstr(str_caps, "audio/x-imelody")) ||
5777 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5778 (g_strrstr(str_caps, "audio/xmf")) ||
5779 (g_strrstr(str_caps, "audio/mxmf"))) {
5788 __mmplayer_is_only_mp3_type(gchar *str_caps)
5790 if (g_strrstr(str_caps, "application/x-id3") ||
5791 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5797 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5799 GstStructure *caps_structure = NULL;
5800 gint samplerate = 0;
5804 MMPLAYER_RETURN_IF_FAIL(player && caps);
5806 caps_structure = gst_caps_get_structure(caps, 0);
5808 /* set stream information */
5809 gst_structure_get_int(caps_structure, "rate", &samplerate);
5810 gst_structure_get_int(caps_structure, "channels", &channels);
5812 mm_player_set_attribute((MMHandleType)player, NULL,
5813 "content_audio_samplerate", samplerate,
5814 "content_audio_channels", channels, NULL);
5816 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5820 __mmplayer_update_content_type_info(mmplayer_t *player)
5823 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5825 if (__mmplayer_is_midi_type(player->type)) {
5826 player->bypass_audio_effect = TRUE;
5830 if (!player->streamer) {
5831 LOGD("no need to check streaming type");
5835 if (g_strrstr(player->type, "application/x-hls")) {
5836 /* If it can't know exact type when it parses uri because of redirection case,
5837 * it will be fixed by typefinder or when doing autoplugging.
5839 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5840 player->streamer->is_adaptive_streaming = TRUE;
5841 } else if (g_strrstr(player->type, "application/dash+xml")) {
5842 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5843 player->streamer->is_adaptive_streaming = TRUE;
5846 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5847 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5848 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5850 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5851 if (player->streamer->is_adaptive_streaming)
5852 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5854 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5858 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5863 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5864 GstCaps *caps, gpointer data)
5866 mmplayer_t *player = (mmplayer_t *)data;
5871 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5873 /* store type string */
5874 MMPLAYER_FREEIF(player->type);
5875 player->type = gst_caps_to_string(caps);
5877 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5878 player, player->type, probability, gst_caps_get_size(caps));
5880 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5881 (g_strrstr(player->type, "audio/x-raw-int"))) {
5882 LOGE("not support media format");
5884 if (player->msg_posted == FALSE) {
5885 MMMessageParamType msg_param;
5886 memset(&msg_param, 0, sizeof(MMMessageParamType));
5888 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5889 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5891 /* don't post more if one was sent already */
5892 player->msg_posted = TRUE;
5897 __mmplayer_update_content_type_info(player);
5899 pad = gst_element_get_static_pad(tf, "src");
5901 LOGE("fail to get typefind src pad.");
5905 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5906 gboolean async = FALSE;
5907 LOGE("failed to autoplug %s", player->type);
5909 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5911 if (async && player->msg_posted == FALSE)
5912 __mmplayer_handle_missed_plugin(player);
5916 gst_object_unref(GST_OBJECT(pad));
5924 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5926 GstElement *decodebin = NULL;
5930 /* create decodebin */
5931 decodebin = gst_element_factory_make("decodebin", NULL);
5934 LOGE("fail to create decodebin");
5938 /* raw pad handling signal */
5939 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5940 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5942 /* no-more-pad pad handling signal */
5943 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5944 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5946 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5947 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5949 /* This signal is emitted when a pad for which there is no further possible
5950 decoding is added to the decodebin.*/
5951 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5952 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5954 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5955 before looking for any elements that can handle that stream.*/
5956 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5957 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5959 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
5960 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
5961 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
5963 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5964 before looking for any elements that can handle that stream.*/
5965 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5966 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5968 /* This signal is emitted once decodebin has finished decoding all the data.*/
5969 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5970 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5972 /* This signal is emitted when a element is added to the bin.*/
5973 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5974 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5981 __mmplayer_gst_make_queue2(mmplayer_t *player)
5983 GstElement *queue2 = NULL;
5984 gint64 dur_bytes = 0L;
5985 mmplayer_gst_element_t *mainbin = NULL;
5986 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5989 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5991 mainbin = player->pipeline->mainbin;
5993 queue2 = gst_element_factory_make("queue2", "queue2");
5995 LOGE("failed to create buffering queue element");
5999 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6000 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6002 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6004 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6005 * skip the pull mode(file or ring buffering) setting. */
6006 if (dur_bytes > 0) {
6007 if (!g_strrstr(player->type, "video/mpegts")) {
6008 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6009 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6015 _mm_player_streaming_set_queue2(player->streamer,
6019 (guint64)dur_bytes); /* no meaning at the moment */
6025 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6027 mmplayer_gst_element_t *mainbin = NULL;
6028 GstElement *decodebin = NULL;
6029 GstElement *queue2 = NULL;
6030 GstPad *sinkpad = NULL;
6031 GstPad *qsrcpad = NULL;
6034 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6036 mainbin = player->pipeline->mainbin;
6038 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6040 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6041 LOGW("need to check: muxed buffer is not null");
6044 queue2 = __mmplayer_gst_make_queue2(player);
6046 LOGE("failed to make queue2");
6050 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6051 LOGE("failed to add buffering queue");
6055 sinkpad = gst_element_get_static_pad(queue2, "sink");
6056 qsrcpad = gst_element_get_static_pad(queue2, "src");
6058 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6059 LOGE("failed to link [%s:%s]-[%s:%s]",
6060 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6064 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6065 LOGE("failed to sync queue2 state with parent");
6069 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6070 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6074 gst_object_unref(GST_OBJECT(sinkpad));
6078 /* create decodebin */
6079 decodebin = _mmplayer_gst_make_decodebin(player);
6081 LOGE("failed to make decodebin");
6085 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6086 LOGE("failed to add decodebin");
6090 /* to force caps on the decodebin element and avoid reparsing stuff by
6091 * typefind. It also avoids a deadlock in the way typefind activates pads in
6092 * the state change */
6093 g_object_set(decodebin, "sink-caps", caps, NULL);
6095 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6097 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6098 LOGE("failed to link [%s:%s]-[%s:%s]",
6099 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6103 gst_object_unref(GST_OBJECT(sinkpad));
6105 gst_object_unref(GST_OBJECT(qsrcpad));
6108 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6109 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6111 /* set decodebin property about buffer in streaming playback. *
6112 * in case of HLS/DASH, it does not need to have big buffer *
6113 * because it is kind of adaptive streaming. */
6114 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6115 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6116 gint high_percent = 0;
6118 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6119 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6121 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6123 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6125 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6126 "high-percent", high_percent,
6127 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6128 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6129 "max-size-buffers", 0, NULL); // disable or automatic
6132 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6133 LOGE("failed to sync decodebin state with parent");
6144 gst_object_unref(GST_OBJECT(sinkpad));
6147 gst_object_unref(GST_OBJECT(qsrcpad));
6150 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6151 * You need to explicitly set elements to the NULL state before
6152 * dropping the final reference, to allow them to clean up.
6154 gst_element_set_state(queue2, GST_STATE_NULL);
6156 /* And, it still has a parent "player".
6157 * You need to let the parent manage the object instead of unreffing the object directly.
6159 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6160 gst_object_unref(queue2);
6165 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6166 * You need to explicitly set elements to the NULL state before
6167 * dropping the final reference, to allow them to clean up.
6169 gst_element_set_state(decodebin, GST_STATE_NULL);
6171 /* And, it still has a parent "player".
6172 * You need to let the parent manage the object instead of unreffing the object directly.
6175 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6176 gst_object_unref(decodebin);
6184 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6188 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6189 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6191 LOGD("class : %s, mime : %s", factory_class, mime);
6193 /* add missing plugin */
6194 /* NOTE : msl should check missing plugin for image mime type.
6195 * Some motion jpeg clips can have playable audio track.
6196 * So, msl have to play audio after displaying popup written video format not supported.
6198 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6199 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6200 LOGD("not found demuxer");
6201 player->not_found_demuxer = TRUE;
6202 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6208 if (!g_strrstr(factory_class, "Demuxer")) {
6209 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6210 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6211 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6213 /* check that clip have multi tracks or not */
6214 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6215 LOGD("video plugin is already linked");
6217 LOGW("add VIDEO to missing plugin");
6218 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6219 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6221 } else if (g_str_has_prefix(mime, "audio")) {
6222 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6223 LOGD("audio plugin is already linked");
6225 LOGW("add AUDIO to missing plugin");
6226 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6227 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6235 return MM_ERROR_NONE;
6239 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6241 mmplayer_t *player = (mmplayer_t *)data;
6245 MMPLAYER_RETURN_IF_FAIL(player);
6247 /* remove fakesink. */
6248 if (!_mmplayer_gst_remove_fakesink(player,
6249 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6250 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6251 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6252 * source element are not same. To overcome this situation, this function will called
6253 * several places and several times. Therefore, this is not an error case.
6258 LOGD("[handle: %p] pipeline has completely constructed", player);
6260 if ((player->msg_posted == FALSE) &&
6261 (player->cmd >= MMPLAYER_COMMAND_START))
6262 __mmplayer_handle_missed_plugin(player);
6264 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6268 __mmplayer_check_profile(void)
6271 static int profile_tv = -1;
6273 if (__builtin_expect(profile_tv != -1, 1))
6276 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6277 switch (*profileName) {
6292 __mmplayer_get_next_uri(mmplayer_t *player)
6294 mmplayer_parse_profile_t profile;
6296 guint num_of_list = 0;
6299 num_of_list = g_list_length(player->uri_info.uri_list);
6300 uri_idx = player->uri_info.uri_idx;
6302 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6303 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6304 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6306 LOGW("next uri does not exist");
6310 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6311 LOGE("failed to parse profile");
6315 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6316 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6317 LOGW("uri type is not supported(%d)", profile.uri_type);
6321 LOGD("success to find next uri %d", uri_idx);
6325 if (!uri || uri_idx == num_of_list) {
6326 LOGE("failed to find next uri");
6330 player->uri_info.uri_idx = uri_idx;
6331 if (mm_player_set_attribute((MMHandleType)player, NULL,
6332 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6333 LOGE("failed to set attribute");
6337 SECURE_LOGD("next playback uri: %s", uri);
6342 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6344 #define REPEAT_COUNT_INFINITE -1
6345 #define REPEAT_COUNT_MIN 2
6346 #define ORIGINAL_URI_ONLY 1
6348 MMHandleType attrs = 0;
6352 guint num_of_uri = 0;
6353 int profile_tv = -1;
6357 LOGD("checking for gapless play option");
6359 if (player->build_audio_offload) {
6360 LOGE("offload path is not supportable.");
6364 if (player->pipeline->textbin) {
6365 LOGE("subtitle path is enabled. gapless play is not supported.");
6369 attrs = MMPLAYER_GET_ATTRS(player);
6371 LOGE("fail to get attributes.");
6375 mm_attrs_multiple_get(player->attrs, NULL,
6376 "content_video_found", &video,
6377 "profile_play_count", &count,
6378 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6380 /* gapless playback is not supported in case of video at TV profile. */
6381 profile_tv = __mmplayer_check_profile();
6382 if (profile_tv && video) {
6383 LOGW("not support video gapless playback");
6387 /* check repeat count in case of audio */
6389 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6390 LOGW("gapless is disabled");
6394 num_of_uri = g_list_length(player->uri_info.uri_list);
6396 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6398 if (num_of_uri == ORIGINAL_URI_ONLY) {
6399 /* audio looping path */
6400 if (count >= REPEAT_COUNT_MIN) {
6401 /* decrease play count */
6402 /* we succeeded to rewind. update play count and then wait for next EOS */
6404 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6405 } else if (count != REPEAT_COUNT_INFINITE) {
6406 LOGD("there is no next uri and no repeat");
6409 LOGD("looping cnt %d", count);
6411 /* gapless playback path */
6412 if (!__mmplayer_get_next_uri(player)) {
6413 LOGE("failed to get next uri");
6420 LOGE("unable to play gapless path. EOS will be posted soon");
6425 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6427 mmplayer_selector_t *selector = &player->selector[type];
6428 mmplayer_gst_element_t *sinkbin = NULL;
6429 main_element_id_e selectorId = MMPLAYER_M_NUM;
6430 main_element_id_e sinkId = MMPLAYER_M_NUM;
6431 GstPad *srcpad = NULL;
6432 GstPad *sinkpad = NULL;
6433 gboolean send_notice = FALSE;
6436 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6438 LOGD("type %d", type);
6441 case MM_PLAYER_TRACK_TYPE_AUDIO:
6442 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6443 sinkId = MMPLAYER_A_BIN;
6444 sinkbin = player->pipeline->audiobin;
6446 case MM_PLAYER_TRACK_TYPE_VIDEO:
6447 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6448 sinkId = MMPLAYER_V_BIN;
6449 sinkbin = player->pipeline->videobin;
6452 case MM_PLAYER_TRACK_TYPE_TEXT:
6453 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6454 sinkId = MMPLAYER_T_BIN;
6455 sinkbin = player->pipeline->textbin;
6458 LOGE("requested type is not supportable");
6463 if (player->pipeline->mainbin[selectorId].gst) {
6466 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6468 if (selector->event_probe_id != 0)
6469 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6470 selector->event_probe_id = 0;
6472 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6473 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6475 if (srcpad && sinkpad) {
6476 /* after getting drained signal there is no data flows, so no need to do pad_block */
6477 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6478 gst_pad_unlink(srcpad, sinkpad);
6480 /* send custom event to sink pad to handle it at video sink */
6482 LOGD("send custom event to sinkpad");
6483 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6484 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6485 gst_pad_send_event(sinkpad, event);
6489 gst_object_unref(sinkpad);
6492 gst_object_unref(srcpad);
6495 LOGD("selector release");
6497 /* release and unref requests pad from the selector */
6498 for (n = 0; n < selector->channels->len; n++) {
6499 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6500 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6502 g_ptr_array_set_size(selector->channels, 0);
6504 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6505 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6507 player->pipeline->mainbin[selectorId].gst = NULL;
6515 __mmplayer_deactivate_old_path(mmplayer_t *player)
6518 MMPLAYER_RETURN_IF_FAIL(player);
6520 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6521 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6522 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6523 LOGE("deactivate selector error");
6527 _mmplayer_track_destroy(player);
6528 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6530 if (player->streamer) {
6531 _mm_player_streaming_initialize(player->streamer, FALSE);
6532 _mm_player_streaming_destroy(player->streamer);
6533 player->streamer = NULL;
6536 MMPLAYER_PLAYBACK_LOCK(player);
6537 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6544 if (!player->msg_posted) {
6545 MMMessageParamType msg = {0,};
6548 msg.code = MM_ERROR_PLAYER_INTERNAL;
6549 LOGE("gapless_uri_play> deactivate error");
6551 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6552 player->msg_posted = TRUE;
6558 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6560 int result = MM_ERROR_NONE;
6561 mmplayer_t *player = (mmplayer_t *)hplayer;
6564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6565 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6567 if (mm_player_set_attribute(hplayer, NULL,
6568 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6569 LOGE("failed to set attribute");
6570 result = MM_ERROR_PLAYER_INTERNAL;
6572 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6573 LOGE("failed to add the original uri in the uri list.");
6581 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6583 mmplayer_t *player = (mmplayer_t *)hplayer;
6584 guint num_of_list = 0;
6588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6589 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6591 if (player->pipeline && player->pipeline->textbin) {
6592 LOGE("subtitle path is enabled.");
6593 return MM_ERROR_PLAYER_INVALID_STATE;
6596 num_of_list = g_list_length(player->uri_info.uri_list);
6598 if (is_first_path) {
6599 if (num_of_list == 0) {
6600 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6601 SECURE_LOGD("add original path : %s", uri);
6603 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6604 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6606 SECURE_LOGD("change original path : %s", uri);
6609 MMHandleType attrs = 0;
6610 attrs = MMPLAYER_GET_ATTRS(player);
6612 if (num_of_list == 0) {
6613 char *original_uri = NULL;
6616 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6618 if (!original_uri) {
6619 LOGE("there is no original uri.");
6620 return MM_ERROR_PLAYER_INVALID_STATE;
6623 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6624 player->uri_info.uri_idx = 0;
6626 SECURE_LOGD("add original path at first : %s", original_uri);
6630 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6631 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6635 return MM_ERROR_NONE;
6639 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6641 mmplayer_t *player = (mmplayer_t *)hplayer;
6642 char *next_uri = NULL;
6643 guint num_of_list = 0;
6646 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6648 num_of_list = g_list_length(player->uri_info.uri_list);
6650 if (num_of_list > 0) {
6651 gint uri_idx = player->uri_info.uri_idx;
6653 if (uri_idx < num_of_list-1)
6658 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6659 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6661 *uri = g_strdup(next_uri);
6665 return MM_ERROR_NONE;
6669 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6670 GstCaps *caps, gpointer data)
6672 mmplayer_t *player = (mmplayer_t *)data;
6673 const gchar *klass = NULL;
6674 const gchar *mime = NULL;
6675 gchar *caps_str = NULL;
6677 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6678 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6679 caps_str = gst_caps_to_string(caps);
6681 LOGW("unknown type of caps : %s from %s",
6682 caps_str, GST_ELEMENT_NAME(elem));
6684 MMPLAYER_FREEIF(caps_str);
6686 /* There is no available codec. */
6687 __mmplayer_check_not_supported_codec(player, klass, mime);
6691 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6692 GstCaps *caps, gpointer data)
6694 mmplayer_t *player = (mmplayer_t *)data;
6695 const char *mime = NULL;
6696 gboolean ret = TRUE;
6698 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6699 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6701 if (g_str_has_prefix(mime, "audio")) {
6702 GstStructure *caps_structure = NULL;
6703 gint samplerate = 0;
6705 gchar *caps_str = NULL;
6707 caps_structure = gst_caps_get_structure(caps, 0);
6708 gst_structure_get_int(caps_structure, "rate", &samplerate);
6709 gst_structure_get_int(caps_structure, "channels", &channels);
6711 if ((channels > 0 && samplerate == 0)) {
6712 LOGD("exclude audio...");
6716 caps_str = gst_caps_to_string(caps);
6717 /* set it directly because not sent by TAG */
6718 if (g_strrstr(caps_str, "mobile-xmf"))
6719 mm_player_set_attribute((MMHandleType)player, NULL,
6720 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6722 MMPLAYER_FREEIF(caps_str);
6723 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6724 LOGD("already video linked");
6727 LOGD("found new stream");
6734 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6736 gboolean ret = FALSE;
6737 GDBusConnection *conn = NULL;
6739 GVariant *result = NULL;
6740 const gchar *dbus_device_type = NULL;
6741 const gchar *dbus_ret = NULL;
6744 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6746 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6751 result = g_dbus_connection_call_sync(conn,
6752 "org.pulseaudio.Server",
6753 "/org/pulseaudio/StreamManager",
6754 "org.pulseaudio.StreamManager",
6755 "GetCurrentMediaRoutingPath",
6756 g_variant_new("(s)", "out"),
6757 G_VARIANT_TYPE("(ss)"),
6758 G_DBUS_CALL_FLAGS_NONE,
6762 if (!result || err) {
6763 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6768 /* device type is listed in stream-map.json at mmfw-sysconf */
6769 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6771 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6772 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6775 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6776 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6777 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6778 LOGD("audio offload is supportable");
6784 LOGD("audio offload is not supportable");
6787 g_variant_unref(result);
6789 g_object_unref(conn);
6794 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6796 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6797 gint64 position = 0;
6799 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6800 player->pipeline && player->pipeline->mainbin);
6802 MMPLAYER_CMD_LOCK(player);
6803 current_state = MMPLAYER_CURRENT_STATE(player);
6805 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6806 LOGW("getting current position failed in paused");
6808 _mmplayer_unrealize((MMHandleType)player);
6809 _mmplayer_realize((MMHandleType)player);
6811 _mmplayer_set_position((MMHandleType)player, position);
6813 /* async not to be blocked in streaming case */
6814 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6816 _mmplayer_pause((MMHandleType)player);
6818 if (current_state == MM_PLAYER_STATE_PLAYING)
6819 _mmplayer_start((MMHandleType)player);
6820 MMPLAYER_CMD_UNLOCK(player);
6822 LOGD("rebuilding audio pipeline is completed.");
6825 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6827 mmplayer_t *player = (mmplayer_t *)user_data;
6828 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6829 gboolean is_supportable = FALSE;
6831 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6832 LOGW("failed to get device type");
6834 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6836 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6837 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6838 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6839 LOGD("ignore this dev connected info");
6843 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6844 if (player->build_audio_offload == is_supportable) {
6845 LOGD("keep current pipeline without re-building");
6849 /* rebuild pipeline */
6850 LOGD("re-build pipeline - offload: %d", is_supportable);
6851 player->build_audio_offload = FALSE;
6852 __mmplayer_rebuild_audio_pipeline(player);
6858 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6860 unsigned int id = 0;
6862 if (player->audio_device_cb_id != 0) {
6863 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6867 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6868 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6869 LOGD("added device connected cb (%u)", id);
6870 player->audio_device_cb_id = id;
6872 LOGW("failed to add device connected cb");
6879 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6881 mmplayer_t *player = (mmplayer_t *)hplayer;
6884 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6885 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6887 *activated = player->build_audio_offload;
6889 LOGD("offload activated : %d", (int)*activated);
6892 return MM_ERROR_NONE;
6896 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6899 this function need to be updated according to the supported media format
6900 @see player->ini.audio_offload_media_format */
6902 if (__mmplayer_is_only_mp3_type(player->type)) {
6903 LOGD("offload supportable media format type");
6911 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6913 gboolean ret = FALSE;
6914 GstElementFactory *factory = NULL;
6917 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6919 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6920 if (!__mmplayer_is_offload_supported_type(player))
6923 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6924 LOGD("there is no audio offload sink");
6928 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6929 LOGW("there is no audio device type to support offload");
6933 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6935 LOGW("there is no installed audio offload sink element");
6938 gst_object_unref(factory);
6940 if (__mmplayer_acquire_hw_resource(player,
6941 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6942 LOGE("failed to acquire audio offload decoder resource");
6946 if (!__mmplayer_add_audio_device_connected_cb(player))
6949 if (!__mmplayer_is_audio_offload_device_type(player))
6952 LOGD("audio offload can be built");
6957 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6963 static GstAutoplugSelectResult
6964 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6966 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6967 int audio_offload = 0;
6969 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6970 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6972 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6973 LOGD("expose audio path to build offload output path");
6974 player->build_audio_offload = TRUE;
6975 /* update codec info */
6976 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6977 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6978 player->audiodec_linked = 1;
6980 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6984 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
6985 And need to consider the multi-track audio content.
6986 There is no HW audio decoder in public. */
6988 /* set stream information */
6989 if (!player->audiodec_linked)
6990 __mmplayer_set_audio_attrs(player, caps);
6992 /* update codec info */
6993 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6994 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6995 player->audiodec_linked = 1;
6997 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6999 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7000 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7002 /* mark video decoder for acquire */
7003 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7004 LOGW("video decoder resource is already acquired, skip it.");
7005 ret = GST_AUTOPLUG_SELECT_SKIP;
7009 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7010 LOGE("failed to acquire video decoder resource");
7011 ret = GST_AUTOPLUG_SELECT_SKIP;
7014 player->interrupted_by_resource = FALSE;
7017 /* update codec info */
7018 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7019 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7020 player->videodec_linked = 1;
7028 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7029 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7031 #define DEFAULT_IDX 0xFFFF
7032 #define MIN_FACTORY_NUM 2
7033 mmplayer_t *player = (mmplayer_t *)data;
7034 GValueArray *new_factories = NULL;
7035 GValue val = { 0, };
7036 GstElementFactory *factory = NULL;
7037 const gchar *klass = NULL;
7038 gchar *factory_name = NULL;
7039 guint hw_dec_idx = DEFAULT_IDX;
7040 guint first_sw_dec_idx = DEFAULT_IDX;
7041 guint last_sw_dec_idx = DEFAULT_IDX;
7042 guint new_pos = DEFAULT_IDX;
7043 guint rm_pos = DEFAULT_IDX;
7044 int audio_codec_type;
7045 int video_codec_type;
7046 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7048 if (factories->n_values < MIN_FACTORY_NUM)
7051 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7052 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7055 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7057 for (int i = 0 ; i < factories->n_values ; i++) {
7058 gchar *hw_dec_info = NULL;
7059 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7061 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7062 klass = gst_element_factory_get_klass(factory);
7063 factory_name = GST_OBJECT_NAME(factory);
7066 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7068 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7069 if (!player->need_audio_dec_sorting) {
7070 LOGD("sorting is not required");
7073 codec_type = audio_codec_type;
7074 hw_dec_info = player->ini.audiocodec_element_hw;
7075 sw_dec_info = player->ini.audiocodec_element_sw;
7076 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7077 if (!player->need_video_dec_sorting) {
7078 LOGD("sorting is not required");
7081 codec_type = video_codec_type;
7082 hw_dec_info = player->ini.videocodec_element_hw;
7083 sw_dec_info = player->ini.videocodec_element_sw;
7088 if (g_strrstr(factory_name, hw_dec_info)) {
7091 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7092 if (strstr(factory_name, sw_dec_info[j])) {
7093 last_sw_dec_idx = i;
7094 if (first_sw_dec_idx == DEFAULT_IDX) {
7095 first_sw_dec_idx = i;
7100 if (first_sw_dec_idx == DEFAULT_IDX)
7101 LOGW("unknown codec %s", factory_name);
7105 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7108 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7109 if (hw_dec_idx < first_sw_dec_idx)
7111 new_pos = first_sw_dec_idx - 1;
7112 rm_pos = hw_dec_idx + 1;
7113 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7114 if (last_sw_dec_idx < hw_dec_idx)
7116 new_pos = last_sw_dec_idx + 1;
7117 rm_pos = hw_dec_idx;
7122 /* change position - insert H/W decoder according to the new position */
7123 new_factories = g_value_array_copy(factories);
7124 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7125 g_value_init (&val, G_TYPE_OBJECT);
7126 g_value_set_object (&val, factory);
7127 g_value_array_insert(new_factories, new_pos, &val);
7128 g_value_unset (&val);
7129 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7131 for (int i = 0 ; i < new_factories->n_values ; i++) {
7132 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7134 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7135 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7138 return new_factories;
7142 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7143 GstCaps *caps, GstElementFactory *factory, gpointer data)
7145 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7146 mmplayer_t *player = (mmplayer_t *)data;
7148 gchar *factory_name = NULL;
7149 gchar *caps_str = NULL;
7150 const gchar *klass = NULL;
7153 factory_name = GST_OBJECT_NAME(factory);
7154 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7155 caps_str = gst_caps_to_string(caps);
7157 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7159 /* store type string */
7160 if (player->type == NULL) {
7161 player->type = gst_caps_to_string(caps);
7162 __mmplayer_update_content_type_info(player);
7165 /* filtering exclude keyword */
7166 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7167 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7168 LOGW("skipping [%s] by exculde keyword [%s]",
7169 factory_name, player->ini.exclude_element_keyword[idx]);
7171 result = GST_AUTOPLUG_SELECT_SKIP;
7176 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7177 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7178 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7179 factory_name, player->ini.unsupported_codec_keyword[idx]);
7180 result = GST_AUTOPLUG_SELECT_SKIP;
7185 /* exclude webm format */
7186 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7187 * because webm format is not supportable.
7188 * If webm is disabled in "autoplug-continue", there is no state change
7189 * failure or error because the decodebin will expose the pad directly.
7190 * It make MSL invoke _prepare_async_callback.
7191 * So, we need to disable webm format in "autoplug-select" */
7192 if (caps_str && strstr(caps_str, "webm")) {
7193 LOGW("webm is not supported");
7194 result = GST_AUTOPLUG_SELECT_SKIP;
7198 /* check factory class for filtering */
7199 /* NOTE : msl don't need to use image plugins.
7200 * So, those plugins should be skipped for error handling.
7202 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7203 LOGD("skipping [%s] by not required", factory_name);
7204 result = GST_AUTOPLUG_SELECT_SKIP;
7208 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7209 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7210 // TO CHECK : subtitle if needed, add subparse exception.
7211 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7212 result = GST_AUTOPLUG_SELECT_SKIP;
7216 if (g_strrstr(factory_name, "mpegpsdemux")) {
7217 LOGD("skipping PS container - not support");
7218 result = GST_AUTOPLUG_SELECT_SKIP;
7222 if (g_strrstr(factory_name, "mssdemux"))
7223 player->smooth_streaming = TRUE;
7225 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7226 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7229 GstStructure *str = NULL;
7230 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7232 /* don't make video because of not required */
7233 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7234 (!player->set_mode.video_export)) {
7235 LOGD("no need video decoding, expose pad");
7236 result = GST_AUTOPLUG_SELECT_EXPOSE;
7240 /* get w/h for omx state-tune */
7241 /* FIXME: deprecated? */
7242 str = gst_caps_get_structure(caps, 0);
7243 gst_structure_get_int(str, "width", &width);
7246 if (player->v_stream_caps) {
7247 gst_caps_unref(player->v_stream_caps);
7248 player->v_stream_caps = NULL;
7251 player->v_stream_caps = gst_caps_copy(caps);
7252 LOGD("take caps for video state tune");
7253 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7257 if (g_strrstr(klass, "Codec/Decoder")) {
7258 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7259 if (result != GST_AUTOPLUG_SELECT_TRY) {
7260 LOGW("skip add decoder");
7266 MMPLAYER_FREEIF(caps_str);
7272 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7275 //mmplayer_t *player = (mmplayer_t *)data;
7276 GstCaps *caps = NULL;
7278 LOGD("[Decodebin2] pad-removed signal");
7280 caps = gst_pad_query_caps(new_pad, NULL);
7282 LOGW("query caps is NULL");
7286 gchar *caps_str = NULL;
7287 caps_str = gst_caps_to_string(caps);
7289 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7291 MMPLAYER_FREEIF(caps_str);
7292 gst_caps_unref(caps);
7296 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7298 mmplayer_t *player = (mmplayer_t *)data;
7299 GstIterator *iter = NULL;
7300 GValue item = { 0, };
7302 gboolean done = FALSE;
7303 gboolean is_all_drained = TRUE;
7306 MMPLAYER_RETURN_IF_FAIL(player);
7308 LOGD("__mmplayer_gst_decode_drained");
7310 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7311 LOGW("Fail to get cmd lock");
7315 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7316 !__mmplayer_verify_gapless_play_path(player)) {
7317 LOGD("decoding is finished.");
7318 __mmplayer_reset_gapless_state(player);
7319 MMPLAYER_CMD_UNLOCK(player);
7323 player->gapless.reconfigure = TRUE;
7325 /* check decodebin src pads whether they received EOS or not */
7326 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7329 switch (gst_iterator_next(iter, &item)) {
7330 case GST_ITERATOR_OK:
7331 pad = g_value_get_object(&item);
7332 if (pad && !GST_PAD_IS_EOS(pad)) {
7333 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7334 is_all_drained = FALSE;
7337 g_value_reset(&item);
7339 case GST_ITERATOR_RESYNC:
7340 gst_iterator_resync(iter);
7342 case GST_ITERATOR_ERROR:
7343 case GST_ITERATOR_DONE:
7348 g_value_unset(&item);
7349 gst_iterator_free(iter);
7351 if (!is_all_drained) {
7352 LOGD("Wait util the all pads get EOS.");
7353 MMPLAYER_CMD_UNLOCK(player);
7358 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7359 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7361 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7362 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7363 __mmplayer_deactivate_old_path(player);
7364 MMPLAYER_CMD_UNLOCK(player);
7370 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7372 mmplayer_t *player = (mmplayer_t *)data;
7373 const gchar *klass = NULL;
7374 gchar *factory_name = NULL;
7376 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7377 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7379 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7381 if (__mmplayer_add_dump_buffer_probe(player, element))
7382 LOGD("add buffer probe");
7384 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7385 gchar *selected = NULL;
7386 selected = g_strdup(GST_ELEMENT_NAME(element));
7387 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7390 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7391 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7392 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7394 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7395 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7397 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7398 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7399 "max-video-width", player->adaptive_info.limit.width,
7400 "max-video-height", player->adaptive_info.limit.height, NULL);
7402 } else if (g_strrstr(klass, "Demuxer")) {
7404 LOGD("plugged element is demuxer. take it");
7406 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7407 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7410 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7411 int surface_type = 0;
7413 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7416 // to support trust-zone only
7417 if (g_strrstr(factory_name, "asfdemux")) {
7418 LOGD("set file-location %s", player->profile.uri);
7419 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7420 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7421 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7422 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7423 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7424 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7425 (__mmplayer_is_only_mp3_type(player->type))) {
7426 LOGD("[mpegaudioparse] set streaming pull mode.");
7427 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7429 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7430 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7433 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7434 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7435 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7437 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7438 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7440 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7441 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7442 (MMPLAYER_IS_DASH_STREAMING(player))) {
7443 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7444 _mm_player_streaming_set_multiqueue(player->streamer, element);
7445 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7454 __mmplayer_release_misc(mmplayer_t *player)
7457 bool cur_mode = player->set_mode.rich_audio;
7460 MMPLAYER_RETURN_IF_FAIL(player);
7462 player->video_decoded_cb = NULL;
7463 player->video_decoded_cb_user_param = NULL;
7464 player->video_stream_prerolled = false;
7466 player->audio_decoded_cb = NULL;
7467 player->audio_decoded_cb_user_param = NULL;
7468 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7470 player->audio_stream_changed_cb = NULL;
7471 player->audio_stream_changed_cb_user_param = NULL;
7473 player->sent_bos = FALSE;
7474 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7476 player->seek_state = MMPLAYER_SEEK_NONE;
7478 player->total_bitrate = 0;
7479 player->total_maximum_bitrate = 0;
7481 player->not_found_demuxer = 0;
7483 player->last_position = 0;
7484 player->duration = 0;
7485 player->http_content_size = 0;
7486 player->not_supported_codec = MISSING_PLUGIN_NONE;
7487 player->can_support_codec = FOUND_PLUGIN_NONE;
7488 player->pending_seek.is_pending = false;
7489 player->pending_seek.pos = 0;
7490 player->msg_posted = FALSE;
7491 player->has_many_types = FALSE;
7492 player->is_subtitle_force_drop = FALSE;
7493 player->play_subtitle = FALSE;
7494 player->adjust_subtitle_pos = 0;
7495 player->has_closed_caption = FALSE;
7496 player->set_mode.video_export = false;
7497 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7498 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7500 player->set_mode.rich_audio = cur_mode;
7502 if (player->audio_device_cb_id > 0 &&
7503 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7504 LOGW("failed to remove audio device_connected_callback");
7505 player->audio_device_cb_id = 0;
7507 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7508 player->bitrate[i] = 0;
7509 player->maximum_bitrate[i] = 0;
7512 /* free memory related to audio effect */
7513 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7515 if (player->adaptive_info.var_list) {
7516 g_list_free_full(player->adaptive_info.var_list, g_free);
7517 player->adaptive_info.var_list = NULL;
7520 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7521 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7522 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7524 /* Reset video360 settings to their defaults in case if the pipeline is to be
7527 player->video360_metadata.is_spherical = -1;
7528 player->is_openal_plugin_used = FALSE;
7530 player->is_content_spherical = FALSE;
7531 player->is_video360_enabled = TRUE;
7532 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7533 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7534 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7535 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7536 player->video360_zoom = 1.0f;
7537 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7538 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7540 player->sound.rg_enable = false;
7542 __mmplayer_initialize_video_roi(player);
7547 __mmplayer_release_misc_post(mmplayer_t *player)
7549 char *original_uri = NULL;
7552 /* player->pipeline is already released before. */
7554 MMPLAYER_RETURN_IF_FAIL(player);
7556 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7558 /* clean found audio decoders */
7559 if (player->audio_decoders) {
7560 GList *a_dec = player->audio_decoders;
7561 for (; a_dec; a_dec = g_list_next(a_dec)) {
7562 gchar *name = a_dec->data;
7563 MMPLAYER_FREEIF(name);
7565 g_list_free(player->audio_decoders);
7566 player->audio_decoders = NULL;
7569 /* clean the uri list except original uri */
7570 if (player->uri_info.uri_list) {
7571 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7574 LOGW("failed to get original uri info");
7576 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7577 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7579 GList *uri_list = player->uri_info.uri_list;
7580 for (; uri_list; uri_list = g_list_next(uri_list)) {
7581 gchar *uri = uri_list->data;
7582 MMPLAYER_FREEIF(uri);
7584 g_list_free(player->uri_info.uri_list);
7585 player->uri_info.uri_list = NULL;
7588 /* clear the audio stream buffer list */
7589 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7591 /* clear the video stream bo list */
7592 __mmplayer_video_stream_destroy_bo_list(player);
7593 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7595 if (player->profile.input_mem.buf) {
7596 free(player->profile.input_mem.buf);
7597 player->profile.input_mem.buf = NULL;
7599 player->profile.input_mem.len = 0;
7600 player->profile.input_mem.offset = 0;
7602 player->uri_info.uri_idx = 0;
7607 __mmplayer_check_subtitle(mmplayer_t *player)
7609 MMHandleType attrs = 0;
7610 char *subtitle_uri = NULL;
7614 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7616 /* get subtitle attribute */
7617 attrs = MMPLAYER_GET_ATTRS(player);
7621 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7622 if (!subtitle_uri || !strlen(subtitle_uri))
7625 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7626 player->is_external_subtitle_present = TRUE;
7634 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7636 MMPLAYER_RETURN_IF_FAIL(player);
7638 if (player->eos_timer) {
7639 LOGD("cancel eos timer");
7640 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7641 player->eos_timer = 0;
7648 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7652 MMPLAYER_RETURN_IF_FAIL(player);
7653 MMPLAYER_RETURN_IF_FAIL(sink);
7655 player->sink_elements = g_list_append(player->sink_elements, sink);
7661 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7665 MMPLAYER_RETURN_IF_FAIL(player);
7666 MMPLAYER_RETURN_IF_FAIL(sink);
7668 player->sink_elements = g_list_remove(player->sink_elements, sink);
7674 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7675 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7677 mmplayer_signal_item_t *item = NULL;
7680 MMPLAYER_RETURN_IF_FAIL(player);
7682 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7683 LOGE("invalid signal type [%d]", type);
7687 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7689 LOGE("cannot connect signal [%s]", signal);
7694 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7695 player->signals[type] = g_list_append(player->signals[type], item);
7701 /* NOTE : be careful with calling this api. please refer to below glib comment
7702 * glib comment : Note that there is a bug in GObject that makes this function much
7703 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7704 * will no longer be called, but, the signal handler is not currently disconnected.
7705 * If the instance is itself being freed at the same time than this doesn't matter,
7706 * since the signal will automatically be removed, but if instance persists,
7707 * then the signal handler will leak. You should not remove the signal yourself
7708 * because in a future versions of GObject, the handler will automatically be
7711 * It's possible to work around this problem in a way that will continue to work
7712 * with future versions of GObject by checking that the signal handler is still
7713 * connected before disconnected it:
7715 * if (g_signal_handler_is_connected(instance, id))
7716 * g_signal_handler_disconnect(instance, id);
7719 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7721 GList *sig_list = NULL;
7722 mmplayer_signal_item_t *item = NULL;
7726 MMPLAYER_RETURN_IF_FAIL(player);
7728 LOGD("release signals type : %d", type);
7730 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7731 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7732 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7733 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7734 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7735 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7739 sig_list = player->signals[type];
7741 for (; sig_list; sig_list = sig_list->next) {
7742 item = sig_list->data;
7744 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7745 if (g_signal_handler_is_connected(item->obj, item->sig))
7746 g_signal_handler_disconnect(item->obj, item->sig);
7749 MMPLAYER_FREEIF(item);
7752 g_list_free(player->signals[type]);
7753 player->signals[type] = NULL;
7761 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7763 mmplayer_t *player = 0;
7764 int prev_display_surface_type = 0;
7768 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7770 player = MM_PLAYER_CAST(handle);
7772 /* check video sinkbin is created */
7773 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7774 LOGW("Videosink is already created");
7775 return MM_ERROR_NONE;
7778 LOGD("videosink element is not yet ready");
7780 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7781 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7783 return MM_ERROR_INVALID_ARGUMENT;
7786 /* load previous attributes */
7787 if (player->attrs) {
7788 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7789 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7790 if (prev_display_surface_type == surface_type) {
7791 LOGD("incoming display surface type is same as previous one, do nothing..");
7793 return MM_ERROR_NONE;
7796 LOGE("failed to load attributes");
7798 return MM_ERROR_PLAYER_INTERNAL;
7801 /* videobin is not created yet, so we just set attributes related to display surface */
7802 LOGD("store display attribute for given surface type(%d)", surface_type);
7803 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7804 "display_overlay", wl_surface_id, NULL);
7807 return MM_ERROR_NONE;
7810 /* Note : if silent is true, then subtitle would not be displayed. :*/
7812 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7814 mmplayer_t *player = (mmplayer_t *)hplayer;
7818 /* check player handle */
7819 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7821 player->set_mode.subtitle_off = silent;
7823 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7827 return MM_ERROR_NONE;
7831 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7833 mmplayer_gst_element_t *mainbin = NULL;
7834 mmplayer_gst_element_t *textbin = NULL;
7835 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7836 GstState current_state = GST_STATE_VOID_PENDING;
7837 GstState element_state = GST_STATE_VOID_PENDING;
7838 GstState element_pending_state = GST_STATE_VOID_PENDING;
7840 GstEvent *event = NULL;
7841 int result = MM_ERROR_NONE;
7843 GstClock *curr_clock = NULL;
7844 GstClockTime base_time, start_time, curr_time;
7849 /* check player handle */
7850 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7852 player->pipeline->mainbin &&
7853 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7855 mainbin = player->pipeline->mainbin;
7856 textbin = player->pipeline->textbin;
7858 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7860 // sync clock with current pipeline
7861 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7862 curr_time = gst_clock_get_time(curr_clock);
7864 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7865 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7867 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7868 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7870 if (current_state > GST_STATE_READY) {
7871 // sync state with current pipeline
7872 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7873 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7874 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7876 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7877 if (GST_STATE_CHANGE_FAILURE == ret) {
7878 LOGE("fail to state change.");
7879 result = MM_ERROR_PLAYER_INTERNAL;
7883 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7884 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7887 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7888 gst_object_unref(curr_clock);
7891 // seek to current position
7892 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7893 result = MM_ERROR_PLAYER_INVALID_STATE;
7894 LOGE("gst_element_query_position failed, invalid state");
7898 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7899 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);
7901 _mmplayer_gst_send_event_to_sink(player, event);
7903 result = MM_ERROR_PLAYER_INTERNAL;
7904 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7908 /* sync state with current pipeline */
7909 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7910 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7911 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7913 return MM_ERROR_NONE;
7916 /* release text pipeline resource */
7917 player->textsink_linked = 0;
7919 /* release signal */
7920 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7922 /* release textbin with it's childs */
7923 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7924 MMPLAYER_FREEIF(player->pipeline->textbin);
7925 player->pipeline->textbin = NULL;
7927 /* release subtitle elem */
7928 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7929 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7935 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7937 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7938 GstState current_state = GST_STATE_VOID_PENDING;
7940 MMHandleType attrs = 0;
7941 mmplayer_gst_element_t *mainbin = NULL;
7942 mmplayer_gst_element_t *textbin = NULL;
7944 gchar *subtitle_uri = NULL;
7945 int result = MM_ERROR_NONE;
7946 const gchar *charset = NULL;
7950 /* check player handle */
7951 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7953 player->pipeline->mainbin &&
7954 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7955 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7957 mainbin = player->pipeline->mainbin;
7958 textbin = player->pipeline->textbin;
7960 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7961 if (current_state < GST_STATE_READY) {
7962 result = MM_ERROR_PLAYER_INVALID_STATE;
7963 LOGE("Pipeline is not in proper state");
7967 attrs = MMPLAYER_GET_ATTRS(player);
7969 LOGE("cannot get content attribute");
7970 result = MM_ERROR_PLAYER_INTERNAL;
7974 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7975 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7976 LOGE("subtitle uri is not proper filepath");
7977 result = MM_ERROR_PLAYER_INVALID_URI;
7981 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7982 LOGE("failed to get storage info of subtitle path");
7983 result = MM_ERROR_PLAYER_INVALID_URI;
7987 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7988 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7990 if (!strcmp(filepath, subtitle_uri)) {
7991 LOGD("subtitle path is not changed");
7994 if (mm_player_set_attribute((MMHandleType)player, NULL,
7995 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7996 LOGE("failed to set attribute");
8001 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8002 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8003 player->subtitle_language_list = NULL;
8004 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8006 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8007 if (ret != GST_STATE_CHANGE_SUCCESS) {
8008 LOGE("failed to change state of textbin to READY");
8009 result = MM_ERROR_PLAYER_INTERNAL;
8013 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8014 if (ret != GST_STATE_CHANGE_SUCCESS) {
8015 LOGE("failed to change state of subparse to READY");
8016 result = MM_ERROR_PLAYER_INTERNAL;
8020 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8021 if (ret != GST_STATE_CHANGE_SUCCESS) {
8022 LOGE("failed to change state of filesrc to READY");
8023 result = MM_ERROR_PLAYER_INTERNAL;
8027 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8029 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8031 charset = _mmplayer_get_charset(filepath);
8033 LOGD("detected charset is %s", charset);
8034 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8037 result = _mmplayer_sync_subtitle_pipeline(player);
8044 /* API to switch between external subtitles */
8046 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8048 int result = MM_ERROR_NONE;
8049 mmplayer_t *player = (mmplayer_t *)hplayer;
8054 /* check player handle */
8055 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8057 /* filepath can be null in idle state */
8059 /* check file path */
8060 if ((path = strstr(filepath, "file://")))
8061 result = _mmplayer_exist_file_path(path + 7);
8063 result = _mmplayer_exist_file_path(filepath);
8065 if (result != MM_ERROR_NONE) {
8066 LOGE("invalid subtitle path 0x%X", result);
8067 return result; /* file not found or permission denied */
8071 if (!player->pipeline) {
8073 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8074 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8075 LOGE("failed to set attribute");
8076 return MM_ERROR_PLAYER_INTERNAL;
8079 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8080 /* check filepath */
8081 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8083 if (!__mmplayer_check_subtitle(player)) {
8084 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8085 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8086 LOGE("failed to set attribute");
8087 return MM_ERROR_PLAYER_INTERNAL;
8090 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8091 LOGE("fail to create text pipeline");
8092 return MM_ERROR_PLAYER_INTERNAL;
8095 result = _mmplayer_sync_subtitle_pipeline(player);
8097 result = __mmplayer_change_external_subtitle_language(player, filepath);
8100 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8101 player->is_external_subtitle_added_now = TRUE;
8103 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8104 if (!player->subtitle_language_list) {
8105 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8106 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8107 LOGW("subtitle language list is not updated yet");
8109 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8117 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8119 int result = MM_ERROR_NONE;
8120 gchar *change_pad_name = NULL;
8121 GstPad *sinkpad = NULL;
8122 mmplayer_gst_element_t *mainbin = NULL;
8123 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8124 GstCaps *caps = NULL;
8125 gint total_track_num = 0;
8129 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8130 MM_ERROR_PLAYER_NOT_INITIALIZED);
8132 LOGD("Change Track(%d) to %d", type, index);
8134 mainbin = player->pipeline->mainbin;
8136 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8137 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8138 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8139 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8141 /* Changing Video Track is not supported. */
8142 LOGE("Track Type Error");
8146 if (mainbin[elem_idx].gst == NULL) {
8147 result = MM_ERROR_PLAYER_NO_OP;
8148 LOGD("Req track doesn't exist");
8152 total_track_num = player->selector[type].total_track_num;
8153 if (total_track_num <= 0) {
8154 result = MM_ERROR_PLAYER_NO_OP;
8155 LOGD("Language list is not available");
8159 if ((index < 0) || (index >= total_track_num)) {
8160 result = MM_ERROR_INVALID_ARGUMENT;
8161 LOGD("Not a proper index : %d", index);
8165 /*To get the new pad from the selector*/
8166 change_pad_name = g_strdup_printf("sink_%u", index);
8167 if (change_pad_name == NULL) {
8168 result = MM_ERROR_PLAYER_INTERNAL;
8169 LOGD("Pad does not exists");
8173 LOGD("new active pad name: %s", change_pad_name);
8175 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8176 if (sinkpad == NULL) {
8177 LOGD("sinkpad is NULL");
8178 result = MM_ERROR_PLAYER_INTERNAL;
8182 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8183 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8185 caps = gst_pad_get_current_caps(sinkpad);
8186 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8189 gst_object_unref(sinkpad);
8191 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8192 __mmplayer_set_audio_attrs(player, caps);
8195 MMPLAYER_FREEIF(change_pad_name);
8200 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8202 int result = MM_ERROR_NONE;
8203 mmplayer_t *player = NULL;
8204 mmplayer_gst_element_t *mainbin = NULL;
8206 gint current_active_index = 0;
8208 GstState current_state = GST_STATE_VOID_PENDING;
8209 GstEvent *event = NULL;
8214 player = (mmplayer_t *)hplayer;
8215 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8217 if (!player->pipeline) {
8218 LOGE("Track %d pre setting -> %d", type, index);
8220 player->selector[type].active_pad_index = index;
8224 mainbin = player->pipeline->mainbin;
8226 current_active_index = player->selector[type].active_pad_index;
8228 /*If index is same as running index no need to change the pad*/
8229 if (current_active_index == index)
8232 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8233 result = MM_ERROR_PLAYER_INVALID_STATE;
8237 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8238 if (current_state < GST_STATE_PAUSED) {
8239 result = MM_ERROR_PLAYER_INVALID_STATE;
8240 LOGW("Pipeline not in porper state");
8244 result = __mmplayer_change_selector_pad(player, type, index);
8245 if (result != MM_ERROR_NONE) {
8246 LOGE("change selector pad error");
8250 player->selector[type].active_pad_index = index;
8252 if (current_state == GST_STATE_PLAYING) {
8253 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8254 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8255 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8257 _mmplayer_gst_send_event_to_sink(player, event);
8259 result = MM_ERROR_PLAYER_INTERNAL;
8269 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8271 mmplayer_t *player = (mmplayer_t *)hplayer;
8275 /* check player handle */
8276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8278 *silent = player->set_mode.subtitle_off;
8280 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8284 return MM_ERROR_NONE;
8288 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8290 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8291 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8293 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8294 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8298 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8299 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8300 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8301 mmplayer_dump_t *dump_s;
8302 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8303 if (dump_s == NULL) {
8304 LOGE("malloc fail");
8308 dump_s->dump_element_file = NULL;
8309 dump_s->dump_pad = NULL;
8310 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8312 if (dump_s->dump_pad) {
8313 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8314 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]);
8315 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8316 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);
8317 /* add list for removed buffer probe and close FILE */
8318 player->dump_list = g_list_append(player->dump_list, dump_s);
8319 LOGD("%s sink pad added buffer probe for dump", factory_name);
8322 MMPLAYER_FREEIF(dump_s);
8323 LOGE("failed to get %s sink pad added", factory_name);
8330 static GstPadProbeReturn
8331 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8333 FILE *dump_data = (FILE *)u_data;
8335 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8336 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8338 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8340 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8342 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8344 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8346 gst_buffer_unmap(buffer, &probe_info);
8348 return GST_PAD_PROBE_OK;
8352 __mmplayer_release_dump_list(GList *dump_list)
8354 GList *d_list = dump_list;
8359 for (; d_list; d_list = g_list_next(d_list)) {
8360 mmplayer_dump_t *dump_s = d_list->data;
8361 if (dump_s->dump_pad) {
8362 if (dump_s->probe_handle_id)
8363 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8364 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8366 if (dump_s->dump_element_file) {
8367 fclose(dump_s->dump_element_file);
8368 dump_s->dump_element_file = NULL;
8370 MMPLAYER_FREEIF(dump_s);
8372 g_list_free(dump_list);
8377 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8379 mmplayer_t *player = (mmplayer_t *)hplayer;
8383 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8384 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8386 *exist = (bool)player->has_closed_caption;
8390 return MM_ERROR_NONE;
8394 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8399 LOGD("unref internal gst buffer %p", buffer);
8401 gst_buffer_unref((GstBuffer *)buffer);
8408 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8410 mmplayer_t *player = (mmplayer_t *)hplayer;
8414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8415 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8417 if (MMPLAYER_IS_STREAMING(player))
8418 *timeout = (int)player->ini.live_state_change_timeout;
8420 *timeout = (int)player->ini.localplayback_state_change_timeout;
8422 LOGD("timeout = %d", *timeout);
8425 return MM_ERROR_NONE;
8429 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8433 MMPLAYER_RETURN_IF_FAIL(player);
8435 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8437 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8438 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8439 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8440 player->storage_info[i].id = -1;
8441 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8443 if (path_type != MMPLAYER_PATH_MAX)
8452 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8454 int ret = MM_ERROR_NONE;
8455 mmplayer_t *player = (mmplayer_t *)hplayer;
8456 MMMessageParamType msg_param = {0, };
8459 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8461 LOGW("state changed storage %d:%d", id, state);
8463 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8464 return MM_ERROR_NONE;
8466 /* FIXME: text path should be handled seperately. */
8467 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8468 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8469 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8470 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8471 LOGW("external storage is removed");
8473 if (player->msg_posted == FALSE) {
8474 memset(&msg_param, 0, sizeof(MMMessageParamType));
8475 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8476 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8477 player->msg_posted = TRUE;
8480 /* unrealize the player */
8481 ret = _mmplayer_unrealize(hplayer);
8482 if (ret != MM_ERROR_NONE)
8483 LOGE("failed to unrealize");
8491 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8493 int ret = MM_ERROR_NONE;
8494 mmplayer_t *player = (mmplayer_t *)hplayer;
8495 int idx = 0, total = 0;
8496 gchar *result = NULL, *tmp = NULL;
8499 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8500 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8502 total = *num = g_list_length(player->adaptive_info.var_list);
8504 LOGW("There is no stream variant info.");
8508 result = g_strdup("");
8509 for (idx = 0 ; idx < total ; idx++) {
8510 stream_variant_t *v_data = NULL;
8511 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8514 gchar data[64] = {0};
8515 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8517 tmp = g_strconcat(result, data, NULL);
8521 LOGW("There is no variant data in %d", idx);
8526 *var_info = (char *)result;
8528 LOGD("variant info %d:%s", *num, *var_info);
8534 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8536 int ret = MM_ERROR_NONE;
8537 mmplayer_t *player = (mmplayer_t *)hplayer;
8540 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8542 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8544 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8545 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8546 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8548 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8549 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8550 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8551 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8553 /* FIXME: seek to current position for applying new variant limitation */
8562 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8564 int ret = MM_ERROR_NONE;
8565 mmplayer_t *player = (mmplayer_t *)hplayer;
8568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8569 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8571 *bandwidth = player->adaptive_info.limit.bandwidth;
8572 *width = player->adaptive_info.limit.width;
8573 *height = player->adaptive_info.limit.height;
8575 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8582 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8584 int ret = MM_ERROR_NONE;
8585 mmplayer_t *player = (mmplayer_t *)hplayer;
8588 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8589 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8590 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8592 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8594 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8595 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8596 else /* live case */
8597 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8599 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8606 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8608 #define IDX_FIRST_SW_CODEC 0
8609 mmplayer_t *player = (mmplayer_t *)hplayer;
8610 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8613 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8615 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8616 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8617 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8619 switch (stream_type) {
8620 case MM_PLAYER_STREAM_TYPE_AUDIO:
8621 /* to support audio codec selection, codec info have to be added in ini file as below.
8622 audio codec element hw = xxxx
8623 audio codec element sw = avdec
8624 and in case of audio hw codec is supported and selected,
8625 audio filter elements should be applied depending on the hw capabilities.
8627 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8628 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8629 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8630 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8631 LOGE("There is no audio codec info for codec_type %d", codec_type);
8632 return MM_ERROR_PLAYER_NO_OP;
8635 case MM_PLAYER_STREAM_TYPE_VIDEO:
8636 /* to support video codec selection, codec info have to be added in ini file as below.
8637 video codec element hw = omx
8638 video codec element sw = avdec */
8639 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8640 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8641 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8642 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8643 LOGE("There is no video codec info for codec_type %d", codec_type);
8644 return MM_ERROR_PLAYER_NO_OP;
8648 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8649 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8653 LOGD("update %s codec_type to %d", attr_name, codec_type);
8654 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8657 return MM_ERROR_NONE;
8661 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8663 mmplayer_t *player = (mmplayer_t *)hplayer;
8664 GstElement *rg_vol_element = NULL;
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8670 player->sound.rg_enable = enabled;
8672 /* just hold rgvolume enable value if pipeline is not ready */
8673 if (!player->pipeline || !player->pipeline->audiobin) {
8674 LOGD("pipeline is not ready. holding rgvolume enable value");
8675 return MM_ERROR_NONE;
8678 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8680 if (!rg_vol_element) {
8681 LOGD("rgvolume element is not created");
8682 return MM_ERROR_PLAYER_INTERNAL;
8686 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8688 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8692 return MM_ERROR_NONE;
8696 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8698 mmplayer_t *player = (mmplayer_t *)hplayer;
8699 GstElement *rg_vol_element = NULL;
8700 gboolean enable = FALSE;
8704 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8705 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8707 /* just hold enable_rg value if pipeline is not ready */
8708 if (!player->pipeline || !player->pipeline->audiobin) {
8709 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8710 *enabled = player->sound.rg_enable;
8711 return MM_ERROR_NONE;
8714 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8716 if (!rg_vol_element) {
8717 LOGD("rgvolume element is not created");
8718 return MM_ERROR_PLAYER_INTERNAL;
8721 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8722 *enabled = (bool)enable;
8726 return MM_ERROR_NONE;
8730 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8732 mmplayer_t *player = (mmplayer_t *)hplayer;
8733 MMHandleType attrs = 0;
8735 int ret = MM_ERROR_NONE;
8739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8741 attrs = MMPLAYER_GET_ATTRS(player);
8742 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8744 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8746 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8747 return MM_ERROR_PLAYER_INTERNAL;
8750 player->video_roi.scale_x = scale_x;
8751 player->video_roi.scale_y = scale_y;
8752 player->video_roi.scale_width = scale_width;
8753 player->video_roi.scale_height = scale_height;
8755 /* check video sinkbin is created */
8756 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8757 return MM_ERROR_NONE;
8759 if (!gst_video_overlay_set_video_roi_area(
8760 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8761 scale_x, scale_y, scale_width, scale_height))
8762 ret = MM_ERROR_PLAYER_INTERNAL;
8764 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8765 scale_x, scale_y, scale_width, scale_height);
8773 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8775 mmplayer_t *player = (mmplayer_t *)hplayer;
8776 int ret = MM_ERROR_NONE;
8780 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8781 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8783 *scale_x = player->video_roi.scale_x;
8784 *scale_y = player->video_roi.scale_y;
8785 *scale_width = player->video_roi.scale_width;
8786 *scale_height = player->video_roi.scale_height;
8788 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8789 *scale_x, *scale_y, *scale_width, *scale_height);
8795 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8797 mmplayer_t *player = (mmplayer_t *)hplayer;
8801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8803 player->client_pid = pid;
8805 LOGD("client pid[%d] %p", pid, player);
8809 return MM_ERROR_NONE;
8813 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
8815 mmplayer_t *player = (mmplayer_t *)hplayer;
8816 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8817 enum audio_element_id elem_id = MMPLAYER_A_NUM;
8821 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8822 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
8825 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
8827 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
8829 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
8830 return MM_ERROR_NONE;
8832 /* in case of audio codec default type is HW */
8834 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
8835 if (player->ini.support_audio_effect)
8836 return MM_ERROR_NONE;
8837 elem_id = MMPLAYER_A_FILTER;
8839 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
8840 if (player->ini.support_replaygain_control)
8841 return MM_ERROR_NONE;
8842 elem_id = MMPLAYER_A_RGVOL;
8844 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
8845 if (player->ini.support_pitch_control)
8846 return MM_ERROR_NONE;
8847 elem_id = MMPLAYER_A_PITCH;
8849 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
8850 if (player->ini.support_audio_effect)
8851 return MM_ERROR_NONE;
8853 /* default case handling is not required */
8856 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
8857 LOGW("audio control option [%d] is not available", opt);
8860 /* setting pcm exporting option is allowed before READY state */
8861 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
8862 return MM_ERROR_PLAYER_INVALID_STATE;
8864 /* check whether the audio filter exist or not after READY state,
8865 because the sw codec could be added during auto-plugging in some cases */
8866 if (!player->pipeline ||
8867 !player->pipeline->audiobin ||
8868 !player->pipeline->audiobin[elem_id].gst) {
8869 LOGW("there is no audio elem [%d]", elem_id);
8874 LOGD("audio control opt %d, available %d", opt, *available);
8878 return MM_ERROR_NONE;
8882 __mmplayer_update_duration_value(mmplayer_t *player)
8884 gboolean ret = FALSE;
8885 gint64 dur_nsec = 0;
8886 LOGD("try to update duration");
8888 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8889 player->duration = dur_nsec;
8890 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8894 if (player->duration < 0) {
8895 LOGW("duration is Non-Initialized !!!");
8896 player->duration = 0;
8899 /* update streaming service type */
8900 player->streaming_type = _mmplayer_get_stream_service_type(player);
8902 /* check duration is OK */
8903 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8904 /* FIXIT : find another way to get duration here. */
8905 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8911 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8913 /* update audio params
8914 NOTE : We need original audio params and it can be only obtained from src pad of audio
8915 decoder. Below code only valid when we are not using 'resampler' just before
8916 'audioconverter'. */
8917 GstCaps *caps_a = NULL;
8919 gint samplerate = 0, channels = 0;
8920 GstStructure *p = NULL;
8921 GstElement *aconv = NULL;
8923 LOGD("try to update audio attrs");
8925 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8927 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8928 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8929 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8930 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8932 LOGE("there is no audio converter");
8936 pad = gst_element_get_static_pad(aconv, "sink");
8939 LOGW("failed to get pad from audio converter");
8943 caps_a = gst_pad_get_current_caps(pad);
8945 LOGW("not ready to get audio caps");
8946 gst_object_unref(pad);
8950 p = gst_caps_get_structure(caps_a, 0);
8952 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8954 gst_structure_get_int(p, "rate", &samplerate);
8955 gst_structure_get_int(p, "channels", &channels);
8957 mm_player_set_attribute((MMHandleType)player, NULL,
8958 "content_audio_samplerate", samplerate,
8959 "content_audio_channels", channels, NULL);
8961 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8963 gst_caps_unref(caps_a);
8964 gst_object_unref(pad);
8970 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8972 LOGD("try to update video attrs");
8974 GstCaps *caps_v = NULL;
8978 GstStructure *p = NULL;
8980 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8981 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8983 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8985 LOGD("no videosink sink pad");
8989 caps_v = gst_pad_get_current_caps(pad);
8990 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8991 if (!caps_v && player->v_stream_caps) {
8992 caps_v = player->v_stream_caps;
8993 gst_caps_ref(caps_v);
8997 LOGD("no negitiated caps from videosink");
8998 gst_object_unref(pad);
9002 p = gst_caps_get_structure(caps_v, 0);
9003 gst_structure_get_int(p, "width", &width);
9004 gst_structure_get_int(p, "height", &height);
9006 mm_player_set_attribute((MMHandleType)player, NULL,
9007 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9009 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9011 SECURE_LOGD("width : %d height : %d", width, height);
9013 gst_caps_unref(caps_v);
9014 gst_object_unref(pad);
9017 mm_player_set_attribute((MMHandleType)player, NULL,
9018 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9019 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9026 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9028 gboolean ret = FALSE;
9029 guint64 data_size = 0;
9033 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9034 if (!player->duration)
9037 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9038 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9039 if (stat(path, &sb) == 0)
9040 data_size = (guint64)sb.st_size;
9042 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9043 data_size = player->http_content_size;
9046 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9049 guint64 bitrate = 0;
9050 guint64 msec_dur = 0;
9052 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9054 bitrate = data_size * 8 * 1000 / msec_dur;
9055 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9056 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9057 mm_player_set_attribute((MMHandleType)player, NULL,
9058 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9061 LOGD("player duration is less than 0");
9065 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9066 if (player->total_bitrate) {
9067 mm_player_set_attribute((MMHandleType)player, NULL,
9068 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9077 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9079 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9080 data->uri_type = uri_type;
9084 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9086 int ret = MM_ERROR_PLAYER_INVALID_URI;
9088 char *buffer = NULL;
9089 char *seperator = strchr(path, ',');
9090 char ext[100] = {0,}, size[100] = {0,};
9093 if ((buffer = strstr(path, "ext="))) {
9094 buffer += strlen("ext=");
9096 if (strlen(buffer)) {
9097 strncpy(ext, buffer, 99);
9099 if ((seperator = strchr(ext, ','))
9100 || (seperator = strchr(ext, ' '))
9101 || (seperator = strchr(ext, '\0'))) {
9102 seperator[0] = '\0';
9107 if ((buffer = strstr(path, "size="))) {
9108 buffer += strlen("size=");
9110 if (strlen(buffer) > 0) {
9111 strncpy(size, buffer, 99);
9113 if ((seperator = strchr(size, ','))
9114 || (seperator = strchr(size, ' '))
9115 || (seperator = strchr(size, '\0'))) {
9116 seperator[0] = '\0';
9119 mem_size = atoi(size);
9124 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9126 if (mem_size && param) {
9127 if (data->input_mem.buf)
9128 free(data->input_mem.buf);
9129 data->input_mem.buf = malloc(mem_size);
9131 if (data->input_mem.buf) {
9132 memcpy(data->input_mem.buf, param, mem_size);
9133 data->input_mem.len = mem_size;
9134 ret = MM_ERROR_NONE;
9136 LOGE("failed to alloc mem %d", mem_size);
9137 ret = MM_ERROR_PLAYER_INTERNAL;
9140 data->input_mem.offset = 0;
9141 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9148 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9150 gchar *location = NULL;
9153 int ret = MM_ERROR_NONE;
9155 if ((path = strstr(uri, "file://"))) {
9156 location = g_filename_from_uri(uri, NULL, &err);
9157 if (!location || (err != NULL)) {
9158 LOGE("Invalid URI '%s' for filesrc: %s", path,
9159 (err != NULL) ? err->message : "unknown error");
9163 MMPLAYER_FREEIF(location);
9165 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9166 return MM_ERROR_PLAYER_INVALID_URI;
9168 LOGD("path from uri: %s", location);
9171 path = (location != NULL) ? (location) : ((char *)uri);
9174 ret = _mmplayer_exist_file_path(path);
9176 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9177 if (ret == MM_ERROR_NONE) {
9178 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9179 if (_mmplayer_is_sdp_file(path)) {
9180 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9181 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9183 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9185 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9186 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9188 LOGE("invalid uri, could not play..");
9189 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9192 MMPLAYER_FREEIF(location);
9197 static mmplayer_video_decoded_data_info_t *
9198 __mmplayer_create_stream_from_pad(GstPad *pad)
9200 GstCaps *caps = NULL;
9201 GstStructure *structure = NULL;
9202 unsigned int fourcc = 0;
9203 const gchar *string_format = NULL;
9204 mmplayer_video_decoded_data_info_t *stream = NULL;
9206 MMPixelFormatType format;
9209 caps = gst_pad_get_current_caps(pad);
9211 LOGE("Caps is NULL.");
9216 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9218 structure = gst_caps_get_structure(caps, 0);
9219 gst_structure_get_int(structure, "width", &width);
9220 gst_structure_get_int(structure, "height", &height);
9221 string_format = gst_structure_get_string(structure, "format");
9224 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9225 format = _mmplayer_get_pixtype(fourcc);
9226 gst_video_info_from_caps(&info, caps);
9227 gst_caps_unref(caps);
9230 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9231 LOGE("Wrong condition!!");
9235 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9237 LOGE("failed to alloc mem for video data");
9241 stream->width = width;
9242 stream->height = height;
9243 stream->format = format;
9244 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9250 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9252 unsigned int pitch = 0;
9253 unsigned int size = 0;
9255 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9258 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9259 bo = gst_tizen_memory_get_bos(mem, index);
9261 stream->bo[index] = tbm_bo_ref(bo);
9263 LOGE("failed to get bo for index %d", index);
9266 for (index = 0; index < stream->plane_num; index++) {
9267 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9268 stream->stride[index] = pitch;
9270 stream->elevation[index] = size / pitch;
9272 stream->elevation[index] = stream->height;
9277 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9279 if (stream->format == MM_PIXEL_FORMAT_I420) {
9280 int ret = TBM_SURFACE_ERROR_NONE;
9281 tbm_surface_h surface;
9282 tbm_surface_info_s info;
9284 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9286 ret = tbm_surface_get_info(surface, &info);
9287 if (ret != TBM_SURFACE_ERROR_NONE) {
9288 tbm_surface_destroy(surface);
9292 tbm_surface_destroy(surface);
9293 stream->stride[0] = info.planes[0].stride;
9294 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9295 stream->stride[1] = info.planes[1].stride;
9296 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9297 stream->stride[2] = info.planes[2].stride;
9298 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9299 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9300 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9301 stream->stride[0] = stream->width * 4;
9302 stream->elevation[0] = stream->height;
9303 stream->bo_size = stream->stride[0] * stream->height;
9305 LOGE("Not support format %d", stream->format);
9313 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9315 tbm_bo_handle thandle;
9317 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9318 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9319 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9323 unsigned char *src = NULL;
9324 unsigned char *dest = NULL;
9325 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9327 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9329 LOGE("fail to gst_memory_map");
9333 if (!mapinfo.data) {
9334 LOGE("data pointer is wrong");
9338 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9339 if (!stream->bo[0]) {
9340 LOGE("Fail to tbm_bo_alloc!!");
9344 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9346 LOGE("thandle pointer is wrong");
9350 if (stream->format == MM_PIXEL_FORMAT_I420) {
9351 src_stride[0] = GST_ROUND_UP_4(stream->width);
9352 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9353 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9354 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9357 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9358 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9360 for (i = 0; i < 3; i++) {
9361 src = mapinfo.data + src_offset[i];
9362 dest = thandle.ptr + dest_offset[i];
9367 for (j = 0; j < stream->height >> k; j++) {
9368 memcpy(dest, src, stream->width>>k);
9369 src += src_stride[i];
9370 dest += stream->stride[i];
9373 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9374 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9376 LOGE("Not support format %d", stream->format);
9380 tbm_bo_unmap(stream->bo[0]);
9381 gst_memory_unmap(mem, &mapinfo);
9387 tbm_bo_unmap(stream->bo[0]);
9390 gst_memory_unmap(mem, &mapinfo);
9396 __mmplayer_set_pause_state(mmplayer_t *player)
9398 if (player->sent_bos)
9401 /* rtsp case, get content attrs by GstMessage */
9402 if (MMPLAYER_IS_RTSP_STREAMING(player))
9405 /* it's first time to update all content attrs. */
9406 _mmplayer_update_content_attrs(player, ATTR_ALL);
9410 __mmplayer_set_playing_state(mmplayer_t *player)
9412 gchar *audio_codec = NULL;
9414 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9415 /* initialize because auto resume is done well. */
9416 player->resumed_by_rewind = FALSE;
9417 player->playback_rate = 1.0;
9420 if (player->sent_bos)
9423 /* try to get content metadata */
9425 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9426 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9427 * legacy mmfw-player api
9429 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9431 if ((player->cmd == MMPLAYER_COMMAND_START)
9432 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9433 __mmplayer_handle_missed_plugin(player);
9436 /* check audio codec field is set or not
9437 * we can get it from typefinder or codec's caps.
9439 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9441 /* The codec format can't be sent for audio only case like amr, mid etc.
9442 * Because, parser don't make related TAG.
9443 * So, if it's not set yet, fill it with found data.
9446 if (g_strrstr(player->type, "audio/midi"))
9447 audio_codec = "MIDI";
9448 else if (g_strrstr(player->type, "audio/x-amr"))
9449 audio_codec = "AMR";
9450 else if (g_strrstr(player->type, "audio/mpeg")
9451 && !g_strrstr(player->type, "mpegversion=(int)1"))
9452 audio_codec = "AAC";
9454 audio_codec = "unknown";
9456 if (mm_player_set_attribute((MMHandleType)player, NULL,
9457 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9458 LOGE("failed to set attribute");
9460 LOGD("set audio codec type with caps");