4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, ByungWook Jang <bw.jang@samsung.com>,
7 * Maksym Ukhanov <m.ukhanov@samsung.com>, Hyunjun Ko <zzoon.ko@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.
24 #include <gst/video/videooverlay.h>
25 #include <Elementary.h>
27 #include "mm_wfd_sink_util.h"
28 #include "mm_wfd_sink_priv.h"
29 #include "mm_wfd_sink_manager.h"
30 #include "mm_wfd_sink_dlog.h"
31 #include "mm_wfd_sink_wfd_enum.h"
35 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
36 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
37 static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink);
38 static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink);
39 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
40 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
41 static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink);
42 static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
43 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
44 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
47 static int __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd);
48 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
51 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
52 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution);
54 int _mm_wfd_sink_create(mm_wfd_sink_t **wfd_sink)
56 int result = MM_ERROR_NONE;
58 wfd_sink_debug_fenter();
60 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
62 mm_wfd_sink_t *new_wfd_sink = NULL;
65 new_wfd_sink = g_malloc0(sizeof(mm_wfd_sink_t));
67 wfd_sink_error("failed to allocate memory for wi-fi display sink");
68 return MM_ERROR_WFD_NO_FREE_SPACE;
71 /* Initialize gstreamer related */
72 new_wfd_sink->attrs = 0;
74 new_wfd_sink->pipeline = NULL;
75 new_wfd_sink->audio_decodebin_is_linked = FALSE;
76 new_wfd_sink->video_decodebin_is_linked = FALSE;
78 /* Initialize timestamp compensation related */
79 new_wfd_sink->need_to_reset_basetime = FALSE;
80 new_wfd_sink->clock = NULL;
81 new_wfd_sink->video_buffer_count = 0LL;
82 new_wfd_sink->video_average_gap = 0LL;
83 new_wfd_sink->video_accumulated_gap = 0LL;
84 new_wfd_sink->audio_buffer_count = 0LL;
85 new_wfd_sink->audio_average_gap = 0LL;
86 new_wfd_sink->audio_accumulated_gap = 0LL;
87 new_wfd_sink->last_buffer_timestamp = GST_CLOCK_TIME_NONE;
89 /* Initialize all states */
90 MMWFDSINK_CURRENT_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
91 MMWFDSINK_PREVIOUS_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
92 MMWFDSINK_PENDING_STATE(new_wfd_sink) = MM_WFD_SINK_STATE_NONE;
94 /* initialize audio/video information */
95 new_wfd_sink->stream_info.audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
96 new_wfd_sink->stream_info.audio_stream_info.channels = 0;
97 new_wfd_sink->stream_info.audio_stream_info.sample_rate = 0;
98 new_wfd_sink->stream_info.audio_stream_info.bitwidth = 0;
99 new_wfd_sink->stream_info.video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
100 new_wfd_sink->stream_info.video_stream_info.width = 0;
101 new_wfd_sink->stream_info.video_stream_info.height = 0;
102 new_wfd_sink->stream_info.video_stream_info.frame_rate = 0;
104 /* Initialize command */
105 new_wfd_sink->cmd = MM_WFD_SINK_COMMAND_CREATE;
106 new_wfd_sink->waiting_cmd = FALSE;
108 /* Initialize manager related */
109 new_wfd_sink->manager_thread = NULL;
110 new_wfd_sink->manager_thread_cmd = NULL;
111 new_wfd_sink->manager_thread_exit = FALSE;
113 /* Initialize video resolution */
114 new_wfd_sink->supportive_resolution = MM_WFD_SINK_RESOLUTION_UNKNOWN;
116 /* construct attributes */
117 new_wfd_sink->attrs = _mmwfd_construct_attribute((MMHandleType)new_wfd_sink);
118 if (!new_wfd_sink->attrs) {
119 MMWFDSINK_FREEIF(new_wfd_sink);
120 wfd_sink_error("failed to set attribute");
121 return MM_ERROR_WFD_INTERNAL;
124 /* load ini for initialize */
125 result = mm_wfd_sink_ini_load(&new_wfd_sink->ini);
126 if (result != MM_ERROR_NONE) {
127 wfd_sink_error("failed to load ini file");
128 goto fail_to_load_ini;
130 new_wfd_sink->need_to_reset_basetime = new_wfd_sink->ini.enable_reset_basetime;
132 /* initialize manager */
133 result = _mm_wfd_sink_init_manager(new_wfd_sink);
134 if (result < MM_ERROR_NONE) {
135 wfd_sink_error("failed to init manager : %d", result);
139 /* initialize gstreamer */
140 result = __mm_wfd_sink_init_gstreamer(new_wfd_sink);
141 if (result < MM_ERROR_NONE) {
142 wfd_sink_error("failed to init gstreamer : %d", result);
147 __mm_wfd_sink_set_state(new_wfd_sink, MM_WFD_SINK_STATE_NULL);
149 /* now take handle */
150 *wfd_sink = new_wfd_sink;
152 wfd_sink_debug_fleave();
158 mm_wfd_sink_ini_unload(&new_wfd_sink->ini);
160 _mmwfd_deconstruct_attribute(new_wfd_sink->attrs);
161 MMWFDSINK_FREEIF(new_wfd_sink);
168 int _mm_wfd_sink_prepare(mm_wfd_sink_t *wfd_sink)
170 int result = MM_ERROR_NONE;
172 wfd_sink_debug_fenter();
174 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
176 /* check current wi-fi display sink state */
177 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PREPARE);
179 /* construct pipeline */
180 /* create main pipeline */
181 result = __mm_wfd_sink_create_pipeline(wfd_sink);
182 if (result < MM_ERROR_NONE) {
183 wfd_sink_error("failed to create pipeline : %d", result);
187 /* create video decodebin */
188 result = __mm_wfd_sink_create_video_decodebin(wfd_sink);
189 if (result < MM_ERROR_NONE) {
190 wfd_sink_error("failed to create video decodebin %d", result);
194 /* create video sinkbin */
195 result = __mm_wfd_sink_create_video_sinkbin(wfd_sink);
196 if (result < MM_ERROR_NONE) {
197 wfd_sink_error("failed to create video sinkbin %d", result);
201 /* create audio decodebin */
202 result = __mm_wfd_sink_create_audio_decodebin(wfd_sink);
203 if (result < MM_ERROR_NONE) {
204 wfd_sink_error("fail to create audio decodebin : %d", result);
208 /* create audio sinkbin */
209 result = __mm_wfd_sink_create_audio_sinkbin(wfd_sink);
210 if (result < MM_ERROR_NONE) {
211 wfd_sink_error("fail to create audio sinkbin : %d", result);
215 /* set pipeline READY state */
216 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_READY, TRUE);
217 if (result < MM_ERROR_NONE) {
218 wfd_sink_error("failed to set state : %d", result);
223 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PREPARED);
225 wfd_sink_debug_fleave();
231 /* need to destroy pipeline already created */
232 __mm_wfd_sink_destroy_pipeline(wfd_sink);
236 int _mm_wfd_sink_connect(mm_wfd_sink_t *wfd_sink, const char *uri)
238 int result = MM_ERROR_NONE;
240 wfd_sink_debug_fenter();
242 wfd_sink_return_val_if_fail(uri && strlen(uri) > strlen("rtsp://"), MM_ERROR_WFD_INVALID_ARGUMENT);
243 wfd_sink_return_val_if_fail(wfd_sink &&
244 wfd_sink->pipeline &&
245 wfd_sink->pipeline->mainbin &&
246 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
247 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
248 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
249 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
250 MM_ERROR_WFD_NOT_INITIALIZED);
252 /* check current wi-fi display sink state */
253 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
255 wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri));
257 /* set uri to wfdsrc */
258 g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
260 /* set pipeline PAUSED state */
261 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
262 if (result < MM_ERROR_NONE) {
263 wfd_sink_error("failed to set state : %d", result);
267 wfd_sink_debug_fleave();
272 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
274 int result = MM_ERROR_NONE;
276 wfd_sink_debug_fenter();
278 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
280 /* check current wi-fi display sink state */
281 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START);
283 WFD_SINK_MANAGER_LOCK(wfd_sink) ;
284 wfd_sink_debug("check pipeline is ready to start");
285 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
287 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
288 if (result < MM_ERROR_NONE) {
289 wfd_sink_error("failed to set state : %d", result);
293 wfd_sink_debug_fleave();
298 int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
300 int result = MM_ERROR_NONE;
302 wfd_sink_debug_fenter();
304 wfd_sink_return_val_if_fail(wfd_sink &&
305 wfd_sink->pipeline &&
306 wfd_sink->pipeline->mainbin &&
307 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
308 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
309 MM_ERROR_WFD_NOT_INITIALIZED);
311 /* check current wi-fi display sink state */
312 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
314 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "pause", NULL);
316 wfd_sink_debug_fleave();
321 int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
323 int result = MM_ERROR_NONE;
325 wfd_sink_debug_fenter();
327 wfd_sink_return_val_if_fail(wfd_sink &&
328 wfd_sink->pipeline &&
329 wfd_sink->pipeline->mainbin &&
330 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
331 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
332 MM_ERROR_WFD_NOT_INITIALIZED);
334 /* check current wi-fi display sink state */
335 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
337 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "resume", NULL);
339 wfd_sink_debug_fleave();
344 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
346 int result = MM_ERROR_NONE;
348 wfd_sink_debug_fenter();
350 wfd_sink_return_val_if_fail(wfd_sink &&
351 wfd_sink->pipeline &&
352 wfd_sink->pipeline->mainbin &&
353 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
354 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
355 MM_ERROR_WFD_NOT_INITIALIZED);
357 /* check current wi-fi display sink state */
358 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
360 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
361 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
363 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL);
365 wfd_sink_debug_fleave();
370 int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
372 int result = MM_ERROR_NONE;
374 wfd_sink_debug_fenter();
376 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
378 /* check current wi-fi display sink state */
379 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE);
381 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
382 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
384 /* release pipeline */
385 result = __mm_wfd_sink_destroy_pipeline(wfd_sink);
386 if (result != MM_ERROR_NONE) {
387 wfd_sink_error("failed to destory pipeline");
388 return MM_ERROR_WFD_INTERNAL;
390 wfd_sink_debug("success to destory pipeline");
394 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NULL);
396 wfd_sink_debug_fleave();
401 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
403 int result = MM_ERROR_NONE;
405 wfd_sink_debug_fenter();
407 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
409 /* check current wi-fi display sink state */
410 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
413 mm_wfd_sink_ini_unload(&wfd_sink->ini);
415 /* release attributes */
416 _mmwfd_deconstruct_attribute(wfd_sink->attrs);
418 if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
419 wfd_sink_error("failed to release manager");
420 return MM_ERROR_WFD_INTERNAL;
425 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NONE);
427 wfd_sink_debug_fleave();
432 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
434 int result = MM_ERROR_NONE;
436 wfd_sink_debug_fenter();
438 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
440 wfd_sink->msg_cb = callback;
441 wfd_sink->msg_user_data = user_data;
443 wfd_sink_debug_fleave();
448 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
450 int result = MM_ERROR_NONE;
453 static const int max_argc = 50;
457 wfd_sink_debug_fenter();
460 argc = calloc(1, sizeof(gint));
461 argv = calloc(max_argc, sizeof(gchar *));
462 if (!argc || !argv) {
463 wfd_sink_error("failed to allocate memory for wfdsink");
465 MMWFDSINK_FREEIF(argv);
466 MMWFDSINK_FREEIF(argc);
468 return MM_ERROR_WFD_NO_FREE_SPACE;
471 /* we would not do fork for scanning plugins */
472 argv[*argc] = g_strdup("--gst-disable-registry-fork");
475 /* check disable registry scan */
476 argv[*argc] = g_strdup("--gst-disable-registry-update");
479 /* check disable segtrap */
480 argv[*argc] = g_strdup("--gst-disable-segtrap");
484 for (i = 0; i < 5; i++) {
485 if (strlen(wfd_sink->ini.gst_param[i]) > 2) {
486 wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]);
487 argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
492 wfd_sink_debug("initializing gstreamer with following parameter");
493 wfd_sink_debug("argc : %d", *argc);
495 for (i = 0; i < *argc; i++) {
496 wfd_sink_debug("argv[%d] : %s", i, argv[i]);
499 /* initializing gstreamer */
500 if (!gst_init_check(argc, &argv, &err)) {
501 wfd_sink_error("failed to initialize gstreamer: %s", err ? err->message : "unknown error occurred");
505 result = MM_ERROR_WFD_INTERNAL;
509 for (i = 0; i < *argc; i++) {
510 MMWFDSINK_FREEIF(argv[i]);
512 MMWFDSINK_FREEIF(argv);
513 MMWFDSINK_FREEIF(argc);
515 wfd_sink_debug_fleave();
520 static GstBusSyncReply
521 _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
523 GstBusSyncReply ret = GST_BUS_PASS;
525 wfd_sink_return_val_if_fail(message &&
526 GST_IS_MESSAGE(message) &&
527 GST_MESSAGE_SRC(message),
530 switch (GST_MESSAGE_TYPE(message)) {
531 case GST_MESSAGE_TAG:
533 case GST_MESSAGE_DURATION:
535 case GST_MESSAGE_STATE_CHANGED: {
536 /* we only handle state change messages from pipeline */
537 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
541 case GST_MESSAGE_ASYNC_DONE: {
542 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
554 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
556 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
557 const GstStructure *message_structure = gst_message_get_structure(msg);
560 wfd_sink_return_val_if_fail(wfd_sink, FALSE);
561 wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
563 wfd_sink_debug("got %s from %s",
564 GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
565 GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
567 switch (GST_MESSAGE_TYPE(msg)) {
568 case GST_MESSAGE_ERROR: {
569 GError *error = NULL;
573 gst_message_parse_error(msg, &error, &debug);
575 wfd_sink_error("error : %s", error->message);
576 wfd_sink_error("debug : %s", debug);
578 MMWFDSINK_FREEIF(debug);
583 case GST_MESSAGE_WARNING: {
585 GError *error = NULL;
587 gst_message_parse_warning(msg, &error, &debug);
589 wfd_sink_warning("warning : %s", error->message);
590 wfd_sink_warning("debug : %s", debug);
592 MMWFDSINK_FREEIF(debug);
597 case GST_MESSAGE_STATE_CHANGED: {
598 const GValue *voldstate, *vnewstate, *vpending;
599 GstState oldstate, newstate, pending;
600 const GstStructure *structure;
602 /* we only handle messages from pipeline */
603 if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
606 /* get state info from msg */
607 structure = gst_message_get_structure(msg);
608 if (structure == NULL)
611 voldstate = gst_structure_get_value(structure, "old-state");
612 vnewstate = gst_structure_get_value(structure, "new-state");
613 vpending = gst_structure_get_value(structure, "pending-state");
614 if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
617 oldstate = (GstState)voldstate->data[0].v_int;
618 newstate = (GstState)vnewstate->data[0].v_int;
619 pending = (GstState)vpending->data[0].v_int;
621 wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
622 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
623 gst_element_state_get_name((GstState)oldstate),
624 gst_element_state_get_name((GstState)newstate),
625 gst_element_state_get_name((GstState)pending));
627 if (oldstate == newstate) {
628 wfd_sink_debug("pipeline reports state transition to old state");
633 case GST_STATE_VOID_PENDING:
635 case GST_STATE_READY:
636 case GST_STATE_PAUSED:
637 case GST_STATE_PLAYING:
644 case GST_MESSAGE_CLOCK_LOST: {
645 GstClock *clock = NULL;
646 gst_message_parse_clock_lost(msg, &clock);
647 wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.", (clock ? GST_OBJECT_NAME(clock) : "NULL"));
651 case GST_MESSAGE_NEW_CLOCK: {
652 GstClock *clock = NULL;
653 gst_message_parse_new_clock(msg, &clock);
657 if (wfd_sink->clock) {
658 if (wfd_sink->clock != clock)
659 wfd_sink_debug("clock is changed! [%s] -->[%s]",
660 GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
661 GST_STR_NULL(GST_OBJECT_NAME(clock)));
663 wfd_sink_debug("same clock is selected again! [%s]",
664 GST_STR_NULL(GST_OBJECT_NAME(clock)));
666 wfd_sink_debug("new clock [%s] was selected in the pipeline",
667 (GST_STR_NULL(GST_OBJECT_NAME(clock))));
670 wfd_sink->clock = clock;
674 case GST_MESSAGE_APPLICATION: {
675 const gchar *message_structure_name;
677 message_structure_name = gst_structure_get_name(message_structure);
678 if (!message_structure_name)
681 wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
685 case GST_MESSAGE_ELEMENT: {
686 const gchar *structure_name = NULL;
688 structure_name = gst_structure_get_name(message_structure);
689 if (structure_name) {
690 wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
691 if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
692 wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
693 MMWFDSINK_POST_MESSAGE(wfd_sink,
694 MM_ERROR_WFD_INTERNAL,
695 MMWFDSINK_CURRENT_STATE(wfd_sink));
696 } else if (g_strrstr(structure_name, "GstWFDSrcSessionTimeout")) {
697 wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
698 MMWFDSINK_POST_MESSAGE(wfd_sink,
699 MM_ERROR_WFD_INTERNAL,
700 MMWFDSINK_CURRENT_STATE(wfd_sink));
706 case GST_MESSAGE_PROGRESS: {
707 GstProgressType type = GST_PROGRESS_TYPE_ERROR;
708 gchar *category = NULL, *text = NULL;
710 gst_message_parse_progress(msg, &type, &category, &text);
711 wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
714 case GST_PROGRESS_TYPE_START:
716 case GST_PROGRESS_TYPE_COMPLETE:
717 if (category && !strcmp(category, "open"))
718 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_CONNECTED);
719 else if (category && !strcmp(category, "play")) {
720 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PLAYING);
721 /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
722 } else if (category && !strcmp(category, "pause"))
723 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PAUSED);
724 else if (category && !strcmp(category, "close"))
725 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_DISCONNECTED);
727 case GST_PROGRESS_TYPE_CANCELED:
729 case GST_PROGRESS_TYPE_ERROR:
730 if (category && !strcmp(category, "open")) {
731 wfd_sink_error("got error : %s", GST_STR_NULL(text));
732 /*_mm_wfd_sink_disconnect (wfd_sink); */
733 MMWFDSINK_POST_MESSAGE(wfd_sink,
734 MM_ERROR_WFD_INTERNAL,
735 MMWFDSINK_CURRENT_STATE(wfd_sink));
736 } else if (category && !strcmp(category, "play")) {
737 wfd_sink_error("got error : %s", GST_STR_NULL(text));
738 /*_mm_wfd_sink_disconnect (wfd_sink); */
739 MMWFDSINK_POST_MESSAGE(wfd_sink,
740 MM_ERROR_WFD_INTERNAL,
741 MMWFDSINK_CURRENT_STATE(wfd_sink));
742 } else if (category && !strcmp(category, "pause")) {
743 wfd_sink_error("got error : %s", GST_STR_NULL(text));
744 /*_mm_wfd_sink_disconnect (wfd_sink); */
745 MMWFDSINK_POST_MESSAGE(wfd_sink,
746 MM_ERROR_WFD_INTERNAL,
747 MMWFDSINK_CURRENT_STATE(wfd_sink));
748 } else if (category && !strcmp(category, "close")) {
749 wfd_sink_error("got error : %s", GST_STR_NULL(text));
750 /*_mm_wfd_sink_disconnect (wfd_sink); */
751 MMWFDSINK_POST_MESSAGE(wfd_sink,
752 MM_ERROR_WFD_INTERNAL,
753 MMWFDSINK_CURRENT_STATE(wfd_sink));
755 wfd_sink_error("got error : %s", GST_STR_NULL(text));
759 wfd_sink_error("progress message has no type");
763 MMWFDSINK_FREEIF(category);
764 MMWFDSINK_FREEIF(text);
767 case GST_MESSAGE_ASYNC_START:
768 wfd_sink_debug("GST_MESSAGE_ASYNC_START : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
770 case GST_MESSAGE_ASYNC_DONE:
771 wfd_sink_debug("GST_MESSAGE_ASYNC_DONE : %s", gst_element_get_name(GST_MESSAGE_SRC(msg)));
773 case GST_MESSAGE_UNKNOWN:
774 case GST_MESSAGE_INFO:
775 case GST_MESSAGE_TAG:
776 case GST_MESSAGE_BUFFERING:
777 case GST_MESSAGE_EOS:
778 case GST_MESSAGE_STATE_DIRTY:
779 case GST_MESSAGE_STEP_DONE:
780 case GST_MESSAGE_CLOCK_PROVIDE:
781 case GST_MESSAGE_STRUCTURE_CHANGE:
782 case GST_MESSAGE_STREAM_STATUS:
783 case GST_MESSAGE_SEGMENT_START:
784 case GST_MESSAGE_SEGMENT_DONE:
785 case GST_MESSAGE_DURATION:
786 case GST_MESSAGE_LATENCY:
787 case GST_MESSAGE_REQUEST_STATE:
788 case GST_MESSAGE_STEP_START:
789 case GST_MESSAGE_QOS:
790 case GST_MESSAGE_ANY:
793 wfd_sink_debug("unhandled message");
801 __mm_wfd_sink_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket, gboolean need_prepare)
803 GList *bucket = element_bucket;
804 MMWFDSinkGstElement *element = NULL;
805 int successful_add_count = 0;
807 wfd_sink_debug_fenter();
809 wfd_sink_return_val_if_fail(element_bucket, 0);
810 wfd_sink_return_val_if_fail(bin, 0);
812 for (; bucket; bucket = bucket->next) {
813 element = (MMWFDSinkGstElement *)bucket->data;
815 if (element && element->gst) {
817 gst_element_set_state(GST_ELEMENT(element->gst), GST_STATE_READY);
819 if (!gst_bin_add(GST_BIN(bin), GST_ELEMENT(element->gst))) {
820 wfd_sink_error("failed to add element [%s] to bin [%s]",
821 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
822 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
826 wfd_sink_debug("add element [%s] to bin [%s]",
827 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))),
828 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT_CAST(bin))));
830 successful_add_count++;
834 wfd_sink_debug_fleave();
836 return successful_add_count;
840 __mm_wfd_sink_gst_element_link_bucket(GList *element_bucket)
842 GList *bucket = element_bucket;
843 MMWFDSinkGstElement *element = NULL;
844 MMWFDSinkGstElement *prv_element = NULL;
845 gint successful_link_count = 0;
847 wfd_sink_debug_fenter();
849 wfd_sink_return_val_if_fail(element_bucket, -1);
851 prv_element = (MMWFDSinkGstElement *)bucket->data;
852 bucket = bucket->next;
854 for (; bucket; bucket = bucket->next) {
855 element = (MMWFDSinkGstElement *)bucket->data;
857 if (element && element->gst) {
858 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
859 wfd_sink_debug("linking [%s] to [%s] success",
860 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
861 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
862 successful_link_count++;
864 wfd_sink_error("linking [%s] to [%s] failed",
865 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst))),
866 GST_STR_NULL(GST_ELEMENT_NAME(GST_ELEMENT(element->gst))));
871 prv_element = element;
874 wfd_sink_debug_fleave();
876 return successful_link_count;
880 __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd)
882 MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
884 wfd_sink_debug_fenter();
886 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
888 MMWFDSINK_PRINT_STATE(wfd_sink);
890 cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
893 case MM_WFD_SINK_COMMAND_CREATE: {
894 if (cur_state != MM_WFD_SINK_STATE_NONE)
897 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
901 case MM_WFD_SINK_COMMAND_PREPARE: {
902 if (cur_state == MM_WFD_SINK_STATE_PREPARED)
904 else if (cur_state != MM_WFD_SINK_STATE_NULL)
907 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PREPARED;
911 case MM_WFD_SINK_COMMAND_CONNECT: {
912 if (cur_state == MM_WFD_SINK_STATE_CONNECTED)
914 else if (cur_state != MM_WFD_SINK_STATE_PREPARED)
917 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_CONNECTED;
921 case MM_WFD_SINK_COMMAND_START: {
922 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
924 else if (cur_state != MM_WFD_SINK_STATE_CONNECTED)
927 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
931 case MM_WFD_SINK_COMMAND_PAUSE: {
932 if (cur_state == MM_WFD_SINK_STATE_PAUSED)
934 else if (cur_state != MM_WFD_SINK_STATE_PLAYING)
937 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PAUSED;
941 case MM_WFD_SINK_COMMAND_RESUME: {
942 if (cur_state == MM_WFD_SINK_STATE_PLAYING)
944 else if (cur_state != MM_WFD_SINK_STATE_PAUSED)
947 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_PLAYING;
951 case MM_WFD_SINK_COMMAND_DISCONNECT: {
952 if (cur_state == MM_WFD_SINK_STATE_NONE ||
953 cur_state == MM_WFD_SINK_STATE_NULL ||
954 cur_state == MM_WFD_SINK_STATE_PREPARED ||
955 cur_state == MM_WFD_SINK_STATE_DISCONNECTED)
957 else if (cur_state != MM_WFD_SINK_STATE_PLAYING &&
958 cur_state != MM_WFD_SINK_STATE_CONNECTED &&
959 cur_state != MM_WFD_SINK_STATE_PAUSED)
962 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_DISCONNECTED;
966 case MM_WFD_SINK_COMMAND_UNPREPARE: {
967 if (cur_state == MM_WFD_SINK_STATE_NONE ||
968 cur_state == MM_WFD_SINK_STATE_NULL)
971 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NULL;
975 case MM_WFD_SINK_COMMAND_DESTROY: {
976 if (cur_state == MM_WFD_SINK_STATE_NONE)
979 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
989 wfd_sink_debug_fleave();
991 return MM_ERROR_NONE;
994 wfd_sink_debug("already %s state, nothing to do.", MMWFDSINK_STATE_GET_NAME(cur_state));
995 return MM_ERROR_WFD_NO_OP;
999 wfd_sink_error("current state is invalid.", MMWFDSINK_STATE_GET_NAME(cur_state));
1000 return MM_ERROR_WFD_INVALID_STATE;
1003 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state)
1005 wfd_sink_debug_fenter();
1007 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1009 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == state) {
1010 wfd_sink_error("already state(%s)", MMWFDSINK_STATE_GET_NAME(state));
1011 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1012 return MM_ERROR_NONE;
1015 /* update wi-fi display state */
1016 MMWFDSINK_PREVIOUS_STATE(wfd_sink) = MMWFDSINK_CURRENT_STATE(wfd_sink);
1017 MMWFDSINK_CURRENT_STATE(wfd_sink) = state;
1019 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MMWFDSINK_PENDING_STATE(wfd_sink))
1020 MMWFDSINK_PENDING_STATE(wfd_sink) = MM_WFD_SINK_STATE_NONE;
1022 /* poset state message to application */
1023 MMWFDSINK_POST_MESSAGE(wfd_sink,
1025 MMWFDSINK_CURRENT_STATE(wfd_sink));
1028 MMWFDSINK_PRINT_STATE(wfd_sink);
1030 wfd_sink_debug_fleave();
1032 return MM_ERROR_NONE;
1036 __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async)
1038 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
1039 GstState cur_state = GST_STATE_VOID_PENDING;
1040 GstState pending_state = GST_STATE_VOID_PENDING;
1042 wfd_sink_debug_fenter();
1044 wfd_sink_return_val_if_fail(wfd_sink &&
1045 wfd_sink->pipeline &&
1046 wfd_sink->pipeline->mainbin &&
1047 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1048 MM_ERROR_WFD_NOT_INITIALIZED);
1050 wfd_sink_return_val_if_fail(state > GST_STATE_VOID_PENDING, MM_ERROR_WFD_INVALID_ARGUMENT);
1052 wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
1054 result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1055 if (result == GST_STATE_CHANGE_FAILURE) {
1056 wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state));
1057 return MM_ERROR_WFD_INTERNAL;
1061 wfd_sink_debug("wait for changing state is completed ");
1063 result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1064 if (result == GST_STATE_CHANGE_FAILURE) {
1065 wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
1067 __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1069 return MM_ERROR_WFD_INTERNAL;
1070 } else if (result == GST_STATE_CHANGE_NO_PREROLL) {
1071 wfd_sink_debug("successfully changed state but is not able to provide data yet");
1074 wfd_sink_debug("cur state is %s, pending state is %s",
1075 gst_element_state_get_name(cur_state),
1076 gst_element_state_get_name(pending_state));
1080 wfd_sink_debug_fleave();
1082 return MM_ERROR_NONE;
1086 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1088 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1091 wfd_sink_debug_fenter();
1093 wfd_sink_return_if_fail(wfd_sink &&
1094 wfd_sink->pipeline &&
1095 wfd_sink->pipeline->mainbin &&
1096 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1097 wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
1100 if (wfd_sink->clock)
1101 base_time = gst_clock_get_time(wfd_sink->clock);
1103 if (GST_CLOCK_TIME_IS_VALID(base_time)) {
1105 wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time));
1107 for (i = 0; i < WFD_SINK_M_NUM; i++) {
1108 if (wfd_sink->pipeline->mainbin[i].gst)
1109 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time);
1112 if (wfd_sink->pipeline->v_decodebin) {
1113 for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
1114 if (wfd_sink->pipeline->v_decodebin[i].gst)
1115 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time);
1119 if (wfd_sink->pipeline->v_sinkbin) {
1120 for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
1121 if (wfd_sink->pipeline->v_sinkbin[i].gst)
1122 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time);
1126 if (wfd_sink->pipeline->a_decodebin) {
1127 for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
1128 if (wfd_sink->pipeline->a_decodebin[i].gst)
1129 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time);
1133 if (wfd_sink->pipeline->a_sinkbin) {
1134 for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
1135 if (wfd_sink->pipeline->a_sinkbin[i].gst)
1136 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time);
1140 wfd_sink->need_to_reset_basetime = FALSE;
1143 wfd_sink_debug_fleave();
1149 __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
1151 GstElement *bin = NULL;
1153 wfd_sink_debug_fenter();
1155 wfd_sink_return_val_if_fail(wfd_sink &&
1156 wfd_sink->pipeline &&
1157 wfd_sink->pipeline->mainbin &&
1158 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1159 MM_ERROR_WFD_NOT_INITIALIZED);
1161 /* check video decodebin is linked */
1162 if (!wfd_sink->video_decodebin_is_linked) {
1163 /* check video decodebin is created */
1164 if (wfd_sink->pipeline->v_decodebin == NULL) {
1165 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) {
1166 wfd_sink_error("failed to create video decodebin....");
1171 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
1172 wfd_sink_error("failed to link video decodebin.....");
1177 /* check video sinkbin is created */
1178 if (wfd_sink->pipeline->v_sinkbin == NULL) {
1179 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) {
1180 wfd_sink_error("failed to create video sinkbin....");
1185 /* set video decodebin state as READY */
1186 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1187 bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1188 if (GST_STATE(bin) <= GST_STATE_NULL) {
1189 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1190 wfd_sink_error("failed to set state(READY) to video decodebin");
1195 wfd_sink_warning("going on without video decodebin....");
1198 /* set video sinkbin state as READY */
1199 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1200 bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1201 if (GST_STATE(bin) <= GST_STATE_NULL) {
1202 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1203 wfd_sink_error("failed to set state(READY) to video sinkbin");
1208 wfd_sink_warning("going on without video sinkbin....");
1211 wfd_sink_debug_fleave();
1213 return MM_ERROR_NONE;
1217 /* need to notify to app */
1218 MMWFDSINK_POST_MESSAGE(wfd_sink,
1219 MM_ERROR_WFD_INTERNAL,
1220 MMWFDSINK_CURRENT_STATE(wfd_sink));
1222 return MM_ERROR_WFD_INTERNAL;
1225 int __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
1227 GstElement *bin = NULL;
1229 wfd_sink_debug_fenter();
1231 wfd_sink_return_val_if_fail(wfd_sink &&
1233 MM_ERROR_WFD_NOT_INITIALIZED);
1235 /* check audio decodebin is linked */
1236 if (!wfd_sink->audio_decodebin_is_linked) {
1237 /* check audio decodebin is created */
1238 if (wfd_sink->pipeline->a_decodebin == NULL) {
1239 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) {
1240 wfd_sink_error("failed to create audio decodebin....");
1245 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
1246 wfd_sink_error("failed to link audio decodebin.....");
1251 /* check audio sinkbin is created */
1252 if (wfd_sink->pipeline->a_sinkbin == NULL) {
1253 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) {
1254 wfd_sink_error("failed to create audio sinkbin....");
1259 /* set audio decodebin state as READY */
1260 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1261 bin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1262 if (GST_STATE(bin) <= GST_STATE_NULL) {
1263 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1264 wfd_sink_error("failed to set state(READY) to audio decodebin");
1269 wfd_sink_warning("going on without audio decodebin....");
1272 /* set audio sinkbin state as READY */
1273 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
1274 bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1275 if (GST_STATE(bin) <= GST_STATE_NULL) {
1276 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) {
1277 wfd_sink_error("failed to set state(READY) to audio sinkbin");
1282 wfd_sink_warning("going on without audio sinkbin....");
1285 wfd_sink_debug_fleave();
1287 return MM_ERROR_NONE;
1291 /* need to notify to app */
1292 MMWFDSINK_POST_MESSAGE(wfd_sink,
1293 MM_ERROR_WFD_INTERNAL,
1294 MMWFDSINK_CURRENT_STATE(wfd_sink));
1296 return MM_ERROR_WFD_INTERNAL;
1299 #define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */
1300 #define COMPENSATION_CHECK_PERIOD (30*GST_SECOND) /* 30 sec */
1302 static GstPadProbeReturn
1303 _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1305 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
1306 GstClockTime current_time = GST_CLOCK_TIME_NONE;
1307 GstClockTime start_time = GST_CLOCK_TIME_NONE;
1308 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1309 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1310 GstClockTime render_time = GST_CLOCK_TIME_NONE;
1311 GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
1312 GstBuffer *buffer = NULL;
1313 gint64 ts_offset = 0LL;
1315 wfd_sink_return_val_if_fail(info, FALSE);
1316 wfd_sink_return_val_if_fail(wfd_sink &&
1317 wfd_sink->pipeline &&
1318 wfd_sink->pipeline->mainbin &&
1319 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1320 GST_PAD_PROBE_DROP);
1322 if (!wfd_sink->clock) {
1323 wfd_sink_warning("pipeline did not select clock, yet");
1324 return GST_PAD_PROBE_OK;
1327 if (wfd_sink->need_to_reset_basetime)
1328 _mm_wfd_sink_reset_basetime(wfd_sink);
1330 /* calculate current runninig time */
1331 current_time = gst_clock_get_time(wfd_sink->clock);
1332 if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
1333 base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst);
1334 else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
1335 base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst);
1336 start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1337 if (GST_CLOCK_TIME_IS_VALID(current_time) &&
1338 GST_CLOCK_TIME_IS_VALID(start_time) &&
1339 GST_CLOCK_TIME_IS_VALID(base_time)) {
1340 running_time = current_time - (start_time + base_time);
1342 wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
1343 " base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
1344 GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
1345 return GST_PAD_PROBE_OK;
1348 /* calculate this buffer rendering time */
1349 buffer = gst_pad_probe_info_get_buffer(info);
1350 if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) {
1351 wfd_sink_warning("buffer timestamp is invalid.");
1352 return GST_PAD_PROBE_OK;
1355 if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
1356 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
1357 g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL);
1358 } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
1359 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
1360 g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL);
1363 render_time = GST_BUFFER_TIMESTAMP(buffer);
1364 render_time += ts_offset;
1366 /* chekc this buffer could be rendered or not */
1367 if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) {
1368 diff = GST_CLOCK_DIFF(running_time, render_time);
1370 /* this buffer could be NOT rendered */
1371 wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
1372 GST_STR_NULL((GST_OBJECT_NAME(pad))),
1373 GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
1375 /* this buffer could be rendered */
1376 /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n", */
1377 /* GST_STR_NULL((GST_OBJECT_NAME(pad))), */
1378 /* GST_TIME_ARGS(diff)); */
1382 /* update buffer count and gap */
1383 if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
1384 wfd_sink->video_buffer_count++;
1385 wfd_sink->video_accumulated_gap += diff;
1386 } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
1387 wfd_sink->audio_buffer_count++;
1388 wfd_sink->audio_accumulated_gap += diff;
1390 wfd_sink_warning("invalid buffer type.. ");
1391 return GST_PAD_PROBE_DROP;
1394 if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) {
1395 /* fisrt 60sec, just calculate the gap between source device and sink device */
1396 if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND)
1397 return GST_PAD_PROBE_OK;
1399 /* every 10sec, calculate the gap between source device and sink device */
1400 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
1401 > COMPENSATION_CHECK_PERIOD) {
1402 gint64 audio_avgrage_gap = 0LL;
1403 gint64 video_avgrage_gap = 0LL;
1404 gint64 audio_avgrage_gap_diff = 0LL;
1405 gint64 video_avgrage_gap_diff = 0LL;
1406 gboolean video_minus_compensation = FALSE;
1407 gboolean audio_minus_compensation = FALSE;
1408 gint64 avgrage_gap_diff = 0LL;
1409 gboolean minus_compensation = FALSE;
1412 if (wfd_sink->video_buffer_count > 0) {
1413 video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count;
1415 if (wfd_sink->video_average_gap != 0) {
1416 if (video_avgrage_gap > wfd_sink->video_average_gap) {
1417 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
1418 video_minus_compensation = TRUE;
1420 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
1421 video_minus_compensation = FALSE;
1424 wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
1425 wfd_sink->video_average_gap = video_avgrage_gap;
1428 wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
1429 " ~ %" GST_TIME_FORMAT"",
1430 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1431 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1435 if (wfd_sink->audio_buffer_count > 0) {
1436 audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count;
1438 if (wfd_sink->audio_average_gap != 0) {
1439 if (audio_avgrage_gap > wfd_sink->audio_average_gap) {
1440 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
1441 audio_minus_compensation = TRUE;
1443 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
1444 audio_minus_compensation = FALSE;
1447 wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
1448 wfd_sink->audio_average_gap = audio_avgrage_gap;
1451 wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
1452 " ~ %" GST_TIME_FORMAT"",
1453 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1454 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1457 /* selecet average_gap_diff between video and audio */
1458 /* which makes no buffer drop in the sink elements */
1459 if (video_avgrage_gap_diff && audio_avgrage_gap_diff) {
1460 if (!video_minus_compensation && !audio_minus_compensation) {
1461 minus_compensation = FALSE;
1462 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1463 avgrage_gap_diff = video_avgrage_gap_diff;
1465 avgrage_gap_diff = audio_avgrage_gap_diff;
1466 } else if (video_minus_compensation && audio_minus_compensation) {
1467 minus_compensation = TRUE;
1468 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1469 avgrage_gap_diff = audio_avgrage_gap_diff;
1471 avgrage_gap_diff = video_avgrage_gap_diff;
1473 minus_compensation = FALSE;
1474 if (!video_minus_compensation)
1475 avgrage_gap_diff = video_avgrage_gap_diff;
1477 avgrage_gap_diff = audio_avgrage_gap_diff;
1479 } else if (video_avgrage_gap_diff) {
1480 minus_compensation = video_minus_compensation;
1481 avgrage_gap_diff = video_avgrage_gap_diff;
1482 } else if (audio_avgrage_gap_diff) {
1483 minus_compensation = audio_minus_compensation;
1484 avgrage_gap_diff = audio_avgrage_gap_diff;
1487 wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
1488 audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
1489 video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
1492 /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
1493 if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) {
1494 if (minus_compensation)
1495 ts_offset -= avgrage_gap_diff;
1497 ts_offset += avgrage_gap_diff;
1499 wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
1500 GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
1501 minus_compensation ? "-" : "", avgrage_gap_diff,
1502 GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
1504 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
1505 g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1506 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
1507 g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1509 wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
1510 minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
1514 wfd_sink->video_buffer_count = 0;
1515 wfd_sink->video_accumulated_gap = 0LL;
1516 wfd_sink->audio_buffer_count = 0;
1517 wfd_sink->audio_accumulated_gap = 0LL;
1518 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1521 wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
1522 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1523 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1526 return GST_PAD_PROBE_OK;
1531 __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data)
1533 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1534 gchar *name = gst_pad_get_name(pad);
1535 GstElement *pipeline = NULL;
1536 GstElement *decodebin = NULL;
1537 GstElement *sinkbin = NULL;
1538 GstPad *sinkpad = NULL;
1539 GstPad *srcpad = NULL;
1541 wfd_sink_debug_fenter();
1543 wfd_sink_return_if_fail(wfd_sink &&
1544 wfd_sink->pipeline &&
1545 wfd_sink->pipeline->mainbin &&
1546 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1548 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1550 /* take decodebin/sinkbin */
1551 if (name[0] == 'v') {
1552 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
1554 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL);
1556 gst_pad_add_probe(pad,
1557 GST_PAD_PROBE_TYPE_BUFFER,
1558 _mm_wfd_sink_check_running_time,
1562 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) {
1563 wfd_sink_error("failed to prepare video pipeline....");
1567 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst)
1568 decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1569 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst)
1570 sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1571 } else if (name[0] == 'a') {
1572 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
1574 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL);
1576 gst_pad_add_probe(pad,
1577 GST_PAD_PROBE_TYPE_BUFFER,
1578 _mm_wfd_sink_check_running_time,
1582 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) {
1583 wfd_sink_error("failed to prepare audio pipeline....");
1587 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst)
1588 decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1589 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst)
1590 sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1592 wfd_sink_error("unexceptable pad is added!!!");
1596 srcpad = gst_object_ref(pad);
1598 /* add decodebin and link */
1600 if (!gst_bin_add(GST_BIN(pipeline), decodebin)) {
1601 wfd_sink_error("failed to add %s to pipeline",
1602 GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1606 sinkpad = gst_element_get_static_pad(decodebin, "sink");
1608 wfd_sink_error("failed to get sink pad from %s",
1609 GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1613 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1614 wfd_sink_error("failed to link %s and %s",
1615 GST_STR_NULL(GST_PAD_NAME(srcpad)),
1616 GST_STR_NULL(GST_PAD_NAME(sinkpad)));
1619 gst_object_unref(GST_OBJECT(srcpad));
1621 gst_object_unref(GST_OBJECT(sinkpad));
1624 srcpad = gst_element_get_static_pad(decodebin, "src");
1626 wfd_sink_error("failed to get src pad from %s",
1627 GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1631 wfd_sink_warning("going on without decodebin...");
1634 /* add sinkbin and link */
1636 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1637 wfd_sink_error("failed to add %s to pipeline",
1638 GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1642 sinkpad = gst_element_get_static_pad(sinkbin, "sink");
1644 wfd_sink_error("failed to get sink pad from %s",
1645 GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1649 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1650 wfd_sink_error("failed to link %s and %s",
1651 GST_STR_NULL(GST_PAD_NAME(srcpad)),
1652 GST_STR_NULL(GST_PAD_NAME(sinkpad)));
1655 gst_object_unref(GST_OBJECT(srcpad));
1657 gst_object_unref(GST_OBJECT(sinkpad));
1660 wfd_sink_error("there is no sinkbin...");
1667 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) {
1668 wfd_sink_error("failed to sync %s state with parent",
1669 GST_STR_NULL(GST_PAD_NAME(decodebin)));
1675 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) {
1676 wfd_sink_error("failed to sync %s state with parent",
1677 GST_STR_NULL(GST_PAD_NAME(sinkbin)));
1682 if (name[0] == 'v') {
1683 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
1684 } else if (name[0] == 'a') {
1685 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
1688 MMWFDSINK_FREEIF(name);
1690 wfd_sink_debug_fleave();
1696 MMWFDSINK_FREEIF(name);
1699 gst_object_unref(GST_OBJECT(srcpad));
1703 gst_object_unref(GST_OBJECT(sinkpad));
1706 /* need to notify to app */
1707 MMWFDSINK_POST_MESSAGE(wfd_sink,
1708 MM_ERROR_WFD_INTERNAL,
1709 MMWFDSINK_CURRENT_STATE(wfd_sink));
1715 __mm_wfd_sink_change_av_format(GstElement *wfdsrc, gpointer *need_to_flush, gpointer data)
1717 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1719 wfd_sink_debug_fenter();
1721 wfd_sink_return_if_fail(wfd_sink);
1722 wfd_sink_return_if_fail(need_to_flush);
1724 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) {
1725 wfd_sink_debug("need to flush pipeline");
1726 *need_to_flush = (gpointer) TRUE;
1728 wfd_sink_debug("don't need to flush pipeline");
1729 *need_to_flush = (gpointer) FALSE;
1733 wfd_sink_debug_fleave();
1738 __mm_wfd_sink_update_stream_info(GstElement *wfdsrc, GstStructure *str, gpointer data)
1740 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1741 MMWFDSinkStreamInfo *stream_info = NULL;
1742 gint is_valid_audio_format = FALSE;
1743 gint is_valid_video_format = FALSE;
1744 gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
1745 gint video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
1746 gchar *audio_format;
1747 gchar *video_format;
1749 wfd_sink_debug_fenter();
1751 wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
1752 wfd_sink_return_if_fail(wfd_sink);
1754 stream_info = &wfd_sink->stream_info;
1756 audio_codec = wfd_sink->stream_info.audio_stream_info.codec;
1757 video_codec = wfd_sink->stream_info.video_stream_info.codec;
1759 if (gst_structure_has_field(str, "audio_format")) {
1760 is_valid_audio_format = TRUE;
1761 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
1762 if (g_strrstr(audio_format, "AAC"))
1763 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC;
1764 else if (g_strrstr(audio_format, "AC3"))
1765 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3;
1766 else if (g_strrstr(audio_format, "LPCM"))
1767 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM;
1769 wfd_sink_error("invalid audio format(%s)...", audio_format);
1770 is_valid_audio_format = FALSE;
1773 if (is_valid_audio_format == TRUE) {
1774 if (gst_structure_has_field(str, "audio_rate"))
1775 gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
1776 if (gst_structure_has_field(str, "audio_channels"))
1777 gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels);
1778 if (gst_structure_has_field(str, "audio_bitwidth"))
1779 gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
1781 if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
1782 if (audio_codec != stream_info->audio_stream_info.codec) {
1783 wfd_sink_debug("audio codec is changed...need to change audio decodebin");
1786 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
1789 wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t",
1791 stream_info->audio_stream_info.sample_rate,
1792 stream_info->audio_stream_info.channels,
1793 stream_info->audio_stream_info.bitwidth);
1797 if (gst_structure_has_field(str, "video_format")) {
1798 is_valid_video_format = TRUE;
1799 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
1800 if (!g_strrstr(video_format, "H264")) {
1801 wfd_sink_error("invalid video format(%s)...", video_format);
1802 is_valid_video_format = FALSE;
1805 if (is_valid_video_format == TRUE) {
1806 stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
1808 if (gst_structure_has_field(str, "video_width"))
1809 gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
1810 if (gst_structure_has_field(str, "video_height"))
1811 gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height);
1812 if (gst_structure_has_field(str, "video_framerate"))
1813 gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
1815 if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
1816 if (video_codec != stream_info->video_stream_info.codec) {
1817 wfd_sink_debug("video codec is changed...need to change video decodebin");
1820 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
1823 wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t",
1825 stream_info->video_stream_info.width,
1826 stream_info->video_stream_info.height,
1827 stream_info->video_stream_info.frame_rate);
1831 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
1833 wfd_sink_debug_fleave();
1836 static int __mm_wfd_sink_prepare_source(mm_wfd_sink_t *wfd_sink, GstElement *wfdsrc)
1838 GstStructure *audio_param = NULL;
1839 GstStructure *video_param = NULL;
1840 GstStructure *hdcp_param = NULL;
1841 gint hdcp_version = 0;
1843 guint CEA_resolution = 0;
1844 guint VESA_resolution = 0;
1845 guint HH_resolution = 0;
1846 GObjectClass *klass;
1848 wfd_sink_debug_fenter();
1850 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1851 wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1852 wfd_sink_return_val_if_fail(wfdsrc, MM_ERROR_WFD_NOT_INITIALIZED);
1854 klass = G_OBJECT_GET_CLASS(G_OBJECT(wfdsrc));
1856 g_object_set(G_OBJECT(wfdsrc), "debug", wfd_sink->ini.set_debug_property, NULL);
1857 g_object_set(G_OBJECT(wfdsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdsrc_pad_probe, NULL);
1858 if (g_object_class_find_property(klass, "udp-buffer-size"))
1859 g_object_set(G_OBJECT(wfdsrc), "udp-buffer-size", 2097152, NULL);
1860 if (g_object_class_find_property(klass, "do-request"))
1861 g_object_set(G_OBJECT(wfdsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
1862 if (g_object_class_find_property(klass, "latency"))
1863 g_object_set(G_OBJECT(wfdsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
1865 audio_param = gst_structure_new("audio_param",
1866 "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec,
1867 "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency,
1868 "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel,
1869 "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency,
1872 CEA_resolution = wfd_sink->ini.video_cea_support;
1873 VESA_resolution = wfd_sink->ini.video_vesa_support;
1874 HH_resolution = wfd_sink->ini.video_hh_support;
1876 __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution, &CEA_resolution, &VESA_resolution, &HH_resolution);
1878 wfd_sink_debug("set video resolution CEA[%x] VESA[%x] HH[%x]", CEA_resolution, VESA_resolution, HH_resolution);
1880 video_param = gst_structure_new("video_param",
1881 "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec,
1882 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution,
1883 "video_cea_support", G_TYPE_UINT, CEA_resolution,
1884 "video_vesa_support", G_TYPE_UINT, VESA_resolution,
1885 "video_hh_support", G_TYPE_UINT, HH_resolution,
1886 "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile,
1887 "video_level", G_TYPE_UINT, wfd_sink->ini.video_level,
1888 "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency,
1889 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution,
1890 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution,
1891 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing,
1892 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param,
1893 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support,
1896 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
1897 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
1898 wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
1900 hdcp_param = gst_structure_new("hdcp_param",
1901 "hdcp_version", G_TYPE_INT, hdcp_version,
1902 "hdcp_port_no", G_TYPE_INT, hdcp_port,
1905 g_object_set(G_OBJECT(wfdsrc), "audio-param", audio_param, NULL);
1906 g_object_set(G_OBJECT(wfdsrc), "video-param", video_param, NULL);
1907 g_object_set(G_OBJECT(wfdsrc), "hdcp-param", hdcp_param, NULL);
1909 g_signal_connect(wfdsrc, "update-media-info", G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
1911 g_signal_connect(wfdsrc, "change-av-format", G_CALLBACK(__mm_wfd_sink_change_av_format), wfd_sink);
1913 wfd_sink_debug_fleave();
1915 return MM_ERROR_NONE;
1918 static int __mm_wfd_sink_prepare_demux(mm_wfd_sink_t *wfd_sink, GstElement *demux)
1920 wfd_sink_debug_fenter();
1922 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1923 wfd_sink_return_val_if_fail(demux, MM_ERROR_WFD_NOT_INITIALIZED);
1925 g_signal_connect(demux, "pad-added", G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink);
1927 wfd_sink_debug_fleave();
1929 return MM_ERROR_NONE;
1932 static void __mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data)
1934 wfd_sink_debug_fenter();
1936 return_if_fail(element);
1938 wfd_sink_warning("%s is overrun",
1939 GST_STR_NULL(GST_ELEMENT_NAME(element)));
1941 wfd_sink_debug_fleave();
1946 static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue)
1948 wfd_sink_debug_fenter();
1950 wfd_sink_return_if_fail(wfd_sink);
1951 wfd_sink_return_if_fail(queue);
1953 /* set maximum buffer size of queue as 3sec */
1954 g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
1955 g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
1956 g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
1957 g_signal_connect(queue, "overrun", G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
1959 wfd_sink_debug_fleave();
1965 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
1967 MMWFDSinkGstElement *mainbin = NULL;
1968 GList *element_bucket = NULL;
1972 wfd_sink_debug_fenter();
1974 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1975 wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1977 /* Create pipeline */
1978 wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo));
1979 if (wfd_sink->pipeline == NULL)
1982 memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
1984 /* create mainbin */
1985 mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1986 if (mainbin == NULL)
1989 memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1991 /* create pipeline */
1992 mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
1993 mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink");
1994 if (!mainbin[WFD_SINK_M_PIPE].gst) {
1995 wfd_sink_error("failed to create pipeline");
2000 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, wfd_sink->ini.name_of_source, "wfdsink_source", TRUE);
2001 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src");
2002 if (mainbin[WFD_SINK_M_SRC].gst) {
2003 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_source(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) {
2004 wfd_sink_error("failed to prepare wfdsrc...");
2009 /* create rtpmp2tdepay */
2010 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
2011 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2012 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink");
2014 MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2016 /* create tsdemuxer*/
2017 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
2018 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
2019 if (mainbin[WFD_SINK_M_DEMUX].gst) {
2020 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) {
2021 wfd_sink_error("failed to prepare demux...");
2026 /* adding created elements to pipeline */
2027 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
2028 wfd_sink_error("failed to add elements");
2032 /* linking elements in the bucket by added order. */
2033 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2034 wfd_sink_error("failed to link elements");
2038 /* connect bus callback */
2039 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
2041 wfd_sink_error("cannot get bus from pipeline.");
2045 /* add bus message callback*/
2046 gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
2048 /* set sync handler to get tag synchronously */
2049 gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
2051 g_list_free(element_bucket);
2052 gst_object_unref(GST_OBJECT(bus));
2054 /* now we have completed mainbin. take it */
2055 wfd_sink->pipeline->mainbin = mainbin;
2057 wfd_sink_debug_fleave();
2059 return MM_ERROR_NONE;
2063 wfd_sink_error("ERROR : releasing pipeline");
2066 g_list_free(element_bucket);
2067 element_bucket = NULL;
2071 gst_object_unref(GST_OBJECT(bus));
2074 /* release element which are not added to bin */
2075 for (i = 1; i < WFD_SINK_M_NUM; i++) { /* NOTE : skip pipeline */
2076 if (mainbin != NULL && mainbin[i].gst) {
2077 GstObject *parent = NULL;
2078 parent = gst_element_get_parent(mainbin[i].gst);
2081 gst_object_unref(GST_OBJECT(mainbin[i].gst));
2082 mainbin[i].gst = NULL;
2084 gst_object_unref(GST_OBJECT(parent));
2089 /* release mainbin with it's childs */
2090 if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst)
2091 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
2093 MMWFDSINK_FREEIF(mainbin);
2095 MMWFDSINK_FREEIF(wfd_sink->pipeline);
2097 return MM_ERROR_WFD_INTERNAL;
2100 int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2102 MMWFDSinkGstElement *a_decodebin = NULL;
2103 MMWFDSinkGstElement *first_element = NULL;
2104 MMWFDSinkGstElement *last_element = NULL;
2105 GList *element_bucket = NULL;
2106 GstPad *sinkpad = NULL;
2107 GstPad *srcpad = NULL;
2108 GstPad *ghostpad = NULL;
2109 GList *first_list = NULL;
2110 GList *last_list = NULL;
2112 wfd_sink_debug_fenter();
2114 wfd_sink_return_val_if_fail(wfd_sink &&
2115 wfd_sink->pipeline &&
2116 wfd_sink->pipeline->a_decodebin &&
2117 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst,
2118 MM_ERROR_WFD_NOT_INITIALIZED);
2120 if (wfd_sink->audio_decodebin_is_linked) {
2121 wfd_sink_debug("audio decodebin is already linked... nothing to do");
2122 return MM_ERROR_NONE;
2125 /* take audio decodebin */
2126 a_decodebin = wfd_sink->pipeline->a_decodebin;
2128 /* check audio queue */
2129 if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
2130 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_QUEUE]);
2132 /* check audio hdcp */
2133 if (a_decodebin[WFD_SINK_A_D_HDCP].gst)
2134 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_HDCP]);
2136 /* check audio codec */
2137 switch (wfd_sink->stream_info.audio_stream_info.codec) {
2138 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
2139 if (a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst)
2140 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER]);
2141 if (a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst) {
2142 GstCaps *caps = NULL;
2143 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_LPCM_FILTER]);
2144 caps = gst_caps_new_simple("audio/x-raw",
2145 "rate", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.sample_rate,
2146 "channels", G_TYPE_INT, wfd_sink->stream_info.audio_stream_info.channels,
2147 "format", G_TYPE_STRING, "S16BE", NULL);
2149 g_object_set(G_OBJECT(a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst), "caps", caps, NULL);
2150 gst_object_unref(GST_OBJECT(caps));
2154 case MM_WFD_SINK_AUDIO_CODEC_AAC:
2155 if (a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst)
2156 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_PARSE]);
2157 if (a_decodebin[WFD_SINK_A_D_AAC_DEC].gst)
2158 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AAC_DEC]);
2161 case MM_WFD_SINK_AUDIO_CODEC_AC3:
2162 if (a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst)
2163 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_PARSE]);
2164 if (a_decodebin[WFD_SINK_A_D_AC3_DEC].gst)
2165 element_bucket = g_list_append(element_bucket, &a_decodebin[WFD_SINK_A_D_AC3_DEC]);
2169 wfd_sink_error("audio codec is not decied yet. cannot link audio decodebin...");
2170 return MM_ERROR_WFD_INTERNAL;
2174 if (element_bucket == NULL) {
2175 wfd_sink_error("there are no elements to be linked in the audio decodebin, destroy it");
2176 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
2177 wfd_sink_error("failed to destroy audio decodebin");
2183 /* adding elements to audio decodebin */
2184 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_decodebin[WFD_SINK_A_D_BIN].gst), element_bucket, FALSE)) {
2185 wfd_sink_error("failed to add elements to audio decodebin");
2189 /* linking elements in the bucket by added order. */
2190 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2191 wfd_sink_error("failed to link elements of the audio decodebin");
2195 /* get first element's sinkpad for creating ghostpad */
2196 first_list = g_list_first(element_bucket);
2197 if (first_list == NULL) {
2198 wfd_sink_error("failed to get first list of the element_bucket");
2202 first_element = (MMWFDSinkGstElement *)first_list->data;
2203 if (!first_element) {
2204 wfd_sink_error("failed to get first element of the audio decodebin");
2208 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2210 wfd_sink_error("failed to get sink pad from element(%s)",
2211 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2215 ghostpad = gst_ghost_pad_new("sink", sinkpad);
2217 wfd_sink_error("failed to create ghostpad of audio decodebin");
2221 if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
2222 wfd_sink_error("failed to add ghostpad to audio decodebin");
2225 gst_object_unref(GST_OBJECT(sinkpad));
2229 /* get last element's src for creating ghostpad */
2230 last_list = g_list_last(element_bucket);
2231 if (last_list == NULL) {
2232 wfd_sink_error("failed to get last list of the element_bucket");
2236 last_element = (MMWFDSinkGstElement *)last_list->data;
2237 if (!last_element) {
2238 wfd_sink_error("failed to get last element of the audio decodebin");
2242 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2244 wfd_sink_error("failed to get src pad from element(%s)",
2245 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
2249 ghostpad = gst_ghost_pad_new("src", srcpad);
2251 wfd_sink_error("failed to create ghostpad of audio decodebin");
2255 if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
2256 wfd_sink_error("failed to add ghostpad to audio decodebin");
2259 gst_object_unref(GST_OBJECT(srcpad));
2262 g_list_free(element_bucket);
2265 wfd_sink->audio_decodebin_is_linked = TRUE;
2267 wfd_sink_debug_fleave();
2269 return MM_ERROR_NONE;
2274 gst_object_unref(GST_OBJECT(srcpad));
2278 gst_object_unref(GST_OBJECT(sinkpad));
2281 g_list_free(element_bucket);
2283 return MM_ERROR_WFD_INTERNAL;
2286 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
2288 wfd_sink_debug_fenter();
2290 /* check audiosink is created */
2291 wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2292 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2294 g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE, NULL);
2295 g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
2296 g_object_set(G_OBJECT(audio_sink), "slave-method", 2, NULL);
2297 g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async, NULL);
2298 g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL);
2300 wfd_sink_debug_fleave();
2302 return MM_ERROR_NONE;
2305 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2307 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2308 MMWFDSinkGstElement *a_decodebin = NULL;
2309 GstObject *parent = NULL;
2312 wfd_sink_debug_fenter();
2314 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2316 if (wfd_sink->pipeline &&
2317 wfd_sink->pipeline->a_decodebin &&
2318 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2319 a_decodebin = wfd_sink->pipeline->a_decodebin;
2321 wfd_sink_debug("audio decodebin is not created, nothing to destroy");
2322 return MM_ERROR_NONE;
2325 parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst);
2327 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
2329 if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
2330 wfd_sink_debug("try to change state of audio decodebin to NULL");
2331 ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
2332 if (ret != GST_STATE_CHANGE_SUCCESS) {
2333 wfd_sink_error("failed to change state of audio decodebin to NULL");
2334 return MM_ERROR_WFD_INTERNAL;
2338 /* release element which are not added to bin */
2339 for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */
2340 if (a_decodebin[i].gst) {
2341 parent = gst_element_get_parent(a_decodebin[i].gst);
2343 wfd_sink_debug("unref %s(current ref %d)",
2344 GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
2345 ((GObject *) a_decodebin[i].gst)->ref_count);
2346 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
2347 a_decodebin[i].gst = NULL;
2349 wfd_sink_debug("unref %s(current ref %d)",
2350 GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
2351 ((GObject *) a_decodebin[i].gst)->ref_count);
2352 gst_object_unref(GST_OBJECT(parent));
2357 /* release audio decodebin with it's childs */
2358 if (a_decodebin[WFD_SINK_A_D_BIN].gst)
2359 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
2362 wfd_sink_debug("audio decodebin has parent(%s), unref it ",
2363 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2365 gst_object_unref(GST_OBJECT(parent));
2368 wfd_sink->audio_decodebin_is_linked = FALSE;
2370 MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
2372 wfd_sink_debug_fleave();
2374 return MM_ERROR_NONE;
2377 static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2379 MMWFDSinkGstElement *a_decodebin = NULL;
2380 gint audio_codec = WFD_AUDIO_UNKNOWN;
2381 GList *element_bucket = NULL;
2382 gboolean link = TRUE;
2385 wfd_sink_debug_fenter();
2387 wfd_sink_return_val_if_fail(wfd_sink &&
2389 MM_ERROR_WFD_NOT_INITIALIZED);
2391 /* check audio decodebin could be linked now */
2392 switch (wfd_sink->stream_info.audio_stream_info.codec) {
2393 case MM_WFD_SINK_AUDIO_CODEC_AAC:
2394 audio_codec = WFD_AUDIO_AAC;
2397 case MM_WFD_SINK_AUDIO_CODEC_AC3:
2398 audio_codec = WFD_AUDIO_AC3;
2401 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
2402 audio_codec = WFD_AUDIO_LPCM;
2405 case MM_WFD_SINK_AUDIO_CODEC_NONE:
2407 wfd_sink_debug("audio decodebin could NOT be linked now, just create");
2408 audio_codec = wfd_sink->ini.audio_codec;
2414 a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
2416 wfd_sink_error("failed to allocate memory for audio decodebin");
2417 return MM_ERROR_WFD_NO_FREE_SPACE;
2420 memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
2422 /* create audio decodebin */
2423 a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN;
2424 a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin");
2425 if (!a_decodebin[WFD_SINK_A_D_BIN].gst) {
2426 wfd_sink_error("failed to create audio decodebin");
2431 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
2432 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "sink");
2433 if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
2434 __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
2437 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
2438 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "sink");
2441 audio_codec = wfd_sink->ini.audio_codec;
2442 if (audio_codec & WFD_AUDIO_LPCM) {
2443 /* create LPCM converter */
2444 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
2445 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "sink");
2446 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "src");
2448 /* create LPCM filter */
2449 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE);
2450 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "sink");
2451 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "src");
2454 if (audio_codec & WFD_AUDIO_AAC) {
2455 /* create AAC parse */
2456 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE);
2457 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "sink");
2458 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "src");
2460 /* create AAC decoder */
2461 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE);
2462 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "sink");
2463 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "src");
2466 if (audio_codec & WFD_AUDIO_AC3) {
2467 /* create AC3 parser */
2468 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE);
2469 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "sink");
2470 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "src");
2472 /* create AC3 decoder */
2473 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE);
2474 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "sink");
2475 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "src");
2478 g_list_free(element_bucket);
2481 wfd_sink->pipeline->a_decodebin = a_decodebin;
2483 /* link audio decodebin if audio codec is fixed */
2485 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
2486 wfd_sink_error("failed to link audio decodebin, destroy audio decodebin");
2487 __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
2488 return MM_ERROR_WFD_INTERNAL;
2492 wfd_sink_debug_fleave();
2494 return MM_ERROR_NONE;
2497 wfd_sink_error("failed to create audio decodebin, release all");
2499 g_list_free(element_bucket);
2501 /* release element which are not added to bin */
2502 for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */
2503 if (a_decodebin != NULL && a_decodebin[i].gst) {
2504 GstObject *parent = NULL;
2505 parent = gst_element_get_parent(a_decodebin[i].gst);
2508 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
2509 a_decodebin[i].gst = NULL;
2511 gst_object_unref(GST_OBJECT(parent));
2516 /* release audioo decodebin with it's childs */
2517 if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst)
2518 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
2520 MMWFDSINK_FREEIF(a_decodebin);
2522 return MM_ERROR_WFD_INTERNAL;
2525 static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
2527 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2528 MMWFDSinkGstElement *a_sinkbin = NULL;
2529 GstObject *parent = NULL;
2532 wfd_sink_debug_fenter();
2534 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2536 if (wfd_sink->pipeline &&
2537 wfd_sink->pipeline->a_sinkbin &&
2538 wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2539 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
2541 wfd_sink_debug("audio sinkbin is not created, nothing to destroy");
2542 return MM_ERROR_NONE;
2545 parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
2547 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
2549 if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
2550 wfd_sink_debug("try to change state of audio decodebin to NULL");
2551 ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
2552 if (ret != GST_STATE_CHANGE_SUCCESS) {
2553 wfd_sink_error("failed to change state of audio decodebin to NULL");
2554 return MM_ERROR_WFD_INTERNAL;
2558 /* release element which are not added to bin */
2559 for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */
2560 if (a_sinkbin[i].gst) {
2561 parent = gst_element_get_parent(a_sinkbin[i].gst);
2563 wfd_sink_debug("unref %s(current ref %d)",
2564 GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
2565 ((GObject *) a_sinkbin[i].gst)->ref_count);
2566 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
2567 a_sinkbin[i].gst = NULL;
2569 wfd_sink_debug("unref %s(current ref %d)",
2570 GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
2571 ((GObject *) a_sinkbin[i].gst)->ref_count);
2572 gst_object_unref(GST_OBJECT(parent));
2577 /* release audio decodebin with it's childs */
2578 if (a_sinkbin[WFD_SINK_A_S_BIN].gst)
2579 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
2582 wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
2583 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2585 gst_object_unref(GST_OBJECT(parent));
2588 MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
2590 wfd_sink_debug_fleave();
2592 return MM_ERROR_NONE;
2595 static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
2597 MMWFDSinkGstElement *a_sinkbin = NULL;
2598 MMWFDSinkGstElement *first_element = NULL;
2599 GList *element_bucket = NULL;
2600 GstPad *ghostpad = NULL;
2603 GList *first_list = NULL;
2605 wfd_sink_debug_fenter();
2607 wfd_sink_return_val_if_fail(wfd_sink &&
2609 MM_ERROR_WFD_NOT_INITIALIZED);
2612 a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
2614 wfd_sink_error("failed to allocate memory for audio sinkbin");
2615 return MM_ERROR_WFD_NO_FREE_SPACE;
2618 memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
2620 /* create audio sinkbin */
2621 a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN;
2622 a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin");
2623 if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2624 wfd_sink_error("failed to create audio sinkbin");
2628 /* create resampler */
2629 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
2630 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "sink");
2631 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "src");
2634 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
2635 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "sink");
2636 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "src");
2639 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
2640 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst, "sink");
2641 if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
2642 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
2643 wfd_sink_error("failed to set audio sink property....");
2648 /* adding created elements to audio sinkbin */
2649 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) {
2650 wfd_sink_error("failed to add elements to audio sinkbin");
2654 /* linking elements in the bucket by added order. */
2655 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2656 wfd_sink_error("failed to link elements fo the audio sinkbin");
2660 /* get first element's of the audio sinkbin */
2661 first_list = g_list_first(element_bucket);
2662 if (first_list == NULL) {
2663 wfd_sink_error("failed to get first list of the element_bucket");
2667 first_element = (MMWFDSinkGstElement *)first_list->data;
2668 if (!first_element) {
2669 wfd_sink_error("failed to get first element of the audio sinkbin");
2673 /* get first element's sinkpad for creating ghostpad */
2674 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2676 wfd_sink_error("failed to get sink pad from element(%s)",
2677 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2681 ghostpad = gst_ghost_pad_new("sink", pad);
2683 wfd_sink_error("failed to create ghostpad of audio sinkbin");
2687 if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) {
2688 wfd_sink_error("failed to add ghostpad to audio sinkbin");
2691 gst_object_unref(GST_OBJECT(pad));
2693 g_list_free(element_bucket);
2696 wfd_sink->pipeline->a_sinkbin = a_sinkbin;
2698 wfd_sink_debug_fleave();
2700 return MM_ERROR_NONE;
2703 wfd_sink_error("failed to create audio sinkbin, releasing all");
2706 gst_object_unref(GST_OBJECT(pad));
2710 gst_object_unref(GST_OBJECT(ghostpad));
2714 g_list_free(element_bucket);
2715 element_bucket = NULL;
2717 /* release element which are not added to bin */
2718 for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */
2719 if (a_sinkbin != NULL && a_sinkbin[i].gst) {
2720 GstObject *parent = NULL;
2721 parent = gst_element_get_parent(a_sinkbin[i].gst);
2724 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
2725 a_sinkbin[i].gst = NULL;
2727 gst_object_unref(GST_OBJECT(parent));
2732 /* release audio sinkbin with it's childs */
2733 if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst)
2734 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
2736 MMWFDSINK_FREEIF(a_sinkbin);
2738 return MM_ERROR_WFD_INTERNAL;
2741 int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
2743 MMWFDSinkGstElement *v_decodebin = NULL;
2744 MMWFDSinkGstElement *first_element = NULL;
2745 MMWFDSinkGstElement *last_element = NULL;
2746 GList *element_bucket = NULL;
2747 GstPad *sinkpad = NULL;
2748 GstPad *srcpad = NULL;
2749 GstPad *ghostpad = NULL;
2750 GList *first_list = NULL;
2751 GList *last_list = NULL;
2753 wfd_sink_debug_fenter();
2755 wfd_sink_return_val_if_fail(wfd_sink &&
2756 wfd_sink->pipeline &&
2757 wfd_sink->pipeline->v_decodebin &&
2758 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
2759 MM_ERROR_WFD_NOT_INITIALIZED);
2761 if (wfd_sink->video_decodebin_is_linked) {
2762 wfd_sink_debug("video decodebin is already linked... nothing to do");
2763 return MM_ERROR_NONE;
2766 /* take video decodebin */
2767 v_decodebin = wfd_sink->pipeline->v_decodebin;
2769 /* check video queue */
2770 if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
2771 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]);
2773 /* check video hdcp */
2774 if (v_decodebin[WFD_SINK_V_D_HDCP].gst)
2775 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]);
2777 /* check video codec */
2778 switch (wfd_sink->stream_info.video_stream_info.codec) {
2779 case MM_WFD_SINK_VIDEO_CODEC_H264:
2780 if (v_decodebin[WFD_SINK_V_D_PARSE].gst)
2781 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]);
2782 if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) {
2783 GstCaps *caps = NULL;
2785 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]);
2786 caps = gst_caps_new_simple("video/x-h264",
2787 "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width,
2788 "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height,
2789 "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL);
2790 g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL);
2791 gst_object_unref(GST_OBJECT(caps));
2793 if (v_decodebin[WFD_SINK_V_D_DEC].gst)
2794 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]);
2798 wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
2799 return MM_ERROR_WFD_INTERNAL;
2803 if (element_bucket == NULL) {
2804 wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it");
2805 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
2806 wfd_sink_error("failed to destroy video decodebin");
2812 /* adding elements to video decodebin */
2813 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) {
2814 wfd_sink_error("failed to add elements to video decodebin");
2818 /* linking elements in the bucket by added order. */
2819 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2820 wfd_sink_error("failed to link elements of the video decodebin");
2824 /* get first element's sinkpad for creating ghostpad */
2825 first_list = g_list_first(element_bucket);
2826 if (first_list == NULL) {
2827 wfd_sink_error("failed to get first list of the element_bucket");
2831 first_element = (MMWFDSinkGstElement *)first_list->data;
2832 if (!first_element) {
2833 wfd_sink_error("failed to get first element of the video decodebin");
2837 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2839 wfd_sink_error("failed to get sink pad from element(%s)",
2840 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2844 ghostpad = gst_ghost_pad_new("sink", sinkpad);
2846 wfd_sink_error("failed to create ghostpad of video decodebin");
2850 if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
2851 wfd_sink_error("failed to add ghostpad to video decodebin");
2854 gst_object_unref(GST_OBJECT(sinkpad));
2858 /* get last element's src for creating ghostpad */
2859 last_list = g_list_last(element_bucket);
2860 if (last_list == NULL) {
2861 wfd_sink_error("failed to get last list of the element_bucket");
2865 last_element = (MMWFDSinkGstElement *)last_list->data;
2866 if (!last_element) {
2867 wfd_sink_error("failed to get last element of the video decodebin");
2871 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2873 wfd_sink_error("failed to get src pad from element(%s)",
2874 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
2878 ghostpad = gst_ghost_pad_new("src", srcpad);
2880 wfd_sink_error("failed to create ghostpad of video decodebin");
2884 if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
2885 wfd_sink_error("failed to add ghostpad to video decodebin");
2888 gst_object_unref(GST_OBJECT(srcpad));
2891 g_list_free(element_bucket);
2894 wfd_sink->video_decodebin_is_linked = TRUE;
2896 wfd_sink_debug_fleave();
2898 return MM_ERROR_NONE;
2903 gst_object_unref(GST_OBJECT(srcpad));
2906 if (sinkpad != NULL)
2907 gst_object_unref(GST_OBJECT(sinkpad));
2910 g_list_free(element_bucket);
2912 return MM_ERROR_WFD_INTERNAL;
2915 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
2917 wfd_sink_debug_fenter();
2919 /* check video decoder is created */
2920 wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT);
2921 wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2923 wfd_sink_debug_fleave();
2925 return MM_ERROR_NONE;
2928 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
2930 gboolean visible = TRUE;
2931 gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
2933 wfd_sink_debug_fenter();
2935 /* check videosink is created */
2936 wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2937 wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2939 /* update display surface */
2940 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
2941 wfd_sink_debug("check display surface type attribute: %d", surface_type);
2942 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
2943 wfd_sink_debug("check display visible attribute: %d", visible);
2945 /* configuring display */
2946 switch (surface_type) {
2947 case MM_DISPLAY_SURFACE_EVAS: {
2948 void *object = NULL;
2951 /* common case if using evas surface */
2952 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
2953 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
2955 wfd_sink_debug("set video param : evas-object %x", object);
2956 g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
2958 wfd_sink_error("no evas object");
2959 return MM_ERROR_WFD_INTERNAL;
2964 case MM_DISPLAY_SURFACE_OVERLAY: {
2965 void *object = NULL;
2966 Evas_Object *obj = NULL;
2967 const char *object_type = NULL;
2968 unsigned int g_xwin = 0;
2971 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
2973 if (object != NULL) {
2974 obj = (Evas_Object *)object;
2975 object_type = evas_object_type_get(obj);
2977 wfd_sink_debug("window object type : %s", object_type);
2979 if (!strcmp(object_type, "elm_win"))
2980 g_xwin = elm_win_xwindow_get(obj);
2983 wfd_sink_debug("xid = %lu", g_xwin);
2984 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), g_xwin);
2989 case MM_DISPLAY_SURFACE_NULL: {
2991 wfd_sink_error("Not Supported Surface.");
2992 return MM_ERROR_WFD_INTERNAL;
2996 wfd_sink_error("Not Supported Surface.(default case)");
2997 return MM_ERROR_WFD_INTERNAL;
3002 g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
3003 g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
3004 g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL);
3005 g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
3006 g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL);
3008 wfd_sink_debug_fleave();
3010 return MM_ERROR_NONE;
3013 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
3015 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3016 MMWFDSinkGstElement *v_decodebin = NULL;
3017 GstObject *parent = NULL;
3020 wfd_sink_debug_fenter();
3022 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3024 if (wfd_sink->pipeline &&
3025 wfd_sink->pipeline->v_decodebin &&
3026 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
3027 v_decodebin = wfd_sink->pipeline->v_decodebin;
3029 wfd_sink_debug("video decodebin is not created, nothing to destroy");
3030 return MM_ERROR_NONE;
3034 parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst);
3036 wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
3038 if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
3039 wfd_sink_debug("try to change state of video decodebin to NULL");
3040 ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
3041 if (ret != GST_STATE_CHANGE_SUCCESS) {
3042 wfd_sink_error("failed to change state of video decodebin to NULL");
3043 return MM_ERROR_WFD_INTERNAL;
3046 /* release element which are not added to bin */
3047 for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */
3048 if (v_decodebin[i].gst) {
3049 parent = gst_element_get_parent(v_decodebin[i].gst);
3051 wfd_sink_debug("unref %s(current ref %d)",
3052 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
3053 ((GObject *) v_decodebin[i].gst)->ref_count);
3054 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
3055 v_decodebin[i].gst = NULL;
3057 wfd_sink_debug("unref %s(current ref %d)",
3058 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
3059 ((GObject *) v_decodebin[i].gst)->ref_count);
3060 gst_object_unref(GST_OBJECT(parent));
3064 /* release video decodebin with it's childs */
3065 if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
3066 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
3067 wfd_sink_debug("unref %s(current ref %d)",
3068 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
3069 ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
3072 wfd_sink_debug("video decodebin has parent(%s), unref it",
3073 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3075 gst_object_unref(GST_OBJECT(parent));
3078 wfd_sink->video_decodebin_is_linked = FALSE;
3080 MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
3082 wfd_sink_debug_fleave();
3084 return MM_ERROR_NONE;
3087 static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
3089 MMWFDSinkGstElement *v_decodebin = NULL;
3090 guint video_codec = WFD_VIDEO_UNKNOWN;
3091 GList *element_bucket = NULL;
3092 gboolean link = TRUE;
3095 wfd_sink_debug_fenter();
3097 wfd_sink_return_val_if_fail(wfd_sink &&
3099 MM_ERROR_WFD_NOT_INITIALIZED);
3101 if (wfd_sink->pipeline->v_decodebin) {
3102 wfd_sink_debug("video decodebin is already created... nothing to do");
3103 return MM_ERROR_NONE;
3106 /* check audio decodebin could be linked now */
3107 switch (wfd_sink->stream_info.video_stream_info.codec) {
3108 case MM_WFD_SINK_VIDEO_CODEC_H264:
3109 video_codec = WFD_VIDEO_H264;
3112 case MM_WFD_SINK_VIDEO_CODEC_NONE:
3114 wfd_sink_debug("video decodebin could NOT be linked now, just create");
3115 video_codec = wfd_sink->ini.video_codec;
3121 v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
3123 wfd_sink_error("failed to allocate memory for video decodebin");
3124 return MM_ERROR_WFD_NO_FREE_SPACE;
3127 memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
3129 /* create video decodebin */
3130 v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN;
3131 v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin");
3132 if (!v_decodebin[WFD_SINK_V_D_BIN].gst) {
3133 wfd_sink_error("failed to create video decodebin");
3138 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
3139 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "sink");
3140 if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
3141 __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
3144 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE);
3145 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "sink");
3146 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "src");
3148 if (video_codec & WFD_VIDEO_H264) {
3150 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE);
3151 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "sink");
3152 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "src");
3154 /* create capssetter */
3155 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE);
3156 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "sink");
3157 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "src");
3160 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE);
3161 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "sink");
3162 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "src");
3163 if (v_decodebin[WFD_SINK_V_D_DEC].gst) {
3164 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) {
3165 wfd_sink_error("failed to set video decoder property...");
3171 g_list_free(element_bucket);
3174 wfd_sink->pipeline->v_decodebin = v_decodebin;
3176 /* link video decodebin if video codec is fixed */
3178 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
3179 wfd_sink_error("failed to link video decodebin, destroy video decodebin");
3180 __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
3181 return MM_ERROR_WFD_INTERNAL;
3185 wfd_sink_debug_fleave();
3187 return MM_ERROR_NONE;
3191 wfd_sink_error("failed to create video decodebin, releasing all");
3193 g_list_free(element_bucket);
3195 /* release element which are not added to bin */
3196 for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */
3197 if (v_decodebin != NULL && v_decodebin[i].gst) {
3198 GstObject *parent = NULL;
3199 parent = gst_element_get_parent(v_decodebin[i].gst);
3202 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
3203 v_decodebin[i].gst = NULL;
3205 gst_object_unref(GST_OBJECT(parent));
3210 /* release video decodebin with it's childs */
3211 if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst)
3212 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
3214 MMWFDSINK_FREEIF(v_decodebin);
3216 return MM_ERROR_WFD_INTERNAL;
3219 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
3221 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3222 MMWFDSinkGstElement *v_sinkbin = NULL;
3223 GstObject *parent = NULL;
3226 wfd_sink_debug_fenter();
3228 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3230 if (wfd_sink->pipeline &&
3231 wfd_sink->pipeline->v_sinkbin &&
3232 wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3233 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
3235 wfd_sink_debug("video sinkbin is not created, nothing to destroy");
3236 return MM_ERROR_NONE;
3240 parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst);
3242 wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
3244 if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
3245 wfd_sink_debug("try to change state of video sinkbin to NULL");
3246 ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
3247 if (ret != GST_STATE_CHANGE_SUCCESS) {
3248 wfd_sink_error("failed to change state of video sinkbin to NULL");
3249 return MM_ERROR_WFD_INTERNAL;
3252 /* release element which are not added to bin */
3253 for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */
3254 if (v_sinkbin[i].gst) {
3255 parent = gst_element_get_parent(v_sinkbin[i].gst);
3257 wfd_sink_debug("unref %s(current ref %d)",
3258 GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
3259 ((GObject *) v_sinkbin[i].gst)->ref_count);
3260 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
3261 v_sinkbin[i].gst = NULL;
3263 wfd_sink_debug("unref %s(current ref %d)",
3264 GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
3265 ((GObject *) v_sinkbin[i].gst)->ref_count);
3266 gst_object_unref(GST_OBJECT(parent));
3270 /* release video sinkbin with it's childs */
3271 if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3272 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
3275 wfd_sink_debug("video sinkbin has parent(%s), unref it ",
3276 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3278 gst_object_unref(GST_OBJECT(parent));
3281 MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
3283 wfd_sink_debug_fleave();
3285 return MM_ERROR_NONE;
3288 static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
3290 MMWFDSinkGstElement *first_element = NULL;
3291 MMWFDSinkGstElement *v_sinkbin = NULL;
3292 GList *element_bucket = NULL;
3294 GstPad *ghostpad = NULL;
3296 gint surface_type = MM_DISPLAY_SURFACE_OVERLAY;
3298 wfd_sink_debug_fenter();
3300 wfd_sink_return_val_if_fail(wfd_sink &&
3302 MM_ERROR_WFD_NOT_INITIALIZED);
3305 v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
3307 wfd_sink_error("failed to allocate memory for video sinkbin");
3308 return MM_ERROR_WFD_NO_FREE_SPACE;
3311 memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
3313 /* create video sinkbin */
3314 v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN;
3315 v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin");
3316 if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3317 wfd_sink_error("failed to create video sinkbin");
3321 /* create convert */
3322 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE);
3323 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "sink");
3324 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "src");
3327 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE);
3328 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "sink");
3329 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "src");
3330 if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) {
3331 GstCaps *caps = NULL;
3332 caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "SN12", NULL);
3333 g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
3334 gst_object_unref(GST_OBJECT(caps));
3338 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type);
3340 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3341 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
3342 } else if (surface_type == MM_DISPLAY_SURFACE_EVAS) {
3343 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_evas_sink, "video_sink", TRUE);
3345 wfd_sink_error("failed to set video sink....");
3349 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst, "sink");
3350 if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
3351 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
3352 wfd_sink_error("failed to set video sink property....");
3357 /* adding created elements to video sinkbin */
3358 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) {
3359 wfd_sink_error("failed to add elements to video sinkbin");
3363 /* linking elements in the bucket by added order. */
3364 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3365 wfd_sink_error("failed to link elements of the video sinkbin");
3369 /* get first element's sinkpad for creating ghostpad */
3370 first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
3371 if (!first_element) {
3372 wfd_sink_error("failed to get first element of the video sinkbin");
3376 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3378 wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
3379 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3383 ghostpad = gst_ghost_pad_new("sink", pad);
3385 wfd_sink_error("failed to create ghostpad of the video sinkbin");
3389 if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) {
3390 wfd_sink_error("failed to add ghostpad to video sinkbin");
3394 gst_object_unref(GST_OBJECT(pad));
3396 g_list_free(element_bucket);
3400 wfd_sink->pipeline->v_sinkbin = v_sinkbin;
3402 wfd_sink_debug_fleave();
3404 return MM_ERROR_NONE;
3408 wfd_sink_error("failed to create video sinkbin, releasing all");
3411 gst_object_unref(GST_OBJECT(pad));
3415 gst_object_unref(GST_OBJECT(ghostpad));
3418 g_list_free(element_bucket);
3420 /* release element which are not added to bin */
3421 for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */
3422 if (v_sinkbin != NULL && v_sinkbin[i].gst) {
3423 GstObject *parent = NULL;
3424 parent = gst_element_get_parent(v_sinkbin[i].gst);
3427 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
3428 v_sinkbin[i].gst = NULL;
3430 gst_object_unref(GST_OBJECT(parent));
3435 /* release video sinkbin with it's childs */
3436 if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst)
3437 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
3439 MMWFDSINK_FREEIF(v_sinkbin);
3441 return MM_ERROR_WFD_INTERNAL;
3444 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
3446 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3448 wfd_sink_debug_fenter();
3450 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3452 /* cleanup gst stuffs */
3453 if (wfd_sink->pipeline) {
3454 MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
3457 ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
3458 if (ret != GST_STATE_CHANGE_SUCCESS) {
3459 wfd_sink_error("failed to change state of mainbin to NULL");
3460 return MM_ERROR_WFD_INTERNAL;
3463 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
3464 wfd_sink_error("failed to destroy video decodebin");
3465 return MM_ERROR_WFD_INTERNAL;
3468 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
3469 wfd_sink_error("failed to destroy audio decodebin");
3470 return MM_ERROR_WFD_INTERNAL;
3473 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) {
3474 wfd_sink_error("failed to destroy video sinkbin");
3475 return MM_ERROR_WFD_INTERNAL;
3478 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) {
3479 wfd_sink_error("failed to destroy audio sinkbin");
3480 return MM_ERROR_WFD_INTERNAL;
3483 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
3485 MMWFDSINK_FREEIF(mainbin);
3488 MMWFDSINK_FREEIF(wfd_sink->pipeline);
3491 wfd_sink->audio_decodebin_is_linked = FALSE;
3492 wfd_sink->video_decodebin_is_linked = FALSE;
3493 wfd_sink->need_to_reset_basetime = FALSE;
3495 wfd_sink_debug_fleave();
3497 return MM_ERROR_NONE;
3501 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
3503 GstIterator *iter = NULL;
3504 gboolean done = FALSE;
3506 GstElement *item = NULL;
3507 GstElementFactory *factory = NULL;
3509 GstState state = GST_STATE_VOID_PENDING;
3510 GstState pending = GST_STATE_VOID_PENDING;
3511 GstClockTime time = 200 * GST_MSECOND;
3513 wfd_sink_debug_fenter();
3515 wfd_sink_return_if_fail(wfd_sink &&
3516 wfd_sink->pipeline &&
3517 wfd_sink->pipeline->mainbin &&
3518 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3520 iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
3524 switch (gst_iterator_next(iter, (gpointer)&item)) {
3525 case GST_ITERATOR_OK:
3526 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
3528 factory = gst_element_get_factory(item) ;
3530 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
3531 GST_STR_NULL(GST_OBJECT_NAME(factory)),
3532 GST_STR_NULL(GST_ELEMENT_NAME(item)),
3533 gst_element_state_get_name(state),
3534 gst_element_state_get_name(pending),
3535 GST_OBJECT_REFCOUNT_VALUE(item));
3537 gst_object_unref(item);
3539 case GST_ITERATOR_RESYNC:
3540 gst_iterator_resync(iter);
3542 case GST_ITERATOR_ERROR:
3545 case GST_ITERATOR_DONE:
3555 item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3557 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
3559 factory = gst_element_get_factory(item) ;
3561 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
3562 GST_OBJECT_NAME(factory),
3563 GST_ELEMENT_NAME(item),
3564 gst_element_state_get_name(state),
3565 gst_element_state_get_name(pending),
3566 GST_OBJECT_REFCOUNT_VALUE(item));
3570 gst_iterator_free(iter);
3572 wfd_sink_debug_fleave();
3577 const gchar * _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
3580 case MM_WFD_SINK_STATE_NONE:
3582 case MM_WFD_SINK_STATE_NULL:
3584 case MM_WFD_SINK_STATE_PREPARED:
3586 case MM_WFD_SINK_STATE_CONNECTED:
3588 case MM_WFD_SINK_STATE_PLAYING:
3590 case MM_WFD_SINK_STATE_PAUSED:
3592 case MM_WFD_SINK_STATE_DISCONNECTED:
3593 return "DISCONNECTED";
3599 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution, guint *VESA_resolution, guint *HH_resolution)
3601 if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
3603 *CEA_resolution = 0;
3604 *VESA_resolution = 0;
3607 if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
3608 *CEA_resolution |= WFD_CEA_1920x1080P30;
3610 if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
3611 *CEA_resolution |= WFD_CEA_1280x720P30;
3613 if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
3614 *HH_resolution |= WFD_HH_960x540P30;
3616 if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
3617 *HH_resolution |= WFD_HH_864x480P30;
3619 if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
3620 *CEA_resolution |= WFD_CEA_720x480P60;
3622 if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
3623 *CEA_resolution |= WFD_CEA_640x480P60;
3625 if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
3626 *HH_resolution |= WFD_HH_640x360P30;
3629 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
3631 MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
3633 wfd_sink_debug_fenter();
3635 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3637 MMWFDSINK_PRINT_STATE(wfd_sink);
3638 cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
3639 if (cur_state != MM_WFD_SINK_STATE_NULL) {
3640 wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL");
3641 return MM_ERROR_WFD_INVALID_STATE;
3644 wfd_sink->supportive_resolution = resolution;
3646 wfd_sink_debug_fleave();
3648 return MM_ERROR_NONE;