X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fmm_player_gst.c;h=da38d539c7b484bcacae974fd8f6bc2f6aedc01d;hb=fb4ccd152b91377ac03a0cbd9e2bb644f766c046;hp=eac4eaf4911e61bf1fd172d213285dc612510437;hpb=b985487642ef5eac00bb5b6c64a91af135e19609;p=platform%2Fcore%2Fmultimedia%2Flibmm-player.git diff --git a/src/mm_player_gst.c b/src/mm_player_gst.c index eac4eaf..da38d53 100644 --- a/src/mm_player_gst.c +++ b/src/mm_player_gst.c @@ -42,58 +42,56 @@ ========================================================================================== */ /*--------------------------------------------------------------------------- -| GLOBAL CONSTANT DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| IMPORTED VARIABLE DECLARATIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| IMPORTED FUNCTION DECLARATIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL #defines: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- | LOCAL CONSTANT DEFINITIONS: | ---------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL DATA TYPE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| GLOBAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ - -/*--------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------*/ +#define MMPLAYER_TAG_INDENT 3 /*=========================================================================================== | | | FUNCTION DEFINITIONS | | | ========================================================================================== */ +#ifdef __DEBUG__ +static void +print_tag(const GstTagList *list, const gchar *tag, gpointer unused) +{ + gint i, count; + + count = gst_tag_list_get_tag_size(list, tag); + + LOGD("count = %d", count); + + for (i = 0; i < count; i++) { + gchar *str; + + if (gst_tag_get_type(tag) == G_TYPE_STRING) { + if (!gst_tag_list_get_string_index(list, tag, i, &str)) + g_assert_not_reached(); + } else { + str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i)); + } + + if (i == 0) + g_print(" %15s: %s", gst_tag_get_nick(tag), str); + else + g_print(" : %s", str); + + g_free(str); + } +} +#endif static gboolean __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *src_element_name) { /* check whether the error is posted from not-activated track or not */ int msg_src_pos = 0; - gint active_pad_index = 0; + gint active_index = 0; MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst, TRUE); - active_pad_index = player->selector[MM_PLAYER_TRACK_TYPE_AUDIO].active_pad_index; - LOGD("current active pad index -%d", active_pad_index); + active_index = player->track[MM_PLAYER_TRACK_TYPE_AUDIO].active_track_index; + LOGD("current active pad index -%d", active_index); if (src_element_name) { int idx = 0; @@ -111,10 +109,10 @@ __mmplayer_check_error_posted_from_activated_track(mmplayer_t *player, gchar *sr idx++; } } - LOGD("active pad = %d, error src index = %d", active_pad_index, msg_src_pos); + LOGD("active pad = %d, error src index = %d", active_index, msg_src_pos); } - if (active_pad_index != msg_src_pos) { + if (active_index != msg_src_pos) { LOGD("skip error because error is posted from no activated track"); return FALSE; } @@ -214,9 +212,6 @@ __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GErro player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); src_element = GST_ELEMENT_CAST(message->src); - if (!src_element) - return MM_ERROR_PLAYER_INTERNAL; - src_element_name = GST_ELEMENT_NAME(src_element); if (!src_element_name) return MM_ERROR_PLAYER_INTERNAL; @@ -232,7 +227,8 @@ __mmplayer_gst_transform_gsterror(mmplayer_t *player, GstMessage *message, GErro LOGD("error code=%d, msg=%s, src element=%s, class=%s", error->code, error->message, src_element_name, klass); - if (!__mmplayer_check_error_posted_from_activated_track(player, src_element_name)) + if (MMPLAYER_USE_DECODEBIN(player) && + !__mmplayer_check_error_posted_from_activated_track(player, src_element_name)) return MM_ERROR_NONE; switch (error->code) { @@ -658,7 +654,7 @@ __mmplayer_handle_streaming_error(mmplayer_t *player, GstMessage *message) if (message->src) { msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src)); - LOGE("-Msg src : [%s] Code : [%x] Error : [%s]", + LOGE("-Msg src : [%s] Code : [0x%x] Error : [%s]", msg_src_element, msg_param.code, (char *)msg_param.data); } @@ -717,7 +713,7 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) { /* macro for better code readability */ -#define MMPLAYER_UPDATE_TAG_STRING(gsttag, attribute, playertag) \ +#define MMPLAYER_UPDATE_TAG_STRING(gsttag, player, playertag) \ do { \ if (gst_tag_list_get_string(tag_list, gsttag, &string)) {\ if (string != NULL) { \ @@ -726,17 +722,19 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) char *new_string = g_malloc(MM_MAX_STRING_LENGTH); \ strncpy(new_string, string, MM_MAX_STRING_LENGTH - 1); \ new_string[MM_MAX_STRING_LENGTH - 1] = '\0'; \ - mm_attrs_set_string_by_name(attribute, playertag, new_string); \ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, new_string, strlen(new_string), NULL); \ MMPLAYER_FREEIF(new_string); \ } else { \ - mm_attrs_set_string_by_name(attribute, playertag, string); \ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, string, strlen(string), NULL); \ } \ MMPLAYER_FREEIF(string); \ } \ } \ } while (0) -#define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, attribute, playertag) \ +#define MMPLAYER_UPDATE_TAG_IMAGE(gsttag, player, playertag) \ do { \ GstSample *sample = NULL;\ if (gst_tag_list_get_sample_index(tag_list, gsttag, index, &sample)) {\ @@ -752,7 +750,8 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) player->album_art = (gchar *)g_malloc(info.size);\ if (player->album_art) {\ memcpy(player->album_art, info.data, info.size);\ - mm_attrs_set_data_by_name(attribute, playertag, (void *)player->album_art, info.size);\ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, (void *)player->album_art, info.size, NULL); \ if (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) {\ msg_param.data = (void *)player->album_art;\ msg_param.size = info.size;\ @@ -765,7 +764,7 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) } \ } while (0) -#define MMPLAYER_UPDATE_TAG_UINT(gsttag, attribute, playertag) \ +#define MMPLAYER_UPDATE_TAG_UINT(gsttag, player, playertag) \ do { \ if (gst_tag_list_get_uint(tag_list, gsttag, &v_uint)) { \ if (v_uint) { \ @@ -779,34 +778,38 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) track_type = MM_PLAYER_TRACK_TYPE_TEXT; \ if (!strncmp(gsttag, GST_TAG_BITRATE, strlen(GST_TAG_BITRATE))) { \ if (track_type == MM_PLAYER_TRACK_TYPE_AUDIO) \ - mm_attrs_set_int_by_name(attribute, "content_audio_bitrate", v_uint); \ + mm_player_set_attribute((MMHandleType)player, NULL,\ + "content_audio_bitrate", v_uint, NULL); \ player->bitrate[track_type] = v_uint; \ player->total_bitrate = 0; \ for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \ player->total_bitrate += player->bitrate[i]; \ - mm_attrs_set_int_by_name(attribute, playertag, player->total_bitrate); \ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, player->total_bitrate, NULL); \ SECURE_LOGD("update bitrate %d[bps] of stream #%d.", v_uint, (int)track_type); \ } else if (!strncmp(gsttag, GST_TAG_MAXIMUM_BITRATE, strlen(GST_TAG_MAXIMUM_BITRATE))) { \ player->maximum_bitrate[track_type] = v_uint; \ player->total_maximum_bitrate = 0; \ for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) \ player->total_maximum_bitrate += player->maximum_bitrate[i]; \ - mm_attrs_set_int_by_name(attribute, playertag, player->total_maximum_bitrate);\ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, player->total_maximum_bitrate, NULL); \ SECURE_LOGD("update maximum bitrate %d[bps] of stream #%d", v_uint, (int)track_type);\ } else { \ - mm_attrs_set_int_by_name(attribute, playertag, v_uint); \ + mm_player_set_attribute((MMHandleType)player, NULL, playertag, v_uint, NULL); \ } \ v_uint = 0;\ } \ } \ } while (0) -#define MMPLAYER_UPDATE_TAG_DATE(gsttag, attribute, playertag) \ +#define MMPLAYER_UPDATE_TAG_DATE(gsttag, player, playertag) \ do { \ if (gst_tag_list_get_date(tag_list, gsttag, &date)) {\ if (date != NULL) {\ string = g_strdup_printf("%d", g_date_get_year(date));\ - mm_attrs_set_string_by_name(attribute, playertag, string);\ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, string, strlen(string), NULL); \ SECURE_LOGD("metainfo year : %s", string);\ MMPLAYER_FREEIF(string);\ g_date_free(date);\ @@ -814,12 +817,13 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) } \ } while (0) -#define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, attribute, playertag) \ +#define MMPLAYER_UPDATE_TAG_DATE_TIME(gsttag, player, playertag) \ do { \ if (gst_tag_list_get_date_time(tag_list, gsttag, &datetime)) {\ if (datetime != NULL) {\ string = g_strdup_printf("%d", gst_date_time_get_year(datetime));\ - mm_attrs_set_string_by_name(attribute, playertag, string);\ + mm_player_set_attribute((MMHandleType)player, NULL,\ + playertag, string, strlen(string), NULL); \ SECURE_LOGD("metainfo year : %s", string);\ MMPLAYER_FREEIF(string);\ gst_date_time_unref(datetime);\ @@ -827,33 +831,9 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) } \ } while (0) -#define MMPLAYER_UPDATE_TAG_UINT64(gsttag, attribute, playertag) \ - do { \ - if (gst_tag_list_get_uint64(tag_list, gsttag, &v_uint64)) {\ - if (v_uint64) {\ - /* FIXIT : don't know how to store date */\ - g_assert(1);\ - v_uint64 = 0;\ - } \ - } \ - } while (0) - -#define MMPLAYER_UPDATE_TAG_DOUBLE(gsttag, attribute, playertag) \ - do { \ - if (gst_tag_list_get_double(tag_list, gsttag, &v_double)) {\ - if (v_double) {\ - /* FIXIT : don't know how to store date */\ - g_assert(1);\ - v_double = 0;\ - } \ - } \ - } while (0) - /* function start */ GstTagList *tag_list = NULL; - MMHandleType attrs = 0; - char *string = NULL; guint v_uint = 0; GDate *date = NULL; @@ -869,69 +849,34 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) MMPLAYER_RETURN_VAL_IF_FAIL(player && msg, FALSE); - attrs = MMPLAYER_GET_ATTRS(player); - - MMPLAYER_RETURN_VAL_IF_FAIL(attrs, FALSE); - /* get tag list from gst message */ gst_message_parse_tag(msg, &tag_list); /* store tags to player attributes */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, attrs, "tag_title"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, attrs, "tag_artist"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, attrs, "tag_album"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM_SORTNAME, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, attrs, "tag_author"); - MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, attrs, "tag_date"); - MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, attrs, "tag_date"); - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, attrs, "tag_genre"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMMENT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_EXTENDED_COMMENT, ?, ?); */ - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, attrs, "tag_track_num"); - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_COUNT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_NUMBER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ALBUM_VOLUME_COUNT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LOCATION, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, attrs, "tag_description"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VERSION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ISRC, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ORGANIZATION, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, attrs, "tag_copyright"); - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT_URI, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CONTACT, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LICENSE_URI, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_PERFORMER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT64(GST_TAG_DURATION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_CODEC, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, attrs, "content_video_codec"); - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, attrs, "content_audio_codec"); - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, attrs, "content_bitrate"); - MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, attrs, "content_max_bitrate"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_TITLE, player, "tag_title"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ARTIST, player, "tag_artist"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ALBUM, player, "tag_album"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COMPOSER, player, "tag_author"); + MMPLAYER_UPDATE_TAG_DATE(GST_TAG_DATE, player, "tag_date"); + MMPLAYER_UPDATE_TAG_DATE_TIME(GST_TAG_DATE_TIME, player, "tag_date"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_GENRE, player, "tag_genre"); + MMPLAYER_UPDATE_TAG_UINT(GST_TAG_TRACK_NUMBER, player, "tag_track_num"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_DESCRIPTION, player, "tag_description"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_COPYRIGHT, player, "tag_copyright"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_VIDEO_CODEC, player, "content_video_codec"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_AUDIO_CODEC, player, "content_audio_codec"); + MMPLAYER_UPDATE_TAG_UINT(GST_TAG_BITRATE, player, "content_bitrate"); + MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MAXIMUM_BITRATE, player, "content_max_bitrate"); MMPLAYER_UPDATE_TAG_LOCK(player); - MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, attrs, "tag_album_cover"); + MMPLAYER_UPDATE_TAG_IMAGE(GST_TAG_IMAGE, player, "tag_album_cover"); MMPLAYER_UPDATE_TAG_UNLOCK(player); - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_NOMINAL_BITRATE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_MINIMUM_BITRATE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_SERIAL, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_ENCODER, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_UINT(GST_TAG_ENCODER_VERSION, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_GAIN, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_TRACK_PEAK, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_GAIN, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_ALBUM_PEAK, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_REFERENCE_LEVEL, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_STRING(GST_TAG_LANGUAGE_CODE, ?, ?); */ - /* MMPLAYER_UPDATE_TAG_DOUBLE(GST_TAG_BEATS_PER_MINUTE, ?, ?); */ - MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, attrs, "content_video_orientation"); + MMPLAYER_UPDATE_TAG_STRING(GST_TAG_IMAGE_ORIENTATION, player, "content_video_orientation"); if (strstr(GST_OBJECT_NAME(msg->src), "demux")) { if (player->video360_metadata.is_spherical == -1) { __mmplayer_get_metadata_360_from_tags(tag_list, &player->video360_metadata); - mm_attrs_set_int_by_name(attrs, "content_video_is_spherical", - player->video360_metadata.is_spherical); + mm_player_set_attribute((MMHandleType)player, NULL, + "content_video_is_spherical", player->video360_metadata.is_spherical, NULL); if (player->video360_metadata.is_spherical == 1) { LOGD("This is spherical content for 360 playback."); player->is_content_spherical = TRUE; @@ -964,9 +909,6 @@ __mmplayer_gst_extract_tag_from_msg(mmplayer_t *player, GstMessage *msg) } } - if (mm_attrs_commit_all(attrs)) - LOGE("failed to commit."); - gst_tag_list_unref(tag_list); return TRUE; @@ -993,6 +935,7 @@ __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message) case GST_MESSAGE_ELEMENT: case GST_MESSAGE_DURATION_CHANGED: case GST_MESSAGE_ASYNC_START: + case GST_MESSAGE_STREAM_COLLECTION: retval = TRUE; break; case GST_MESSAGE_ASYNC_DONE: @@ -1028,6 +971,36 @@ __mmplayer_gst_check_useful_message(mmplayer_t *player, GstMessage *message) break; } + case GST_MESSAGE_STREAMS_SELECTED: + { + if (MMPLAYER_USE_DECODEBIN(player)) + break; /* drop msg */ + + if ((MMPLAYER_IS_HTTP_STREAMING(player)) && + (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) && + (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) { + + gint64 dur_bytes = 0L; + + if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + LOGE("fail to get duration."); + + /* there is no mq, enable use-buffering on queue2 (ex) wav streaming + * use file information was already set on Q2 when it was created. */ + _mm_player_streaming_set_queue2(player->streamer, + player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst, + TRUE, /* use_buffering */ + MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */ + ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0)); + } + + LOGD("GST_MESSAGE_STREAMS_SELECTED"); + player->no_more_pad = TRUE; + _mmplayer_set_reconfigure_state(player, FALSE); + _mmplayer_pipeline_complete(NULL, player); + retval = TRUE; + break; + } default: retval = FALSE; break; @@ -1044,14 +1017,14 @@ __mmplayer_update_buffer_setting(mmplayer_t *player, GstMessage *buffering_msg) MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - __mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */ + _mmplayer_gst_get_position(player, &pos_nsec); /* to update player->last_position */ if (MMPLAYER_IS_HTTP_STREAMING(player)) { data_size = player->http_content_size; } - __mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration); - __mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); + _mm_player_streaming_buffering(player->streamer, buffering_msg, data_size, player->last_position, player->duration); + _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst); return; } @@ -1090,7 +1063,7 @@ __mmplayer_handle_buffering_playback(mmplayer_t *player) { switch (pending_state) { case MM_PLAYER_STATE_PLAYING: - __mmplayer_gst_pause(player, TRUE); + _mmplayer_gst_pause(player, TRUE); break; case MM_PLAYER_STATE_PAUSED: @@ -1113,7 +1086,7 @@ __mmplayer_handle_buffering_playback(mmplayer_t *player) case MM_PLAYER_STATE_NONE: { if (current_state != MM_PLAYER_STATE_PLAYING) - __mmplayer_gst_resume(player, TRUE); + _mmplayer_gst_resume(player, TRUE); } break; @@ -1122,12 +1095,12 @@ __mmplayer_handle_buffering_playback(mmplayer_t *player) * Because, buffering can be completed during autoplugging when pipeline would try to go playing state directly. */ if (current_state == MM_PLAYER_STATE_PLAYING) { - /* NOTE: If the current state is PLAYING, it means, async __mmplayer_gst_pause() is not completed yet. + /* NOTE: If the current state is PLAYING, it means, async _mmplayer_gst_pause() is not completed yet. * The current state should be changed to paused purposely to prevent state conflict. */ MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED); } - __mmplayer_gst_resume(player, TRUE); + _mmplayer_gst_resume(player, TRUE); break; case MM_PLAYER_STATE_PLAYING: @@ -1161,7 +1134,7 @@ __mmplayer_handle_buffering_playback(mmplayer_t *player) /* rtsp streaming pause makes rtsp server stop sending data. */ if (!MMPLAYER_IS_RTSP_STREAMING(player)) { LOGD("set pause state during buffering"); - __mmplayer_gst_pause(player, TRUE); + _mmplayer_gst_pause(player, TRUE); } } } @@ -1170,7 +1143,7 @@ __mmplayer_handle_buffering_playback(mmplayer_t *player) case MM_PLAYER_STATE_PLAYING: /* rtsp streaming pause makes rtsp server stop sending data. */ if (!MMPLAYER_IS_RTSP_STREAMING(player)) - __mmplayer_gst_pause(player, TRUE); + _mmplayer_gst_pause(player, TRUE); break; case MM_PLAYER_STATE_PAUSED: @@ -1222,7 +1195,7 @@ __mmplayer_gst_handle_duration(mmplayer_t *player, GstMessage *msg) } } else { /* handling audio clip which has vbr. means duration is keep changing */ - __mmplayer_update_content_attrs(player, ATTR_DURATION); + _mmplayer_update_content_attrs(player, ATTR_DURATION); } MMPLAYER_FLEAVE(); @@ -1246,7 +1219,7 @@ __mmplayer_eos_timer_cb(gpointer u_data) if (count == -1) { gint ret_value = 0; - ret_value = __mmplayer_gst_set_position(player, 0, TRUE); + ret_value = _mmplayer_gst_set_position(player, 0, TRUE); if (ret_value != MM_ERROR_NONE) LOGE("seeking to 0 failed in repeat play"); } else { @@ -1269,13 +1242,13 @@ __mmplayer_handle_eos_delay(mmplayer_t *player, int delay_in_ms) MMPLAYER_POST_MSG(player, MM_MESSAGE_END_OF_STREAM, NULL); if (player->audio_decoded_cb) - __mmplayer_cancel_eos_timer(player); + _mmplayer_cancel_eos_timer(player); return; } /* cancel if existing */ - __mmplayer_cancel_eos_timer(player); + _mmplayer_cancel_eos_timer(player); /* init new timeout */ /* NOTE : consider give high priority to this timer */ @@ -1320,7 +1293,7 @@ __mmplayer_gst_pending_seek(mmplayer_t *player) LOGD("trying to play from(%"G_GINT64_FORMAT") pending position", player->pending_seek.pos); - ret = __mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE); + ret = _mmplayer_gst_set_position(player, player->pending_seek.pos, FALSE); if (ret != MM_ERROR_NONE) LOGE("failed to seek pending postion. just keep staying current position."); @@ -1410,7 +1383,7 @@ __mmplayer_gst_handle_eos_message(mmplayer_t *player, GstMessage *msg) __mmplayer_drop_subtitle(player, TRUE); if ((player->audio_decoded_cb) && (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK)) - __mmplayer_audio_stream_clear_buffer(player, TRUE); + _mmplayer_audio_stream_clear_buffer(player, TRUE); /* rewind if repeat count is greater then zero */ /* get play count */ @@ -1471,7 +1444,7 @@ __mmplayer_gst_handle_error_message(mmplayer_t *player, GstMessage *msg) __mmplayer_handle_streaming_error(player, msg); /* dump state of all element */ - __mmplayer_dump_pipeline_state(player); + _mmplayer_dump_pipeline_state(player); } else { /* traslate gst error code to msl error code. then post it * to application if needed @@ -1653,7 +1626,7 @@ __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg) int retVal = MM_ERROR_NONE; LOGD("trying to play from (%"G_GINT64_FORMAT") pending position", player->pending_seek.pos); - retVal = __mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE); + retVal = _mmplayer_gst_set_position(player, player->pending_seek.pos, TRUE); if (MM_ERROR_NONE != retVal) LOGE("failed to seek pending postion. just keep staying current position."); @@ -1682,7 +1655,7 @@ __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg) MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED); if (MMPLAYER_IS_STREAMING(player) && (player->streamer)) - __mm_player_streaming_set_content_bitrate(player->streamer, + _mm_player_streaming_set_content_bitrate(player->streamer, player->total_maximum_bitrate, player->total_bitrate); if (player->pending_seek.is_pending) { @@ -1719,7 +1692,7 @@ __mmplayer_gst_handle_state_message(mmplayer_t *player, GstMessage *msg) } if (player->gapless.stream_changed) { - __mmplayer_update_content_attrs(player, ATTR_ALL); + _mmplayer_update_content_attrs(player, ATTR_ALL); player->gapless.stream_changed = FALSE; } @@ -1745,17 +1718,10 @@ __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg) { const gchar *structure_name; gint count = 0, idx = 0; - MMHandleType attrs = 0; MMPLAYER_FENTER(); MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("Failed to get content attribute"); - return; - } - if (gst_message_get_structure(msg) == NULL) return; @@ -1797,19 +1763,21 @@ __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg) gint extra_num_buffers = 0; if (gst_structure_get_int(gst_message_get_structure(msg), "num_buffers", &num_buffers)) { - player->video_num_buffers = num_buffers; - LOGD("video_num_buffers : %d", player->video_num_buffers); + LOGD("video_num_buffers : %d", num_buffers); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, num_buffers, NULL); } if (gst_structure_get_int(gst_message_get_structure(msg), "extra_num_buffers", &extra_num_buffers)) { - player->video_extra_num_buffers = extra_num_buffers; LOGD("num_of_vout_extra num buffers : %d", extra_num_buffers); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, extra_num_buffers, NULL); } return; } if (!strcmp(structure_name, "Ext_Sub_Language_List")) - __mmplayer_track_update_text_attr_info(player, msg); + _mmplayer_track_update_text_attr_info(player, msg); /* custom message */ if (!strcmp(structure_name, "audio_codec_not_supported")) { @@ -1827,39 +1795,36 @@ __mmplayer_gst_handle_element_message(mmplayer_t *player, GstMessage *msg) gchar *video_codec = NULL; gchar *video_frame_size = NULL; - gst_structure_get(gst_message_get_structure(msg), "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL); + gst_structure_get(gst_message_get_structure(msg), + "rtsp_duration", G_TYPE_UINT64, &player->duration, NULL); LOGD("rtsp duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(player->duration)); - player->streaming_type = __mmplayer_get_stream_service_type(player); + player->streaming_type = _mmplayer_get_stream_service_type(player); - gst_structure_get(gst_message_get_structure(msg), "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL); + gst_structure_get(gst_message_get_structure(msg), + "rtsp_audio_codec", G_TYPE_STRING, &audio_codec, NULL); LOGD("rtsp_audio_codec : %s", audio_codec); if (audio_codec) - mm_attrs_set_string_by_name(attrs, "content_audio_codec", audio_codec); + mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_codec", audio_codec, strlen(audio_codec), NULL); - gst_structure_get(gst_message_get_structure(msg), "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL); + gst_structure_get(gst_message_get_structure(msg), + "rtsp_video_codec", G_TYPE_STRING, &video_codec, NULL); LOGD("rtsp_video_codec : %s", video_codec); if (video_codec) - mm_attrs_set_string_by_name(attrs, "content_video_codec", video_codec); + mm_player_set_attribute((MMHandleType)player, NULL, + "content_video_codec", video_codec, strlen(video_codec), NULL); - gst_structure_get(gst_message_get_structure(msg), "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL); + gst_structure_get(gst_message_get_structure(msg), + "rtsp_video_frame_size", G_TYPE_STRING, &video_frame_size, NULL); LOGD("rtsp_video_frame_size : %s", video_frame_size); if (video_frame_size) { - char *seperator = strchr(video_frame_size, '-'); - if (seperator) { - char video_width[10] = {0,}; - int frame_size_len = strlen(video_frame_size); - int separtor_len = strlen(seperator); - - strncpy(video_width, video_frame_size, (frame_size_len - separtor_len)); - mm_attrs_set_int_by_name(attrs, "content_video_width", atoi(video_width)); - - seperator++; - mm_attrs_set_int_by_name(attrs, "content_video_height", atoi(seperator)); - } + gchar **res_str = g_strsplit(video_frame_size, "-", 0); + mm_player_set_attribute((MMHandleType)player, NULL, + MM_PLAYER_VIDEO_WIDTH, atoi(res_str[0]), + MM_PLAYER_VIDEO_HEIGHT, atoi(res_str[1]), + NULL); + g_strfreev(res_str); } - - if (mm_attrs_commit_all(attrs)) - LOGE("failed to commit."); } MMPLAYER_FLEAVE(); @@ -1931,6 +1896,81 @@ __mmplayer_gst_handle_async_done_message(mmplayer_t *player, GstMessage *msg) } static void +__mmplayer_print_tag_foreach(const GstTagList *tags, const gchar *tag, gpointer user_data) +{ + GValue val = { 0, }; + gchar *str = NULL; + guint indent = GPOINTER_TO_UINT(user_data); + + if (!gst_tag_list_copy_value(&val, tags, tag)) + return; + + if (G_VALUE_HOLDS_STRING(&val)) + str = g_value_dup_string(&val); + else + str = gst_value_serialize(&val); + + LOGD("%*s%s: %s\n", 2 * indent, " ", gst_tag_get_nick(tag), str); + g_free(str); + g_value_unset(&val); +} + +static void +__mmplayer_dump_collection(GstStreamCollection * collection) +{ + guint i = 0; + GstTagList *tags = NULL; + GstCaps *caps = NULL; + + for (i = 0; i < gst_stream_collection_get_size(collection); i++) { + GstStream *stream = gst_stream_collection_get_stream(collection, i); + LOGD ("collection: Stream %u type %s flags 0x%x\n", i, + gst_stream_type_get_name(gst_stream_get_stream_type(stream)), + gst_stream_get_stream_flags(stream)); + LOGD (" ID: %s\n", gst_stream_get_stream_id(stream)); + + caps = gst_stream_get_caps(stream); + if (caps) { + gchar *caps_str = gst_caps_to_string(caps); + LOGD (" caps: %s\n", caps_str); + g_free(caps_str); + gst_caps_unref(caps); + } + + tags = gst_stream_get_tags(stream); + if (tags) { + LOGD (" tags:\n"); + gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT)); + gst_tag_list_unref(tags); + } + } +} + +static void +__mmplayer_stream_notify_cb(GstStreamCollection *collection, + GstStream *stream, GParamSpec *pspec, gpointer data) +{ + LOGD ("Got stream-notify from stream %s for %s (collection %p)\n", + gst_stream_get_stream_id(stream), pspec->name, collection); + if (g_str_equal(pspec->name, "caps")) { + GstCaps *caps = gst_stream_get_caps(stream); + gchar *caps_str = gst_caps_to_string(caps); + LOGD (" New caps: %s\n", caps_str); + g_free(caps_str); + gst_caps_unref(caps); + } + + if (g_str_equal (pspec->name, "tags")) { + GstTagList *tags = gst_stream_get_tags(stream); + if (tags) { + LOGD (" tags:\n"); + gst_tag_list_foreach(tags, __mmplayer_print_tag_foreach, GUINT_TO_POINTER(MMPLAYER_TAG_INDENT)); + gst_tag_list_unref(tags); + } + } +} + +static void __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data) { mmplayer_t *player = (mmplayer_t *)(data); @@ -1949,6 +1989,7 @@ __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data) break; case GST_MESSAGE_ERROR: + _mmplayer_set_reconfigure_state(player, FALSE); __mmplayer_gst_handle_error_message(player, msg); break; @@ -2000,8 +2041,8 @@ __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data) if (need_new_clock) { LOGD("Provide clock is TRUE, do pause->resume"); - __mmplayer_gst_pause(player, FALSE); - __mmplayer_gst_resume(player, FALSE); + _mmplayer_gst_pause(player, FALSE); + _mmplayer_gst_resume(player, FALSE); } } break; @@ -2033,8 +2074,45 @@ __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data) case GST_MESSAGE_ASYNC_DONE: __mmplayer_gst_handle_async_done_message(player, msg); break; + case GST_MESSAGE_STREAM_COLLECTION: + { + GstStreamCollection *collection = NULL; + LOGD("GST_MESSAGE_STREAM_COLLECTION : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); + + gst_message_parse_stream_collection(msg, &collection); + if (collection) { + __mmplayer_dump_collection(collection); + if (player->collection && player->stream_notify_id) { + g_signal_handler_disconnect(player->collection, player->stream_notify_id); + player->stream_notify_id = 0; + } + gst_object_replace((GstObject **)&player->collection, (GstObject *)collection); + if (player->collection) { + player->stream_notify_id = g_signal_connect(player->collection, "stream-notify", + (GCallback)__mmplayer_stream_notify_cb, player); + } + gst_object_unref(collection); + } + } break; + case GST_MESSAGE_STREAMS_SELECTED: + { + GstStreamCollection *collection = NULL; + LOGD("GST_MESSAGE_STREAMS_SELECTED : %s", GST_ELEMENT_NAME(GST_MESSAGE_SRC(msg))); + + gst_message_parse_streams_selected(msg, &collection); + if (collection) { + guint i = 0, len = 0; + len = gst_message_streams_selected_get_size(msg); + for (i = 0; i < len; i++) { + GstStream *stream = gst_message_streams_selected_get_stream(msg, i); + LOGD (" Stream #%d : %s\n", i, gst_stream_get_stream_id(stream)); + gst_object_unref(stream); + } + gst_object_unref (collection); + } + } break; - #if 0 /* delete unnecessary logs */ +#ifdef __DEBUG__ case GST_MESSAGE_REQUEST_STATE: LOGD("GST_MESSAGE_REQUEST_STATE"); break; case GST_MESSAGE_STEP_START: LOGD("GST_MESSAGE_STEP_START"); break; case GST_MESSAGE_QOS: LOGD("GST_MESSAGE_QOS"); break; @@ -2050,7 +2128,7 @@ __mmplayer_gst_bus_msg_callback(GstMessage *msg, gpointer data) case GST_MESSAGE_SEGMENT_START: LOGD("GST_MESSAGE_SEGMENT_START"); break; case GST_MESSAGE_SEGMENT_DONE: LOGD("GST_MESSAGE_SEGMENT_DONE"); break; case GST_MESSAGE_LATENCY: LOGD("GST_MESSAGE_LATENCY"); break; - #endif +#endif default: break; @@ -2080,7 +2158,7 @@ __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data case GST_MESSAGE_TAG: __mmplayer_gst_extract_tag_from_msg(player, message); - #if 0 // debug +#ifdef __DEBUG__ { GstTagList *tags = NULL; @@ -2095,12 +2173,24 @@ __mmplayer_gst_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data } break; } - #endif +#endif break; case GST_MESSAGE_DURATION_CHANGED: __mmplayer_gst_handle_duration(player, message); break; + case GST_MESSAGE_ELEMENT: + { + const gchar *klass = NULL; + klass = gst_element_factory_get_metadata + (gst_element_get_factory((GstElement *)message->src), GST_ELEMENT_METADATA_KLASS); + if (!klass || !g_strrstr(klass, "Codec/Decoder")) { + reply = GST_BUS_PASS; + break; + } + __mmplayer_gst_handle_element_message(player, message); + } + break; case GST_MESSAGE_ASYNC_DONE: /* NOTE:Don't call gst_callback directly * because previous frame can be showed even though this message is received for seek. @@ -2148,7 +2238,9 @@ __mmplayer_gst_appsrc_feed_data_mem(GstElement *element, guint size, gpointer us GST_BUFFER_OFFSET(buffer) = (guint64)buf->offset; GST_BUFFER_OFFSET_END(buffer) = (guint64)(buf->offset + len); - //LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len); +#ifdef __DEBUG__ + LOGD("feed buffer %p, offset %u-%u length %u", buffer, buf->offset, (buf->offset+len), len); +#endif g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret); buf->offset += len; @@ -2170,89 +2262,89 @@ void __mmplayer_gst_appsrc_feed_data(GstElement *element, guint size, gpointer user_data) { mmplayer_t *player = (mmplayer_t *)user_data; - mmplayer_stream_type_e type = MM_PLAYER_STREAM_TYPE_DEFAULT; + mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT; + MMMessageParamType msg_param = {0,}; guint64 current_level_bytes = 0; MMPLAYER_RETURN_IF_FAIL(player); if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) { - type = MM_PLAYER_STREAM_TYPE_AUDIO; + stream_type = MM_PLAYER_STREAM_TYPE_AUDIO; } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) { - type = MM_PLAYER_STREAM_TYPE_VIDEO; - } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) { - type = MM_PLAYER_STREAM_TYPE_TEXT; + stream_type = MM_PLAYER_STREAM_TYPE_VIDEO; } else { - LOGE("can not enter here"); + LOGW("invalid feed-data signal from %s", GST_ELEMENT_NAME(element)); return; } g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); - LOGI("type: %d, level: %"G_GUINT64_FORMAT, type, current_level_bytes); + LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes); + + msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS; + msg_param.buffer_status.stream_type = stream_type; + msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN; + msg_param.buffer_status.bytes = current_level_bytes; - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_UNDERRUN, current_level_bytes, player->buffer_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param); } void __mmplayer_gst_appsrc_enough_data(GstElement *element, gpointer user_data) { mmplayer_t *player = (mmplayer_t *)user_data; - mmplayer_stream_type_e type = MM_PLAYER_STREAM_TYPE_DEFAULT; + mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT; + MMMessageParamType msg_param = {0,}; guint64 current_level_bytes = 0; MMPLAYER_RETURN_IF_FAIL(player); if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) { - type = MM_PLAYER_STREAM_TYPE_AUDIO; + stream_type = MM_PLAYER_STREAM_TYPE_AUDIO; } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) { - type = MM_PLAYER_STREAM_TYPE_VIDEO; - } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) { - type = MM_PLAYER_STREAM_TYPE_TEXT; + stream_type = MM_PLAYER_STREAM_TYPE_VIDEO; } else { - LOGE("can not enter here"); + LOGW("invalid enough-data signal from %s", GST_ELEMENT_NAME(element)); return; } - LOGI("type: %d, buffer is full", type); - g_object_get(G_OBJECT(element), "current-level-bytes", ¤t_level_bytes, NULL); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); + LOGI("stream type: %d, level: %"G_GUINT64_FORMAT, stream_type, current_level_bytes); - if (player->media_stream_buffer_status_cb[type]) - player->media_stream_buffer_status_cb[type](type, MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW, current_level_bytes, player->buffer_cb_user_param[type]); + msg_param.union_type = MM_MSG_UNION_BUFFER_STATUS; + msg_param.buffer_status.stream_type = stream_type; + msg_param.buffer_status.status = MM_PLAYER_MEDIA_STREAM_BUFFER_OVERFLOW; + msg_param.buffer_status.bytes = current_level_bytes; - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_STATUS, &msg_param); } gboolean __mmplayer_gst_appsrc_seek_data(GstElement *element, guint64 position, gpointer user_data) { mmplayer_t *player = (mmplayer_t *)user_data; - mmplayer_stream_type_e type = MM_PLAYER_STREAM_TYPE_DEFAULT; + mmplayer_stream_type_e stream_type = MM_PLAYER_STREAM_TYPE_DEFAULT; + MMMessageParamType msg_param = {0,}; MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); if (g_strrstr(GST_ELEMENT_NAME(element), "audio")) { - type = MM_PLAYER_STREAM_TYPE_AUDIO; + stream_type = MM_PLAYER_STREAM_TYPE_AUDIO; } else if (g_strrstr(GST_ELEMENT_NAME(element), "video")) { - type = MM_PLAYER_STREAM_TYPE_VIDEO; - } else if (g_strrstr(GST_ELEMENT_NAME(element), "subtitle")) { - type = MM_PLAYER_STREAM_TYPE_TEXT; + stream_type = MM_PLAYER_STREAM_TYPE_VIDEO; } else { - LOGE("can not enter here"); + LOGW("invalid seek-data signal from %s", GST_ELEMENT_NAME(element)); return TRUE; } - LOGD("type: %d, pos: %"G_GUINT64_FORMAT, type, position); - MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player); + LOGD("stream type: %d, pos: %"G_GUINT64_FORMAT, stream_type, position); + + msg_param.union_type = MM_MSG_UNION_SEEK_DATA; + msg_param.seek_data.stream_type = stream_type; + msg_param.seek_data.offset = position; - if (player->media_stream_seek_data_cb[type]) - player->media_stream_seek_data_cb[type](type, position, player->seek_cb_user_param[type]); - MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player); + MMPLAYER_POST_MSG(player, MM_MESSAGE_PUSH_BUFFER_SEEK_DATA, &msg_param); return TRUE; } @@ -2312,17 +2404,21 @@ __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type mainbin[elem_id].gst = decodebin; /* raw pad handling signal */ - __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", - G_CALLBACK(__mmplayer_gst_decode_pad_added), (gpointer)player); + _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player); /* This signal is emitted whenever decodebin finds a new stream. It is emitted before looking for any elements that can handle that stream.*/ - __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", - G_CALLBACK(__mmplayer_gst_decode_autoplug_select), (gpointer)player); + _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", + G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player); + + if (player->need_video_dec_sorting || player->need_audio_dec_sorting) + _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort", + G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player); /* This signal is emitted when a element is added to the bin.*/ - __mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", - G_CALLBACK(__mmplayer_gst_element_added), (gpointer)player); + _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added", + G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player); if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) { LOGE("failed to add new decodebin"); @@ -2331,7 +2427,9 @@ __mmplayer_gst_create_es_decoder(mmplayer_t *player, mmplayer_stream_type_e type dec_caps = gst_pad_query_caps(srcpad, NULL); if (dec_caps) { - //LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps); +#ifdef __DEBUG__ + LOGD("got pad %s:%s , dec_caps %" GST_PTR_FORMAT, GST_DEBUG_PAD_NAME(srcpad), dec_caps); +#endif g_object_set(G_OBJECT(decodebin), "sink-caps", dec_caps, NULL); gst_caps_unref(dec_caps); } @@ -2435,11 +2533,11 @@ __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, G /*Fix Seek External Demuxer: set audio and video appsrc as seekable */ gst_app_src_set_stream_type((GstAppSrc*)G_OBJECT(src), GST_APP_STREAM_TYPE_SEEKABLE); - __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", G_CALLBACK(__mmplayer_gst_appsrc_seek_data), (gpointer)player); - __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", G_CALLBACK(__mmplayer_gst_appsrc_feed_data), (gpointer)player); - __mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", + _mmplayer_add_signal_connection(player, G_OBJECT(src), MM_PLAYER_SIGNAL_TYPE_OTHERS, "enough-data", G_CALLBACK(__mmplayer_gst_appsrc_enough_data), (gpointer)player); /* create queue */ @@ -2476,7 +2574,7 @@ __mmplayer_gst_create_es_path(mmplayer_t *player, mmplayer_stream_type_e type, G } if (type == MM_PLAYER_STREAM_TYPE_TEXT) { - __mmplayer_gst_create_decoder(player, srcpad, caps); + _mmplayer_gst_create_decoder(player, srcpad, caps); } else { if (!__mmplayer_gst_create_es_decoder(player, type, srcpad)) { LOGE("failed to create decoder"); @@ -2555,7 +2653,7 @@ __mmplayer_gst_rtp_dynamic_pad(GstElement *element, GstPad *pad, gpointer data) } } - if (!__mmplayer_gst_create_decoder(player, pad, caps)) { + if (!_mmplayer_gst_create_decoder(player, pad, caps)) { LOGE("failed to autoplug for caps"); goto ERROR; } @@ -2643,9 +2741,9 @@ __mmplayer_gst_rtp_no_more_pads(GstElement *element, gpointer data) if (player->num_dynamic_pad == 0) { LOGD("it seems pad caps is directely used for autoplugging. removing fakesink now"); - if (!__mmplayer_gst_remove_fakesink(player, + if (!_mmplayer_gst_remove_fakesink(player, &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) - /* NOTE : __mmplayer_pipeline_complete() can be called several time. because + /* NOTE : _mmplayer_pipeline_complete() can be called several time. because * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various * source element are not same. To overcome this situation, this function will called * several places and several times. Therefore, this is not an error case. @@ -2694,22 +2792,441 @@ __mmplayer_gst_make_rtsp_src(mmplayer_t *player) if (user_agent) g_object_set(G_OBJECT(element), "user-agent", user_agent, NULL); - __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", + _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_rtp_dynamic_pad), (gpointer)player); - __mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", + _mmplayer_add_signal_connection(player, G_OBJECT(element), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_rtp_no_more_pads), (gpointer)player); MMPLAYER_FLEAVE(); return element; } +void __mmplayer_http_src_setup(GstElement *source, gpointer data) +{ +#define HTTP_SOURCE_BLOCK_SIZE (64 * 1024) + + mmplayer_t *player = (mmplayer_t *)data; + MMHandleType attrs = 0; + gchar *user_agent, *cookies, **cookie_list; + gint http_timeout = DEFAULT_HTTP_TIMEOUT; + user_agent = cookies = NULL; + cookie_list = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player); + + LOGD("source element %s", GST_ELEMENT_NAME(source)); + + /* get profile attribute */ + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) { + LOGE("failed to get content attribute"); + return; + } + + /* get attribute */ + mm_attrs_get_string_by_name(attrs, "streaming_cookie", &cookies); + mm_attrs_get_string_by_name(attrs, "streaming_user_agent", &user_agent); + + if (player->ini.http_timeout != DEFAULT_HTTP_TIMEOUT) + http_timeout = player->ini.http_timeout; + + /* get attribute */ + SECURE_LOGD("cookies : %s", cookies); + SECURE_LOGD("user_agent : %s", user_agent); + LOGD("timeout : %d", http_timeout); + + /* setting property to streaming source */ + g_object_set(G_OBJECT(source), "timeout", http_timeout, "blocksize", (unsigned long)(HTTP_SOURCE_BLOCK_SIZE), NULL); + + /* parsing cookies */ + if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) { + g_object_set(G_OBJECT(source), "cookies", cookie_list, NULL); + g_strfreev(cookie_list); + } + + if (user_agent) + g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL); + + MMPLAYER_FLEAVE(); + return; +} + +static void +__mmplayer_gst_found_source(GObject *object, GObject *orig, GParamSpec *pspec, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + GstElement *source = NULL; + + MMPLAYER_FENTER(); + LOGD("%s >> %s", GST_ELEMENT_NAME(object), pspec->name); + + g_object_get(orig, pspec->name, &source, NULL); + + player->pipeline->mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; + player->pipeline->mainbin[MMPLAYER_M_SRC].gst = source; + + if (MMPLAYER_IS_HTTP_STREAMING(player)) { + __mmplayer_http_src_setup(source, data); + } else if (MMPLAYER_IS_RTSP_STREAMING(player)) { + gchar *user_agent = NULL; + + /* get attribute */ + mm_attrs_get_string_by_name(player->attrs, "streaming_user_agent", &user_agent); + + SECURE_LOGD("user_agent : %s", user_agent); + + /* setting property to streaming source */ + if (user_agent) + g_object_set(G_OBJECT(source), "user-agent", user_agent, NULL); + } else if (MMPLAYER_IS_SMOOTH_STREAMING(player)) { + g_object_set(G_OBJECT(source), "timeout", DEFAULT_HTTP_TIMEOUT, NULL); + } else if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) { + g_object_set(source, "stream-type", GST_APP_STREAM_TYPE_RANDOM_ACCESS, + "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL); + + _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem); + _mmplayer_add_signal_connection(player, G_OBJECT(source), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem); + } + MMPLAYER_FLEAVE(); +} + +static gint +__mmplayer_gst_select_stream (GstElement * uridecodebin, GstStreamCollection * collection, + GstStream * stream, gpointer data) +{ + gint ret = 0; /* 1: select, 0: skip, -1: depends on decodebin */ + GstStreamType stype = gst_stream_get_stream_type(stream); + mmplayer_t *player = (mmplayer_t *)data; + mmplayer_track_type_e type = MM_PLAYER_TRACK_TYPE_MAX; + GstCaps *caps = gst_stream_get_caps(stream); + gchar *caps_str = NULL; + + LOGD("Stream type %s flags 0x%x", + gst_stream_type_get_name(stype), + gst_stream_get_stream_flags(stream)); + LOGD(" ID: %s", gst_stream_get_stream_id(stream)); + + if (caps) { + caps_str = gst_caps_to_string(caps); + LOGD(" caps: %s", caps_str); + } + + switch (stype) { + case GST_STREAM_TYPE_AUDIO: + { + GstStructure *caps_structure = NULL; + gint samplerate = 0; + gint channels = 0; + + type = MM_PLAYER_TRACK_TYPE_AUDIO; + + if (caps) { + caps_structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(caps_structure, "rate", &samplerate); + gst_structure_get_int(caps_structure, "channels", &channels); + + if (channels > 0 && samplerate == 0) { + LOGW("Skip corrupted audio stream"); + goto EXIT; + } + + if (g_strrstr(caps_str, "mobile-xmf")) + mm_player_set_attribute((MMHandleType)player, NULL, + "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL); + } + break; + } + case GST_STREAM_TYPE_VIDEO: + { + GstStructure *caps_structure = NULL; + gint stype = 0; + gint width = 0; + + type = MM_PLAYER_TRACK_TYPE_VIDEO; + + /* do not support multi track video */ + if (player->track[MM_PLAYER_TRACK_TYPE_VIDEO].total_track_num >= 1) + goto EXIT; + + mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype); + + /* don't make video because of not required */ + if ((stype == MM_DISPLAY_SURFACE_NULL) && + (!player->set_mode.video_export)) { + LOGD("no need video decoding, skip video stream"); + goto EXIT; + } + + if (caps) { + caps_structure = gst_caps_get_structure(caps, 0); + gst_structure_get_int(caps_structure, "width", &width); + + if (width != 0) { + if (player->v_stream_caps) { + gst_caps_unref(player->v_stream_caps); + player->v_stream_caps = NULL; + } + + player->v_stream_caps = gst_caps_copy(caps); + MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps); + } + } + break; + } + case GST_STREAM_TYPE_TEXT: + type = MM_PLAYER_TRACK_TYPE_TEXT; + break; + default: + LOGW("Skip not supported stream type"); + goto EXIT; + } + + _mmplayer_track_update_stream(player, type, stream); + + if (player->track[type].active_track_index == (player->track[type].total_track_num - 1)) { + LOGD("select this stream, active idx : %d", player->track[type].active_track_index); + if (type == MM_PLAYER_TRACK_TYPE_AUDIO) + _mmplayer_set_audio_attrs(player, caps); + ret = 1; + } + +EXIT: + g_free(caps_str); + if (caps) + gst_caps_unref(caps); + + LOGD("ret %d", ret); + return ret; +} + +static gboolean +__mmplayer_gst_decode_request_resource(GstElement * uridecodebin, GstStreamCollection * collection, + GstStream * stream, gpointer data) +{ + mmplayer_t *player = (mmplayer_t *)data; + GstStreamType stype = gst_stream_get_stream_type(stream); + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE); + + LOGD("stream type %s", gst_stream_type_get_name(stype)); + + /* public does not support audio hw decoder at the moment */ + + if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) { + LOGW("video decoder resource is already acquired, skip it."); + return TRUE; + } + + if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) { + LOGE("failed to acquire video decoder resource"); + return FALSE; + } + player->interrupted_by_resource = FALSE; + MMPLAYER_FLEAVE(); + return TRUE; +} + +static void +__mmplayer_gst_deep_element_added(GstElement *bin, GstBin *child, GstElement *element, gpointer data) +{ + gchar *factory_name = NULL; + mmplayer_t *player = (mmplayer_t *)data; + mmplayer_gst_element_t *mainbin = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin); + + factory_name = GST_OBJECT_NAME(gst_element_get_factory(element)); + mainbin = player->pipeline->mainbin; + + LOGD("%s > %s > %s : %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), + factory_name, GST_ELEMENT_NAME(element)); + + /* keep the first typefind reference only */ + if (!mainbin[MMPLAYER_M_TYPEFIND].gst && g_strrstr(factory_name, "typefind")) { // FIXME : not required for local playback+ + mainbin[MMPLAYER_M_TYPEFIND].id = MMPLAYER_M_TYPEFIND; + mainbin[MMPLAYER_M_TYPEFIND].gst = element; + + _mmplayer_add_signal_connection(player, G_OBJECT(element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player); + LOGD("typefind reference is added"); + return; + } + + if ((MMPLAYER_IS_STREAMING(player)) && (!MMPLAYER_IS_RTSP_STREAMING(player))) { + /* update queue2 setting */ + if (g_strrstr(factory_name, "queue2") && (!mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) { + gint64 dur_bytes = 0L; + muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE; + + mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER; + mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = element; + + if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes)) + LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst)); + + LOGD("type %s, dur_bytes = %"G_GINT64_FORMAT, player->type, dur_bytes); + /* NOTE : in case of ts streaming, player could not get the correct duration info * + * skip the pull mode(file or ring buffering) setting. */ + if (dur_bytes > 0) { + if ((!g_strrstr(player->type, "video/mpegts")) && (!g_strrstr(player->type, "application/x-hls"))) { + type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER; + player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size; + } + } else { + dur_bytes = 0; + } + + _mm_player_streaming_set_queue2(player->streamer, + element, + FALSE, + type, + (guint64)dur_bytes); /* no meaning at the moment */ + return; + } + + /* update mq setting */ + if (g_strrstr(factory_name, "parsebin") && (!mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst)) { + GstIterator *iter = NULL; + GValue item = {0, }; + GstElement *ch_element = NULL; + GstElementFactory *ch_factory = NULL; + + iter = gst_bin_iterate_recurse(child); + if (iter != NULL) { + while (gst_iterator_next(iter, &item) == GST_ITERATOR_OK) { + ch_element = g_value_get_object(&item); + ch_factory = gst_element_get_factory(ch_element); + LOGD("children factory %s", GST_OBJECT_NAME(ch_factory)); + if (g_strrstr(GST_OBJECT_NAME(ch_factory), "multiqueue")) { + LOGD("get multiqueue"); + player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER; + player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = ch_element; + + /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h */ + _mm_player_streaming_set_multiqueue(player->streamer, ch_element); + g_value_reset(&item); + break; + } + g_value_reset(&item); + } + gst_iterator_free(iter); + } + } + } + + if (g_strrstr(factory_name, "parsebin")) { + int video_codec_type = 0; + int audio_codec_type = 0; + + g_object_set(G_OBJECT(child), "message-forward", TRUE, NULL); + g_object_set(G_OBJECT(element), "message-forward", TRUE, NULL); + + mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type); + mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type); + + /* CAUTION: if there is hw decoder, the rank value has to be higher than sw decoder + and codec default type in ini has to be hw. + */ + LOGD("set codec type v(%d) a(%d)", video_codec_type, audio_codec_type); + if (video_codec_type == MM_PLAYER_CODEC_TYPE_SW) + g_object_set(G_OBJECT(child), "force-sw-decoders-for-video", TRUE, NULL); + if (audio_codec_type == MM_PLAYER_CODEC_TYPE_SW) + g_object_set(G_OBJECT(child), "force-sw-decoders-for-audio", TRUE, NULL); + + mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].id = MMPLAYER_M_AUTOPLUG_PARSEBIN; + mainbin[MMPLAYER_M_AUTOPLUG_PARSEBIN].gst = element; + _mmplayer_add_signal_connection(player, G_OBJECT(element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type", G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue", G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select", G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(child), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "request-resource", G_CALLBACK(__mmplayer_gst_decode_request_resource), (gpointer)player); + + } else { + _mmplayer_gst_element_added((GstElement *)child, element, data); + } + return; +} + +void +__mmplayer_gst_deep_element_removed(GstElement *bin, GstBin *child, GstElement *element, gpointer data) +{ + LOGD("%s > %s > %s", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(child), GST_ELEMENT_NAME(element)); + return; +} + +static GstElement * +__mmplayer_gst_make_uridecodebin(mmplayer_t *player) +{ + GstElement *uridecodebin3 = NULL; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL); + + uridecodebin3 = gst_element_factory_make("uridecodebin3", "uridecodebin3"); + if (!uridecodebin3) { + LOGE("failed to create uridecodebin3"); + return NULL; + } + + /* get attribute */ + SECURE_LOGD("uri : %s", player->profile.uri); + + /* setting property to streaming source */ + g_object_set(G_OBJECT(uridecodebin3), "uri", player->profile.uri, + "message-forward", TRUE, + "buffer-size", DEFAULT_BUFFER_SIZE_BYTES, NULL); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-notify::source", G_CALLBACK(__mmplayer_gst_found_source), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed", G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "select-stream", G_CALLBACK(__mmplayer_gst_select_stream), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "about-to-finish", G_CALLBACK(_mmplayer_gst_about_to_finish), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-added", G_CALLBACK(__mmplayer_gst_deep_element_added), (gpointer)player); + + _mmplayer_add_signal_connection(player, G_OBJECT(uridecodebin3), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "deep-element-removed", G_CALLBACK(__mmplayer_gst_deep_element_removed), (gpointer)player); + + if (MMPLAYER_URL_HAS_DASH_SUFFIX(player)) + LOGW("[DASH] this is still experimental feature"); + + MMPLAYER_FLEAVE(); + return uridecodebin3; +} + static GstElement * __mmplayer_gst_make_http_src(mmplayer_t *player) { +#define MAX_RETRY_COUNT 10 GstElement *element = NULL; MMHandleType attrs = 0; gchar *user_agent, *cookies, **cookie_list; gint http_timeout = DEFAULT_HTTP_TIMEOUT; + user_agent = cookies = NULL; cookie_list = NULL; @@ -2746,10 +3263,11 @@ __mmplayer_gst_make_http_src(mmplayer_t *player) /* setting property to streaming source */ g_object_set(G_OBJECT(element), "location", player->profile.uri, - "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024), NULL); + "timeout", http_timeout, "blocksize", (unsigned long)(64 * 1024), + "retries", MAX_RETRY_COUNT, NULL); /* parsing cookies */ - if ((cookie_list = util_get_cookie_list((const char *)cookies))) { + if ((cookie_list = _mmplayer_get_cookie_list((const char *)cookies))) { g_object_set(G_OBJECT(element), "cookies", cookie_list, NULL); g_strfreev(cookie_list); } @@ -2773,7 +3291,7 @@ __mmplayer_gst_make_file_src(mmplayer_t *player) MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL); LOGD("using filesrc for 'file://' handler"); - if (!util_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) { + if (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD])) { LOGE("failed to get storage info"); return NULL; } @@ -2797,7 +3315,6 @@ __mmplayer_gst_msg_push(GstBus *bus, GstMessage *msg, gpointer data) g_return_val_if_fail(player, FALSE); g_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE); - gst_message_ref(msg); g_mutex_lock(&player->bus_msg_q_lock); @@ -2814,7 +3331,6 @@ static gpointer __mmplayer_gst_bus_msg_thread(gpointer data) { mmplayer_t *player = (mmplayer_t *)(data); GstMessage *msg = NULL; - GstBus *bus = NULL; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player && @@ -2823,12 +3339,6 @@ static gpointer __mmplayer_gst_bus_msg_thread(gpointer data) player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, NULL); - bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst)); - if (!bus) { - LOGE("cannot get BUS from the pipeline"); - return NULL; - } - MMPLAYER_BUS_MSG_THREAD_LOCK(player); LOGD("[handle: %p] gst bus msg thread will be started.", player); @@ -2848,9 +3358,8 @@ static gpointer __mmplayer_gst_bus_msg_thread(gpointer data) } MMPLAYER_BUS_MSG_THREAD_UNLOCK(player); - gst_object_unref(GST_OBJECT(bus)); - MMPLAYER_FLEAVE(); + return NULL; } @@ -2873,7 +3382,7 @@ __mmplayer_gst_check_duration(mmplayer_t *player, gint64 position) /* For RTSP Streaming , duration is not returned in READY state. So seek to the previous position does not work properly. * Added a patch to postpone the actual seek when state changes to PLAY. Sending a fake SEEK_COMPLETED event to finish the current request. */ if ((MMPLAYER_IS_RTSP_STREAMING(player)) && - (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { + (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { player->pending_seek.is_pending = true; player->pending_seek.pos = position; player->seek_state = MMPLAYER_SEEK_NONE; @@ -2925,7 +3434,7 @@ __mmplayer_gst_check_seekable(mmplayer_t *player) } int -__mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout) +_mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState state, gboolean async, gint timeout) { GstState element_state = GST_STATE_VOID_PENDING; GstState element_pending_state = GST_STATE_VOID_PENDING; @@ -2944,7 +3453,7 @@ __mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState stat LOGE("failed to set [%s] state", GST_ELEMENT_NAME(element)); /* dump state of all element */ - __mmplayer_dump_pipeline_state(player); + _mmplayer_dump_pipeline_state(player); return MM_ERROR_PLAYER_INTERNAL; } @@ -2968,7 +3477,7 @@ __mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState stat gst_element_state_get_name(element_pending_state)); /* dump state of all element */ - __mmplayer_dump_pipeline_state(player); + _mmplayer_dump_pipeline_state(player); return MM_ERROR_PLAYER_INTERNAL; } @@ -2981,7 +3490,7 @@ __mmplayer_gst_set_state(mmplayer_t *player, GstElement *element, GstState stat } int -__mmplayer_gst_start(mmplayer_t *player) +_mmplayer_gst_start(mmplayer_t *player) { int ret = MM_ERROR_NONE; gboolean async = FALSE; @@ -2996,7 +3505,7 @@ __mmplayer_gst_start(mmplayer_t *player) */ if (player->pending_seek.is_pending && !MMPLAYER_IS_STREAMING(player)) { MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED; - ret = __mmplayer_gst_pause(player, FALSE); + ret = _mmplayer_gst_pause(player, FALSE); if (ret != MM_ERROR_NONE) { LOGE("failed to set state to PAUSED for pending seek"); return ret; @@ -3012,7 +3521,7 @@ __mmplayer_gst_start(mmplayer_t *player) MMPLAYER_PRINT_STATE(player); /* set pipeline state to PLAYING */ - ret = __mmplayer_gst_set_state(player, + ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); if (ret != MM_ERROR_NONE) { LOGE("failed to set state to PLAYING"); @@ -3030,7 +3539,7 @@ __mmplayer_gst_start(mmplayer_t *player) } int -__mmplayer_gst_stop(mmplayer_t *player) +_mmplayer_gst_stop(mmplayer_t *player) { GstStateChangeReturn change_ret = GST_STATE_CHANGE_SUCCESS; MMHandleType attrs = 0; @@ -3065,7 +3574,7 @@ __mmplayer_gst_stop(mmplayer_t *player) __mmplayer_gst_set_async(player, FALSE, MMPLAYER_SINK_ALL); /* set gst state */ - ret = __mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout); + ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, FALSE, timeout); if (player->es_player_push_mode) { /* enable the async state transition as default operation */ @@ -3080,7 +3589,7 @@ __mmplayer_gst_stop(mmplayer_t *player) /* rewind */ if (rewind) { - if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, + if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { LOGW("failed to rewind"); @@ -3101,7 +3610,7 @@ __mmplayer_gst_stop(mmplayer_t *player) } else { LOGE("fail to stop player."); ret = MM_ERROR_PLAYER_INTERNAL; - __mmplayer_dump_pipeline_state(player); + _mmplayer_dump_pipeline_state(player); } /* generate dot file if enabled */ @@ -3113,7 +3622,7 @@ __mmplayer_gst_stop(mmplayer_t *player) } int -__mmplayer_gst_pause(mmplayer_t *player, gboolean async) +_mmplayer_gst_pause(mmplayer_t *player, gboolean async) { int ret = MM_ERROR_NONE; @@ -3127,7 +3636,7 @@ __mmplayer_gst_pause(mmplayer_t *player, gboolean async) MMPLAYER_PRINT_STATE(player); /* set pipeline status to PAUSED */ - ret = __mmplayer_gst_set_state(player, + ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PAUSED, async, MMPLAYER_STATE_CHANGE_TIMEOUT(player)); if (async) @@ -3197,9 +3706,11 @@ __mmplayer_gst_pause(mmplayer_t *player, gboolean async) return ret; } - if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) && - (!player->pipeline->videobin) && (!player->pipeline->audiobin)) - return MM_ERROR_PLAYER_CODEC_NOT_FOUND; + if (MMPLAYER_USE_DECODEBIN(player)) { + if ((!MMPLAYER_IS_RTSP_STREAMING(player)) && (!player->video_decoded_cb) && + (!player->pipeline->videobin) && (!player->pipeline->audiobin)) + return MM_ERROR_PLAYER_CODEC_NOT_FOUND; + } MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_PAUSED); @@ -3213,7 +3724,7 @@ EXIT: } int -__mmplayer_gst_resume(mmplayer_t *player, gboolean async) +_mmplayer_gst_resume(mmplayer_t *player, gboolean async) { int ret = MM_ERROR_NONE; gint timeout = 0; @@ -3233,7 +3744,7 @@ __mmplayer_gst_resume(mmplayer_t *player, gboolean async) /* set pipeline state to PLAYING */ timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player); - ret = __mmplayer_gst_set_state(player, + ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_PLAYING, async, timeout); if (ret != MM_ERROR_NONE) { LOGE("failed to set state to PLAYING"); @@ -3254,7 +3765,7 @@ EXIT: /* sending event to one of sinkelements */ gboolean -__mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event) +_mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event) { GstEvent *event2 = NULL; GList *sinks = NULL; @@ -3344,7 +3855,7 @@ __mmplayer_gst_send_event_to_sink(mmplayer_t *player, GstEvent *event) } gboolean -__mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate, +_mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate, GstFormat format, GstSeekFlags flags, GstSeekType cur_type, gint64 cur, GstSeekType stop_type, gint64 stop) { @@ -3361,7 +3872,7 @@ __mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate, event = gst_event_new_seek(rate, format, flags, cur_type, cur, stop_type, stop); - result = __mmplayer_gst_send_event_to_sink(player, event); + result = _mmplayer_gst_send_event_to_sink(player, event); MMPLAYER_FLEAVE(); @@ -3369,7 +3880,7 @@ __mmplayer_gst_seek(mmplayer_t *player, GstElement *element, gdouble rate, } int -__mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called) +_mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean internal_called) { int ret = MM_ERROR_NONE; gint64 pos_nsec = 0; @@ -3401,7 +3912,7 @@ __mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean intern This causes problem is position calculation during normal pause resume scenarios also. Currently during seek , we are sending the current position to rtspsrc module for position saving for later use. */ if ((MMPLAYER_IS_RTSP_STREAMING(player)) && - (__mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { + (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) { if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec)) LOGW("getting current position failed in seek"); @@ -3437,7 +3948,7 @@ __mmplayer_gst_set_position(mmplayer_t *player, gint64 position, gboolean intern else seek_flags |= GST_SEEK_FLAG_KEY_UNIT; - if (!__mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, + if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, player->playback_rate, GST_FORMAT_TIME, seek_flags, GST_SEEK_TYPE_SET, position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) { LOGE("failed to set position"); @@ -3480,7 +3991,7 @@ SEEK_ERROR: } int -__mmplayer_gst_get_position(mmplayer_t *player, gint64 *position) +_mmplayer_gst_get_position(mmplayer_t *player, gint64 *position) { #define TRICKPLAY_OFFSET GST_MSECOND @@ -3531,7 +4042,7 @@ __mmplayer_gst_get_position(mmplayer_t *player, gint64 *position) } int -__mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos) +_mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_pos) { #define STREAMING_IS_FINISHED 0 #define BUFFERING_MAX_PER 100 @@ -3568,7 +4079,7 @@ __mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_ return MM_ERROR_NONE; } - if (__mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) { + if (_mmplayer_gst_get_position(player, &position) != MM_ERROR_NONE) { LOGW("fail to get current position"); return MM_ERROR_NONE; } @@ -3661,7 +4172,7 @@ __mmplayer_gst_get_buffer_position(mmplayer_t *player, int *start_pos, int *end_ } GstElement * -__mmplayer_gst_create_source(mmplayer_t *player) +_mmplayer_gst_create_source(mmplayer_t *player) { GstElement *element = NULL; @@ -3693,34 +4204,26 @@ __mmplayer_gst_create_source(mmplayer_t *player) } int -__mmplayer_gst_build_es_pipeline(mmplayer_t *player) +_mmplayer_gst_build_es_pipeline(mmplayer_t *player) { - MMHandleType attrs = 0; - MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* get profile attribute */ - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("failed to get content attribute"); - return MM_ERROR_PLAYER_INTERNAL; - } - SECURE_LOGD("uri : %s", player->profile.uri); - mm_attrs_set_int_by_name(attrs, "profile_prepare_async", TRUE); - if (mm_attrs_commit_all(attrs)) /* return -1 if error */ - LOGE("failed to commit"); + mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL); - if (player->v_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps)) + if ((player->v_stream_caps) && + !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_VIDEO, player->v_stream_caps))) return MM_ERROR_PLAYER_INTERNAL; - if (player->a_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps)) + if ((player->a_stream_caps) && + !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_AUDIO, player->a_stream_caps))) return MM_ERROR_PLAYER_INTERNAL; - if (player->s_stream_caps && !__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps)) + if ((player->s_stream_caps) && + !(__mmplayer_gst_create_es_path(player, MM_PLAYER_STREAM_TYPE_TEXT, player->s_stream_caps))) return MM_ERROR_PLAYER_INTERNAL; MMPLAYER_FLEAVE(); @@ -3728,26 +4231,93 @@ __mmplayer_gst_build_es_pipeline(mmplayer_t *player) } int -__mmplayer_gst_build_pipeline(mmplayer_t *player) +_mmplayer_gst_build_pipeline_with_src(mmplayer_t *player) { mmplayer_gst_element_t *mainbin = NULL; - GstElement *src_elem = NULL; GstElement *autoplug_elem = NULL; - GList *element_bucket = NULL; - MMHandleType attrs = 0; - main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM; MMPLAYER_FENTER(); MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); - /* get profile attribute */ - attrs = MMPLAYER_GET_ATTRS(player); - if (!attrs) { - LOGE("failed to get content attribute"); + mainbin = player->pipeline->mainbin; + + LOGD("uri type %d", player->profile.uri_type); + + if ((player->profile.uri_type == MM_PLAYER_URI_TYPE_FILE) && + (!_mmplayer_get_storage_info(player->profile.uri, &player->storage_info[MMPLAYER_PATH_VOD]))) { return MM_ERROR_PLAYER_INTERNAL; } + if (player->profile.uri_type == MM_PLAYER_URI_TYPE_MEM) { + g_strlcpy(player->profile.uri, "appsrc://", MM_MAX_URL_LEN); + } + + autoplug_elem = __mmplayer_gst_make_uridecodebin(player); + if (!autoplug_elem) { + LOGE("failed to create uridecodebin3 element"); + goto ERROR; + } + + LOGD("autoplug elem is created %s", GST_ELEMENT_NAME(autoplug_elem)); + mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG; + mainbin[MMPLAYER_M_AUTOPLUG].gst = autoplug_elem; + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), autoplug_elem)) { + LOGE("failed to add uridecodebin to pipeline"); + goto ERROR; + } + + /* FIXME: required ?*/ + /* create fakesink element for keeping the pipeline state PAUSED. if needed */ + mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK; + mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder"); + + if (!mainbin[MMPLAYER_M_SRC_FAKESINK].gst) { + LOGE("failed to create fakesink"); + goto ERROR; + } + GST_OBJECT_FLAG_UNSET(mainbin[MMPLAYER_M_SRC_FAKESINK].gst, GST_ELEMENT_FLAG_SINK); + + /* take ownership of fakesink. we are reusing it */ + gst_object_ref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst); + + if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_SRC_FAKESINK].gst)) { + LOGE("failed to add fakesink to bin"); + gst_object_unref(mainbin[MMPLAYER_M_SRC_FAKESINK].gst); + goto ERROR; + } + + MMPLAYER_FLEAVE(); + return MM_ERROR_NONE; + +ERROR: + + if (mainbin[MMPLAYER_M_AUTOPLUG].gst) + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_AUTOPLUG].gst)); + + if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst) + gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst)); + + mainbin[MMPLAYER_M_AUTOPLUG].gst = NULL; + mainbin[MMPLAYER_M_SRC_FAKESINK].gst = NULL; + + return MM_ERROR_PLAYER_INTERNAL; +} + +int +_mmplayer_gst_build_pipeline(mmplayer_t *player) +{ + mmplayer_gst_element_t *mainbin = NULL; + GstElement *src_elem = NULL; + GstElement *autoplug_elem = NULL; + GList *element_bucket = NULL; + main_element_id_e autoplug_elem_id = MMPLAYER_M_NUM; + + MMPLAYER_FENTER(); + MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && + player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED); + LOGD("uri type %d", player->profile.uri_type); /* create source element */ @@ -3792,9 +4362,9 @@ __mmplayer_gst_build_pipeline(mmplayer_t *player) g_object_set(src_elem, "stream-type", stream_type, "size", (gint64)player->profile.input_mem.len, "blocksize", 20480, NULL); - __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", + _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "seek-data", G_CALLBACK(__mmplayer_gst_appsrc_seek_data_mem), (gpointer)&player->profile.input_mem); - __mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", + _mmplayer_add_signal_connection(player, G_OBJECT(src_elem), MM_PLAYER_SIGNAL_TYPE_OTHERS, "need-data", G_CALLBACK(__mmplayer_gst_appsrc_feed_data_mem), (gpointer)&player->profile.input_mem); } break; @@ -3826,11 +4396,11 @@ __mmplayer_gst_build_pipeline(mmplayer_t *player) goto ERROR; } - __mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", - G_CALLBACK(__mmplayer_typefind_have_type), (gpointer)player); + _mmplayer_add_signal_connection(player, G_OBJECT(autoplug_elem), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", + G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player); } else if (!MMPLAYER_IS_RTSP_STREAMING(player)) { autoplug_elem_id = MMPLAYER_M_AUTOPLUG; - autoplug_elem = __mmplayer_gst_make_decodebin(player); + autoplug_elem = _mmplayer_gst_make_decodebin(player); if (!autoplug_elem) { LOGE("failed to create decodebin"); goto ERROR; @@ -3850,19 +4420,20 @@ __mmplayer_gst_build_pipeline(mmplayer_t *player) } /* add elements to pipeline */ - if (!__mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) { + if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element_bucket)) { LOGE("failed to add elements to pipeline"); goto ERROR; } /* linking elements in the bucket by added order. */ - if (__mmplayer_gst_element_link_bucket(element_bucket) == -1) { + if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) { LOGE("failed to link some elements"); goto ERROR; } /* FIXME: need to check whether this is required or not. */ - if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player)) { + if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_RTSP_STREAMING(player) || + (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE)) { /* create fakesink element for keeping the pipeline state PAUSED. if needed */ mainbin[MMPLAYER_M_SRC_FAKESINK].id = MMPLAYER_M_SRC_FAKESINK; mainbin[MMPLAYER_M_SRC_FAKESINK].gst = gst_element_factory_make("fakesink", "state-holder"); @@ -3908,7 +4479,7 @@ ERROR: } int -__mmplayer_gst_add_bus_watch(mmplayer_t *player) +_mmplayer_gst_add_bus_watch(mmplayer_t *player) { GstBus *bus = NULL; mmplayer_gst_element_t *mainbin = NULL; @@ -3926,7 +4497,17 @@ __mmplayer_gst_add_bus_watch(mmplayer_t *player) return MM_ERROR_PLAYER_INTERNAL; } - player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_msg_push, player); + player->bus_watcher = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, + (GstBusFunc)__mmplayer_gst_msg_push, player, + (GDestroyNotify)_mmplayer_watcher_removed_notify); + if (player->bus_watcher == 0) { + LOGE("failed to add bus watch"); + return MM_ERROR_PLAYER_INTERNAL; + } + + g_mutex_init(&player->bus_watcher_mutex); + g_cond_init(&player->bus_watcher_cond); + player->context.thread_default = g_main_context_get_thread_default(); if (player->context.thread_default == NULL) { player->context.thread_default = g_main_context_default(); @@ -3954,3 +4535,146 @@ __mmplayer_gst_add_bus_watch(mmplayer_t *player) MMPLAYER_FLEAVE(); return MM_ERROR_NONE; } + +void +_mmplayer_activate_next_source(mmplayer_t *player, GstState target) +{ + int ret = MM_ERROR_NONE; + mmplayer_gst_element_t *mainbin = NULL; + MMMessageParamType msg_param = {0,}; + GstElement *element = NULL; + MMHandleType attrs = 0; + char *uri = NULL; + main_element_id_e elem_idx = MMPLAYER_M_NUM; + + MMPLAYER_FENTER(); + + if (!player || !player->pipeline || !player->pipeline->mainbin) { + LOGE("player is not initialized"); + goto ERROR; + } + + mainbin = player->pipeline->mainbin; + msg_param.code = MM_ERROR_PLAYER_INTERNAL; + + attrs = MMPLAYER_GET_ATTRS(player); + if (!attrs) { + LOGE("fail to get attributes"); + goto ERROR; + } + + mm_attrs_get_string_by_name(attrs, "profile_uri", &uri); + + if (_mmplayer_parse_profile((const char *)uri, NULL, &player->profile) != MM_ERROR_NONE) { + LOGE("failed to parse profile"); + msg_param.code = MM_ERROR_PLAYER_INVALID_URI; + goto ERROR; + } + + if ((MMPLAYER_URL_HAS_DASH_SUFFIX(player)) || + (MMPLAYER_URL_HAS_HLS_SUFFIX(player))) { + LOGE("dash or hls is not supportable"); + msg_param.code = MM_ERROR_PLAYER_INVALID_URI; + goto ERROR; + } + + if (!MMPLAYER_USE_DECODEBIN(player)) { + ret = _mmplayer_gst_build_pipeline_with_src(player); + if (ret != MM_ERROR_NONE) + goto ERROR; + + if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) { + LOGE("Failed to change state of uridecodebin3 element"); + goto ERROR; + } + goto DONE; + } + + element = _mmplayer_gst_create_source(player); + if (!element) { + LOGE("no source element was created"); + goto ERROR; + } + + if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) { + LOGE("failed to add source element to pipeline"); + gst_object_unref(GST_OBJECT(element)); + element = NULL; + goto ERROR; + } + + /* take source element */ + mainbin[MMPLAYER_M_SRC].id = MMPLAYER_M_SRC; + mainbin[MMPLAYER_M_SRC].gst = element; + + element = NULL; + + if (MMPLAYER_IS_HTTP_STREAMING(player)) { + if (player->streamer == NULL) { + player->streamer = _mm_player_streaming_create(); + _mm_player_streaming_initialize(player->streamer, TRUE); + } + + elem_idx = MMPLAYER_M_TYPEFIND; + element = gst_element_factory_make("typefind", "typefinder"); + _mmplayer_add_signal_connection(player, G_OBJECT(element), + MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "have-type", G_CALLBACK(_mmplayer_typefind_have_type), (gpointer)player); + } else { + elem_idx = MMPLAYER_M_AUTOPLUG; + element = _mmplayer_gst_make_decodebin(player); + } + + /* check autoplug element is OK */ + if (!element) { + LOGE("can not create element(%d)", elem_idx); + goto ERROR; + } + + if (gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), element) == FALSE) { + LOGE("failed to add %s to pipeline", GST_ELEMENT_NAME(element)); + gst_object_unref(GST_OBJECT(element)); + element = NULL; + goto ERROR; + } + + mainbin[elem_idx].id = elem_idx; + mainbin[elem_idx].gst = element; + + if (gst_element_link(mainbin[MMPLAYER_M_SRC].gst, mainbin[elem_idx].gst) == FALSE) { + LOGE("Failed to link src - autoplug(or typefind)"); + goto ERROR; + } + + if (MMPLAYER_IS_HTTP_STREAMING(player)) { + if (gst_element_set_state(mainbin[MMPLAYER_M_TYPEFIND].gst, target) == GST_STATE_CHANGE_FAILURE) { // ???? + LOGE("Failed to change state of src element"); + goto ERROR; + } + } else { + if (gst_element_set_state(mainbin[MMPLAYER_M_AUTOPLUG].gst, target) == GST_STATE_CHANGE_FAILURE) { + LOGE("Failed to change state of decodebin"); + goto ERROR; + } + } + + if (gst_element_set_state(mainbin[MMPLAYER_M_SRC].gst, target) == GST_STATE_CHANGE_FAILURE) { + LOGE("Failed to change state of src element"); + goto ERROR; + } + +DONE: + player->gapless.stream_changed = TRUE; + player->gapless.running = TRUE; + MMPLAYER_FLEAVE(); + return; + +ERROR: + if (player) { + _mmplayer_set_reconfigure_state(player, FALSE); + if (!player->msg_posted) { + MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param); + player->msg_posted = TRUE; + } + } + return; +}