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>
26 #include "mm_wfd_sink_util.h"
27 #include "mm_wfd_sink_priv.h"
28 #include "mm_wfd_sink_manager.h"
29 #include "mm_wfd_sink_dlog.h"
30 #include <wfdconfigmessage.h>
34 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink);
35 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink);
36 static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink);
37 static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink);
38 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink);
39 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink);
40 static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink);
41 static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink);
42 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink);
43 static int __mm_wfd_sink_set_pipeline_state(mm_wfd_sink_t *wfd_sink, GstState state, gboolean async);
46 static int __mm_wfd_sink_check_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkCommandType cmd);
47 static int __mm_wfd_sink_set_state(mm_wfd_sink_t *wfd_sink, MMWFDSinkStateType state);
50 static void __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink);
51 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution,
52 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://"),
243 MM_ERROR_WFD_INVALID_ARGUMENT);
244 wfd_sink_return_val_if_fail(wfd_sink &&
245 wfd_sink->pipeline &&
246 wfd_sink->pipeline->mainbin &&
247 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
248 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst &&
249 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEPAY].gst &&
250 wfd_sink->pipeline->mainbin[WFD_SINK_M_DEMUX].gst,
251 MM_ERROR_WFD_NOT_INITIALIZED);
253 /* check current wi-fi display sink state */
254 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_CONNECT);
256 wfd_sink_debug("try to connect to %s.....", GST_STR_NULL(uri));
258 /* set uri to wfdrtspsrc */
259 g_object_set(G_OBJECT(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst), "location", uri, NULL);
261 /* set pipeline PAUSED state */
262 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PAUSED, TRUE);
263 if (result < MM_ERROR_NONE) {
264 wfd_sink_error("failed to set state : %d", result);
268 wfd_sink_debug_fleave();
273 int _mm_wfd_sink_start(mm_wfd_sink_t *wfd_sink)
275 int result = MM_ERROR_NONE;
277 wfd_sink_debug_fenter();
279 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
281 /* check current wi-fi display sink state */
282 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_START);
284 WFD_SINK_MANAGER_LOCK(wfd_sink) ;
285 wfd_sink_debug("check pipeline is ready to start");
286 WFD_SINK_MANAGER_UNLOCK(wfd_sink);
288 result = __mm_wfd_sink_set_pipeline_state(wfd_sink, GST_STATE_PLAYING, TRUE);
289 if (result < MM_ERROR_NONE) {
290 wfd_sink_error("failed to set state : %d", result);
294 wfd_sink_debug_fleave();
299 int _mm_wfd_sink_pause(mm_wfd_sink_t *wfd_sink)
301 int result = MM_ERROR_NONE;
303 wfd_sink_debug_fenter();
305 wfd_sink_return_val_if_fail(wfd_sink &&
306 wfd_sink->pipeline &&
307 wfd_sink->pipeline->mainbin &&
308 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
309 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
310 MM_ERROR_WFD_NOT_INITIALIZED);
312 /* check current wi-fi display sink state */
313 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_PAUSE);
315 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "pause", NULL);
317 wfd_sink_debug_fleave();
322 int _mm_wfd_sink_resume(mm_wfd_sink_t *wfd_sink)
324 int result = MM_ERROR_NONE;
326 wfd_sink_debug_fenter();
328 wfd_sink_return_val_if_fail(wfd_sink &&
329 wfd_sink->pipeline &&
330 wfd_sink->pipeline->mainbin &&
331 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
332 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
333 MM_ERROR_WFD_NOT_INITIALIZED);
335 /* check current wi-fi display sink state */
336 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_RESUME);
338 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "resume", NULL);
340 wfd_sink_debug_fleave();
345 int _mm_wfd_sink_disconnect(mm_wfd_sink_t *wfd_sink)
347 int result = MM_ERROR_NONE;
349 wfd_sink_debug_fenter();
351 wfd_sink_return_val_if_fail(wfd_sink &&
352 wfd_sink->pipeline &&
353 wfd_sink->pipeline->mainbin &&
354 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst &&
355 wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst,
356 MM_ERROR_WFD_NOT_INITIALIZED);
358 /* check current wi-fi display sink state */
359 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DISCONNECT);
361 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
362 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
364 g_signal_emit_by_name(wfd_sink->pipeline->mainbin[WFD_SINK_M_SRC].gst, "close", NULL);
366 wfd_sink_debug_fleave();
371 int _mm_wfd_sink_unprepare(mm_wfd_sink_t *wfd_sink)
373 int result = MM_ERROR_NONE;
375 wfd_sink_debug_fenter();
377 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
379 /* check current wi-fi display sink state */
380 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_UNPREPARE);
382 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_EXIT);
383 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
385 /* release pipeline */
386 result = __mm_wfd_sink_destroy_pipeline(wfd_sink);
387 if (result != MM_ERROR_NONE) {
388 wfd_sink_error("failed to destory pipeline");
389 return MM_ERROR_WFD_INTERNAL;
391 wfd_sink_debug("success to destory pipeline");
395 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NULL);
397 wfd_sink_debug_fleave();
402 int _mm_wfd_sink_destroy(mm_wfd_sink_t *wfd_sink)
404 int result = MM_ERROR_NONE;
406 wfd_sink_debug_fenter();
408 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
410 /* check current wi-fi display sink state */
411 MMWFDSINK_CHECK_STATE(wfd_sink, MM_WFD_SINK_COMMAND_DESTROY);
414 mm_wfd_sink_ini_unload(&wfd_sink->ini);
416 /* release attributes */
417 _mmwfd_deconstruct_attribute(wfd_sink->attrs);
419 if (MM_ERROR_NONE != _mm_wfd_sink_release_manager(wfd_sink)) {
420 wfd_sink_error("failed to release manager");
421 return MM_ERROR_WFD_INTERNAL;
426 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_NONE);
428 wfd_sink_debug_fleave();
433 int _mm_wfd_set_message_callback(mm_wfd_sink_t *wfd_sink, MMWFDMessageCallback callback, void *user_data)
435 int result = MM_ERROR_NONE;
437 wfd_sink_debug_fenter();
439 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
441 wfd_sink->msg_cb = callback;
442 wfd_sink->msg_user_data = user_data;
444 wfd_sink_debug_fleave();
449 static int __mm_wfd_sink_init_gstreamer(mm_wfd_sink_t *wfd_sink)
451 int result = MM_ERROR_NONE;
454 static const int max_argc = 50;
458 wfd_sink_debug_fenter();
461 argc = calloc(1, sizeof(gint));
462 argv = calloc(max_argc, sizeof(gchar *));
463 if (!argc || !argv) {
464 wfd_sink_error("failed to allocate memory for wfdsink");
466 MMWFDSINK_FREEIF(argv);
467 MMWFDSINK_FREEIF(argc);
469 return MM_ERROR_WFD_NO_FREE_SPACE;
472 /* we would not do fork for scanning plugins */
473 argv[*argc] = g_strdup("--gst-disable-registry-fork");
476 /* check disable registry scan */
477 argv[*argc] = g_strdup("--gst-disable-registry-update");
480 /* check disable segtrap */
481 argv[*argc] = g_strdup("--gst-disable-segtrap");
485 for (i = 0; i < 5; i++) {
486 if (strlen(wfd_sink->ini.gst_param[i]) > 2) {
487 wfd_sink_debug("set %s", wfd_sink->ini.gst_param[i]);
488 argv[*argc] = g_strdup(wfd_sink->ini.gst_param[i]);
493 wfd_sink_debug("initializing gstreamer with following parameter");
494 wfd_sink_debug("argc : %d", *argc);
496 for (i = 0; i < *argc; i++) {
497 wfd_sink_debug("argv[%d] : %s", i, argv[i]);
500 /* initializing gstreamer */
501 if (!gst_init_check(argc, &argv, &err)) {
502 wfd_sink_error("failed to initialize gstreamer: %s",
503 err ? err->message : "unknown error occurred");
507 result = MM_ERROR_WFD_INTERNAL;
511 for (i = 0; i < *argc; i++) {
512 MMWFDSINK_FREEIF(argv[i]);
514 MMWFDSINK_FREEIF(argv);
515 MMWFDSINK_FREEIF(argc);
517 wfd_sink_debug_fleave();
522 static GstBusSyncReply
523 _mm_wfd_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data)
525 GstBusSyncReply ret = GST_BUS_PASS;
527 wfd_sink_return_val_if_fail(message &&
528 GST_IS_MESSAGE(message) &&
529 GST_MESSAGE_SRC(message),
532 switch (GST_MESSAGE_TYPE(message)) {
533 case GST_MESSAGE_TAG:
535 case GST_MESSAGE_DURATION:
537 case GST_MESSAGE_STATE_CHANGED: {
538 /* we only handle state change messages from pipeline */
539 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
543 case GST_MESSAGE_ASYNC_DONE: {
544 if (!GST_IS_PIPELINE(GST_MESSAGE_SRC(message)))
556 _mm_wfd_sink_msg_callback(GstBus *bus, GstMessage *msg, gpointer data)
558 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *) data;
559 const GstStructure *message_structure = gst_message_get_structure(msg);
562 wfd_sink_return_val_if_fail(wfd_sink, FALSE);
563 wfd_sink_return_val_if_fail(msg && GST_IS_MESSAGE(msg), FALSE);
565 wfd_sink_debug("got %s from %s",
566 GST_STR_NULL(GST_MESSAGE_TYPE_NAME(msg)),
567 GST_STR_NULL(GST_OBJECT_NAME(GST_MESSAGE_SRC(msg))));
569 switch (GST_MESSAGE_TYPE(msg)) {
570 case GST_MESSAGE_ERROR: {
571 GError *error = NULL;
575 gst_message_parse_error(msg, &error, &debug);
577 wfd_sink_error("error : %s", error->message);
578 wfd_sink_error("debug : %s", debug);
580 MMWFDSINK_FREEIF(debug);
585 case GST_MESSAGE_WARNING: {
587 GError *error = NULL;
589 gst_message_parse_warning(msg, &error, &debug);
591 wfd_sink_warning("warning : %s", error->message);
592 wfd_sink_warning("debug : %s", debug);
594 MMWFDSINK_FREEIF(debug);
599 case GST_MESSAGE_STATE_CHANGED: {
600 const GValue *voldstate, *vnewstate, *vpending;
601 GstState oldstate, newstate, pending;
602 const GstStructure *structure;
604 /* we only handle messages from pipeline */
605 if (msg->src != (GstObject *)wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst)
608 /* get state info from msg */
609 structure = gst_message_get_structure(msg);
610 if (structure == NULL)
613 voldstate = gst_structure_get_value(structure, "old-state");
614 vnewstate = gst_structure_get_value(structure, "new-state");
615 vpending = gst_structure_get_value(structure, "pending-state");
616 if (voldstate == NULL || vnewstate == NULL || vpending == NULL)
619 oldstate = (GstState)voldstate->data[0].v_int;
620 newstate = (GstState)vnewstate->data[0].v_int;
621 pending = (GstState)vpending->data[0].v_int;
623 wfd_sink_debug("state changed [%s] : %s--->%s final : %s",
624 GST_OBJECT_NAME(GST_MESSAGE_SRC(msg)),
625 gst_element_state_get_name((GstState)oldstate),
626 gst_element_state_get_name((GstState)newstate),
627 gst_element_state_get_name((GstState)pending));
629 if (oldstate == newstate) {
630 wfd_sink_debug("pipeline reports state transition to old state");
635 case GST_STATE_VOID_PENDING:
637 case GST_STATE_READY:
638 case GST_STATE_PAUSED:
639 case GST_STATE_PLAYING:
646 case GST_MESSAGE_CLOCK_LOST: {
647 GstClock *clock = NULL;
648 gst_message_parse_clock_lost(msg, &clock);
649 wfd_sink_debug("The current clock[%s] as selected by the pipeline became unusable.",
650 (clock ? GST_OBJECT_NAME(clock) : "NULL"));
654 case GST_MESSAGE_NEW_CLOCK: {
655 GstClock *clock = NULL;
656 gst_message_parse_new_clock(msg, &clock);
660 if (wfd_sink->clock) {
661 if (wfd_sink->clock != clock)
662 wfd_sink_debug("clock is changed! [%s] -->[%s]",
663 GST_STR_NULL(GST_OBJECT_NAME(wfd_sink->clock)),
664 GST_STR_NULL(GST_OBJECT_NAME(clock)));
666 wfd_sink_debug("same clock is selected again! [%s]",
667 GST_STR_NULL(GST_OBJECT_NAME(clock)));
669 wfd_sink_debug("new clock [%s] was selected in the pipeline",
670 (GST_STR_NULL(GST_OBJECT_NAME(clock))));
673 wfd_sink->clock = clock;
677 case GST_MESSAGE_APPLICATION: {
678 const gchar *message_structure_name;
680 message_structure_name = gst_structure_get_name(message_structure);
681 if (!message_structure_name)
684 wfd_sink_debug("message name : %s", GST_STR_NULL(message_structure_name));
688 case GST_MESSAGE_ELEMENT: {
689 const gchar *structure_name = NULL;
691 structure_name = gst_structure_get_name(message_structure);
692 if (structure_name) {
693 wfd_sink_debug("got element specific message[%s]", GST_STR_NULL(structure_name));
694 if (g_strrstr(structure_name, "GstUDPSrcTimeout")) {
695 wfd_sink_error("Got %s, post error message", GST_STR_NULL(structure_name));
696 MMWFDSINK_POST_MESSAGE(wfd_sink,
697 MM_ERROR_WFD_INTERNAL,
698 MMWFDSINK_CURRENT_STATE(wfd_sink));
704 case GST_MESSAGE_PROGRESS: {
705 GstProgressType type = GST_PROGRESS_TYPE_ERROR;
706 gchar *category = NULL, *text = NULL;
708 gst_message_parse_progress(msg, &type, &category, &text);
709 wfd_sink_debug("%s : %s ", GST_STR_NULL(category), GST_STR_NULL(text));
712 case GST_PROGRESS_TYPE_START:
714 case GST_PROGRESS_TYPE_COMPLETE:
715 if (category && !strcmp(category, "open"))
716 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_CONNECTED);
717 else if (category && !strcmp(category, "play")) {
718 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PLAYING);
719 /*_mm_wfd_sink_correct_pipeline_latency (wfd_sink); */
720 } else if (category && !strcmp(category, "pause"))
721 __mm_wfd_sink_set_state(wfd_sink, MM_WFD_SINK_STATE_PAUSED);
722 else if (category && !strcmp(category, "close"))
723 __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,
1051 MM_ERROR_WFD_INVALID_ARGUMENT);
1053 wfd_sink_debug("try to set %s state ", gst_element_state_get_name(state));
1055 result = gst_element_set_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst, state);
1056 if (result == GST_STATE_CHANGE_FAILURE) {
1057 wfd_sink_error("fail to set %s state....", gst_element_state_get_name(state));
1058 return MM_ERROR_WFD_INTERNAL;
1062 wfd_sink_debug("wait for changing state is completed ");
1064 result = gst_element_get_state(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1065 &cur_state, &pending_state, wfd_sink->ini.state_change_timeout * GST_SECOND);
1066 if (result == GST_STATE_CHANGE_FAILURE) {
1067 wfd_sink_error("fail to get state within %d seconds....", wfd_sink->ini.state_change_timeout);
1069 __mm_wfd_sink_dump_pipeline_state(wfd_sink);
1071 return MM_ERROR_WFD_INTERNAL;
1072 } else if (result == GST_STATE_CHANGE_NO_PREROLL) {
1073 wfd_sink_debug("successfully changed state but is not able to provide data yet");
1076 wfd_sink_debug("cur state is %s, pending state is %s",
1077 gst_element_state_get_name(cur_state),
1078 gst_element_state_get_name(pending_state));
1082 wfd_sink_debug_fleave();
1084 return MM_ERROR_NONE;
1088 _mm_wfd_sink_reset_basetime(mm_wfd_sink_t *wfd_sink)
1090 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1093 wfd_sink_debug_fenter();
1095 wfd_sink_return_if_fail(wfd_sink &&
1096 wfd_sink->pipeline &&
1097 wfd_sink->pipeline->mainbin &&
1098 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1099 wfd_sink_return_if_fail(wfd_sink->need_to_reset_basetime);
1102 if (wfd_sink->clock)
1103 base_time = gst_clock_get_time(wfd_sink->clock);
1105 if (GST_CLOCK_TIME_IS_VALID(base_time)) {
1107 wfd_sink_debug("set pipeline base_time as now [%"GST_TIME_FORMAT"]", GST_TIME_ARGS(base_time));
1109 for (i = 0; i < WFD_SINK_M_NUM; i++) {
1110 if (wfd_sink->pipeline->mainbin[i].gst)
1111 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[i].gst), base_time);
1114 if (wfd_sink->pipeline->v_decodebin) {
1115 for (i = 0; i < WFD_SINK_V_D_NUM; i++) {
1116 if (wfd_sink->pipeline->v_decodebin[i].gst)
1117 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_decodebin[i].gst), base_time);
1121 if (wfd_sink->pipeline->v_sinkbin) {
1122 for (i = 0; i < WFD_SINK_V_S_NUM; i++) {
1123 if (wfd_sink->pipeline->v_sinkbin[i].gst)
1124 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->v_sinkbin[i].gst), base_time);
1128 if (wfd_sink->pipeline->a_decodebin) {
1129 for (i = 0; i < WFD_SINK_A_D_NUM; i++) {
1130 if (wfd_sink->pipeline->a_decodebin[i].gst)
1131 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_decodebin[i].gst), base_time);
1135 if (wfd_sink->pipeline->a_sinkbin) {
1136 for (i = 0; i < WFD_SINK_A_S_NUM; i++) {
1137 if (wfd_sink->pipeline->a_sinkbin[i].gst)
1138 gst_element_set_base_time(GST_ELEMENT_CAST(wfd_sink->pipeline->a_sinkbin[i].gst), base_time);
1142 wfd_sink->need_to_reset_basetime = FALSE;
1145 wfd_sink_debug_fleave();
1151 __mm_wfd_sink_prepare_video_pipeline(mm_wfd_sink_t *wfd_sink)
1153 GstElement *bin = NULL;
1155 wfd_sink_debug_fenter();
1157 wfd_sink_return_val_if_fail(wfd_sink &&
1158 wfd_sink->pipeline &&
1159 wfd_sink->pipeline->mainbin &&
1160 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1161 MM_ERROR_WFD_NOT_INITIALIZED);
1163 /* check video decodebin is linked */
1164 if (!wfd_sink->video_decodebin_is_linked) {
1165 /* check video decodebin is created */
1166 if (wfd_sink->pipeline->v_decodebin == NULL) {
1167 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_decodebin(wfd_sink)) {
1168 wfd_sink_error("failed to create video decodebin....");
1173 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
1174 wfd_sink_error("failed to link video decodebin.....");
1179 /* check video sinkbin is created */
1180 if (wfd_sink->pipeline->v_sinkbin == NULL) {
1181 if (MM_ERROR_NONE != __mm_wfd_sink_create_video_sinkbin(wfd_sink)) {
1182 wfd_sink_error("failed to create video sinkbin....");
1187 /* set video decodebin state as READY */
1188 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
1189 bin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1190 if (GST_STATE(bin) <= GST_STATE_NULL) {
1191 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1192 wfd_sink_error("failed to set state(READY) to video decodebin");
1197 wfd_sink_warning("going on without video decodebin....");
1200 /* set video sinkbin state as READY */
1201 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
1202 bin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1203 if (GST_STATE(bin) <= GST_STATE_NULL) {
1204 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1205 wfd_sink_error("failed to set state(READY) to video sinkbin");
1210 wfd_sink_warning("going on without video sinkbin....");
1213 wfd_sink_debug_fleave();
1215 return MM_ERROR_NONE;
1219 /* need to notify to app */
1220 MMWFDSINK_POST_MESSAGE(wfd_sink,
1221 MM_ERROR_WFD_INTERNAL,
1222 MMWFDSINK_CURRENT_STATE(wfd_sink));
1224 return MM_ERROR_WFD_INTERNAL;
1228 __mm_wfd_sink_prepare_audio_pipeline(mm_wfd_sink_t *wfd_sink)
1230 GstElement *bin = NULL;
1232 wfd_sink_debug_fenter();
1234 wfd_sink_return_val_if_fail(wfd_sink &&
1236 MM_ERROR_WFD_NOT_INITIALIZED);
1238 /* check audio decodebin is linked */
1239 if (!wfd_sink->audio_decodebin_is_linked) {
1240 /* check audio decodebin is created */
1241 if (wfd_sink->pipeline->a_decodebin == NULL) {
1242 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_decodebin(wfd_sink)) {
1243 wfd_sink_error("failed to create audio decodebin....");
1248 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
1249 wfd_sink_error("failed to link audio decodebin.....");
1254 /* check audio sinkbin is created */
1255 if (wfd_sink->pipeline->a_sinkbin == NULL) {
1256 if (MM_ERROR_NONE != __mm_wfd_sink_create_audio_sinkbin(wfd_sink)) {
1257 wfd_sink_error("failed to create audio sinkbin....");
1262 /* set audio decodebin state as READY */
1263 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
1264 bin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1265 if (GST_STATE(bin) <= GST_STATE_NULL) {
1266 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin, GST_STATE_READY)) {
1267 wfd_sink_error("failed to set state(READY) to audio decodebin");
1272 wfd_sink_warning("going on without audio decodebin....");
1275 /* set audio sinkbin state as READY */
1276 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
1277 bin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1278 if (GST_STATE(bin) <= GST_STATE_NULL) {
1279 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(bin , GST_STATE_READY)) {
1280 wfd_sink_error("failed to set state(READY) to audio sinkbin");
1285 wfd_sink_warning("going on without audio sinkbin....");
1288 wfd_sink_debug_fleave();
1290 return MM_ERROR_NONE;
1294 /* need to notify to app */
1295 MMWFDSINK_POST_MESSAGE(wfd_sink,
1296 MM_ERROR_WFD_INTERNAL,
1297 MMWFDSINK_CURRENT_STATE(wfd_sink));
1299 return MM_ERROR_WFD_INTERNAL;
1302 #define COMPENSATION_CRETERIA_VALUE 1000000 /* 1 msec */
1303 #define COMPENSATION_CHECK_PERIOD (30*GST_SECOND) /* 30 sec */
1305 static GstPadProbeReturn
1306 _mm_wfd_sink_check_running_time(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
1308 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)u_data;
1309 GstClockTime current_time = GST_CLOCK_TIME_NONE;
1310 GstClockTime start_time = GST_CLOCK_TIME_NONE;
1311 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1312 GstClockTime base_time = GST_CLOCK_TIME_NONE;
1313 GstClockTime render_time = GST_CLOCK_TIME_NONE;
1314 GstClockTimeDiff diff = GST_CLOCK_TIME_NONE;
1315 GstBuffer *buffer = NULL;
1316 gint64 ts_offset = 0LL;
1318 wfd_sink_return_val_if_fail(info, FALSE);
1319 wfd_sink_return_val_if_fail(wfd_sink &&
1320 wfd_sink->pipeline &&
1321 wfd_sink->pipeline->mainbin &&
1322 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst,
1323 GST_PAD_PROBE_DROP);
1325 if (!wfd_sink->clock) {
1326 wfd_sink_warning("pipeline did not select clock, yet");
1327 return GST_PAD_PROBE_OK;
1330 if (wfd_sink->need_to_reset_basetime)
1331 _mm_wfd_sink_reset_basetime(wfd_sink);
1333 /* calculate current runninig time */
1334 current_time = gst_clock_get_time(wfd_sink->clock);
1335 if (g_strrstr(GST_OBJECT_NAME(pad), "video"))
1336 base_time = gst_element_get_base_time(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst);
1337 else if (g_strrstr(GST_OBJECT_NAME(pad), "audio"))
1338 base_time = gst_element_get_base_time(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst);
1339 start_time = gst_element_get_start_time(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1340 if (GST_CLOCK_TIME_IS_VALID(current_time) &&
1341 GST_CLOCK_TIME_IS_VALID(start_time) &&
1342 GST_CLOCK_TIME_IS_VALID(base_time)) {
1343 running_time = current_time - (start_time + base_time);
1345 wfd_sink_debug("current time %"GST_TIME_FORMAT", start time %"GST_TIME_FORMAT
1346 " base time %"GST_TIME_FORMAT"", GST_TIME_ARGS(current_time),
1347 GST_TIME_ARGS(start_time), GST_TIME_ARGS(base_time));
1348 return GST_PAD_PROBE_OK;
1351 /* calculate this buffer rendering time */
1352 buffer = gst_pad_probe_info_get_buffer(info);
1353 if (!GST_BUFFER_TIMESTAMP_IS_VALID(buffer)) {
1354 wfd_sink_warning("buffer timestamp is invalid.");
1355 return GST_PAD_PROBE_OK;
1358 if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
1359 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
1360 g_object_get(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", &ts_offset, NULL);
1361 } else if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
1362 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
1363 g_object_get(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", &ts_offset, NULL);
1366 render_time = GST_BUFFER_TIMESTAMP(buffer);
1367 render_time += ts_offset;
1369 /* chekc this buffer could be rendered or not */
1370 if (GST_CLOCK_TIME_IS_VALID(running_time) && GST_CLOCK_TIME_IS_VALID(render_time)) {
1371 diff = GST_CLOCK_DIFF(running_time, render_time);
1373 /* this buffer could be NOT rendered */
1374 wfd_sink_debug("%s : diff time : -%" GST_TIME_FORMAT "",
1375 GST_STR_NULL((GST_OBJECT_NAME(pad))),
1376 GST_TIME_ARGS(GST_CLOCK_DIFF(render_time, running_time)));
1378 /* this buffer could be rendered */
1379 /*wfd_sink_debug ("%s :diff time : %" GST_TIME_FORMAT "\n", */
1380 /* GST_STR_NULL((GST_OBJECT_NAME(pad))), */
1381 /* GST_TIME_ARGS(diff)); */
1385 /* update buffer count and gap */
1386 if (g_strrstr(GST_OBJECT_NAME(pad), "video")) {
1387 wfd_sink->video_buffer_count++;
1388 wfd_sink->video_accumulated_gap += diff;
1389 } else if (g_strrstr(GST_OBJECT_NAME(pad), "audio")) {
1390 wfd_sink->audio_buffer_count++;
1391 wfd_sink->audio_accumulated_gap += diff;
1393 wfd_sink_warning("invalid buffer type.. ");
1394 return GST_PAD_PROBE_DROP;
1397 if (GST_CLOCK_TIME_IS_VALID(wfd_sink->last_buffer_timestamp)) {
1398 /* fisrt 60sec, just calculate the gap between source device and sink device */
1399 if (GST_BUFFER_TIMESTAMP(buffer) < 60 * GST_SECOND)
1400 return GST_PAD_PROBE_OK;
1402 /* every 10sec, calculate the gap between source device and sink device */
1403 if (GST_CLOCK_DIFF(wfd_sink->last_buffer_timestamp, GST_BUFFER_TIMESTAMP(buffer))
1404 > COMPENSATION_CHECK_PERIOD) {
1405 gint64 audio_avgrage_gap = 0LL;
1406 gint64 video_avgrage_gap = 0LL;
1407 gint64 audio_avgrage_gap_diff = 0LL;
1408 gint64 video_avgrage_gap_diff = 0LL;
1409 gboolean video_minus_compensation = FALSE;
1410 gboolean audio_minus_compensation = FALSE;
1411 gint64 avgrage_gap_diff = 0LL;
1412 gboolean minus_compensation = FALSE;
1415 if (wfd_sink->video_buffer_count > 0) {
1416 video_avgrage_gap = wfd_sink->video_accumulated_gap / wfd_sink->video_buffer_count;
1418 if (wfd_sink->video_average_gap != 0) {
1419 if (video_avgrage_gap > wfd_sink->video_average_gap) {
1420 video_avgrage_gap_diff = video_avgrage_gap - wfd_sink->video_average_gap;
1421 video_minus_compensation = TRUE;
1423 video_avgrage_gap_diff = wfd_sink->video_average_gap - video_avgrage_gap;
1424 video_minus_compensation = FALSE;
1427 wfd_sink_debug("first update video average gap(%lld) ", video_avgrage_gap);
1428 wfd_sink->video_average_gap = video_avgrage_gap;
1431 wfd_sink_debug("there is no video buffer flow during %"GST_TIME_FORMAT
1432 " ~ %" GST_TIME_FORMAT"",
1433 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1434 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1438 if (wfd_sink->audio_buffer_count > 0) {
1439 audio_avgrage_gap = wfd_sink->audio_accumulated_gap / wfd_sink->audio_buffer_count;
1441 if (wfd_sink->audio_average_gap != 0) {
1442 if (audio_avgrage_gap > wfd_sink->audio_average_gap) {
1443 audio_avgrage_gap_diff = audio_avgrage_gap - wfd_sink->audio_average_gap;
1444 audio_minus_compensation = TRUE;
1446 audio_avgrage_gap_diff = wfd_sink->audio_average_gap - audio_avgrage_gap;
1447 audio_minus_compensation = FALSE;
1450 wfd_sink_debug("first update audio average gap(%lld) ", audio_avgrage_gap);
1451 wfd_sink->audio_average_gap = audio_avgrage_gap;
1454 wfd_sink_debug("there is no audio buffer flow during %"GST_TIME_FORMAT
1455 " ~ %" GST_TIME_FORMAT"",
1456 GST_TIME_ARGS(wfd_sink->last_buffer_timestamp),
1457 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1460 /* selecet average_gap_diff between video and audio */
1461 /* which makes no buffer drop in the sink elements */
1462 if (video_avgrage_gap_diff && audio_avgrage_gap_diff) {
1463 if (!video_minus_compensation && !audio_minus_compensation) {
1464 minus_compensation = FALSE;
1465 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1466 avgrage_gap_diff = video_avgrage_gap_diff;
1468 avgrage_gap_diff = audio_avgrage_gap_diff;
1469 } else if (video_minus_compensation && audio_minus_compensation) {
1470 minus_compensation = TRUE;
1471 if (video_avgrage_gap_diff > audio_avgrage_gap_diff)
1472 avgrage_gap_diff = audio_avgrage_gap_diff;
1474 avgrage_gap_diff = video_avgrage_gap_diff;
1476 minus_compensation = FALSE;
1477 if (!video_minus_compensation)
1478 avgrage_gap_diff = video_avgrage_gap_diff;
1480 avgrage_gap_diff = audio_avgrage_gap_diff;
1482 } else if (video_avgrage_gap_diff) {
1483 minus_compensation = video_minus_compensation;
1484 avgrage_gap_diff = video_avgrage_gap_diff;
1485 } else if (audio_avgrage_gap_diff) {
1486 minus_compensation = audio_minus_compensation;
1487 avgrage_gap_diff = audio_avgrage_gap_diff;
1490 wfd_sink_debug("average diff gap difference beween audio:%s%lld and video:%s%lld ",
1491 audio_minus_compensation ? "-" : "", audio_avgrage_gap_diff,
1492 video_minus_compensation ? "-" : "", video_avgrage_gap_diff);
1495 /* if calculated gap diff is larger than 1ms. need to compensate buffer timestamp */
1496 if (avgrage_gap_diff >= COMPENSATION_CRETERIA_VALUE) {
1497 if (minus_compensation)
1498 ts_offset -= avgrage_gap_diff;
1500 ts_offset += avgrage_gap_diff;
1502 wfd_sink_debug("do timestamp compensation : %s%lld (ts-offset : %"
1503 GST_TIME_FORMAT") at(%" GST_TIME_FORMAT")",
1504 minus_compensation ? "-" : "", avgrage_gap_diff,
1505 GST_TIME_ARGS(ts_offset), GST_TIME_ARGS(running_time));
1507 if (wfd_sink->pipeline && wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst)
1508 g_object_set(G_OBJECT(wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1509 if (wfd_sink->pipeline && wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst)
1510 g_object_set(G_OBJECT(wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_SINK].gst), "ts-offset", (gint64)ts_offset, NULL);
1512 wfd_sink_debug("don't need to do timestamp compensation : %s%lld (ts-offset : %"GST_TIME_FORMAT ")",
1513 minus_compensation ? "-" : "", avgrage_gap_diff, GST_TIME_ARGS(ts_offset));
1517 wfd_sink->video_buffer_count = 0;
1518 wfd_sink->video_accumulated_gap = 0LL;
1519 wfd_sink->audio_buffer_count = 0;
1520 wfd_sink->audio_accumulated_gap = 0LL;
1521 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1524 wfd_sink_debug("first update last buffer timestamp :%" GST_TIME_FORMAT,
1525 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
1526 wfd_sink->last_buffer_timestamp = GST_BUFFER_TIMESTAMP(buffer);
1529 return GST_PAD_PROBE_OK;
1534 __mm_wfd_sink_demux_pad_added(GstElement *ele, GstPad *pad, gpointer data)
1536 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1537 gchar *name = gst_pad_get_name(pad);
1538 GstElement *pipeline = NULL;
1539 GstElement *decodebin = NULL;
1540 GstElement *sinkbin = NULL;
1541 GstPad *sinkpad = NULL;
1542 GstPad *srcpad = NULL;
1544 wfd_sink_debug_fenter();
1546 wfd_sink_return_if_fail(wfd_sink &&
1547 wfd_sink->pipeline &&
1548 wfd_sink->pipeline->mainbin &&
1549 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
1551 pipeline = wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst;
1553 /* take decodebin/sinkbin */
1554 if (name[0] == 'v') {
1555 wfd_sink_debug("=========== >>>>>>>>>> Received VIDEO pad...");
1557 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL);
1559 gst_pad_add_probe(pad,
1560 GST_PAD_PROBE_TYPE_BUFFER,
1561 _mm_wfd_sink_check_running_time,
1565 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_video_pipeline(wfd_sink)) {
1566 wfd_sink_error("failed to prepare video pipeline....");
1570 if (wfd_sink->pipeline->v_decodebin && wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst)
1571 decodebin = wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst;
1572 if (wfd_sink->pipeline->v_sinkbin && wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst)
1573 sinkbin = wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst;
1574 } else if (name[0] == 'a') {
1575 wfd_sink_debug("=========== >>>>>>>>>> Received AUDIO pad...");
1577 MMWFDSINK_PAD_PROBE(wfd_sink, pad, NULL, NULL);
1579 gst_pad_add_probe(pad,
1580 GST_PAD_PROBE_TYPE_BUFFER,
1581 _mm_wfd_sink_check_running_time,
1585 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audio_pipeline(wfd_sink)) {
1586 wfd_sink_error("failed to prepare audio pipeline....");
1590 if (wfd_sink->pipeline->a_decodebin && wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst)
1591 decodebin = wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst;
1592 if (wfd_sink->pipeline->a_sinkbin && wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst)
1593 sinkbin = wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst;
1595 wfd_sink_error("unexceptable pad is added!!!");
1599 srcpad = gst_object_ref(pad);
1601 /* add decodebin and link */
1603 if (!gst_bin_add(GST_BIN(pipeline), decodebin)) {
1604 wfd_sink_error("failed to add %s to pipeline",
1605 GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1609 sinkpad = gst_element_get_static_pad(decodebin, "sink");
1611 wfd_sink_error("failed to get sink pad from %s",
1612 GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1616 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1617 wfd_sink_error("failed to link %s and %s",
1618 GST_STR_NULL(GST_PAD_NAME(srcpad)),
1619 GST_STR_NULL(GST_PAD_NAME(sinkpad)));
1622 gst_object_unref(GST_OBJECT(srcpad));
1624 gst_object_unref(GST_OBJECT(sinkpad));
1627 srcpad = gst_element_get_static_pad(decodebin, "src");
1629 wfd_sink_error("failed to get src pad from %s",
1630 GST_STR_NULL(GST_ELEMENT_NAME(decodebin)));
1634 wfd_sink_warning("going on without decodebin...");
1637 /* add sinkbin and link */
1639 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1640 wfd_sink_error("failed to add %s to pipeline",
1641 GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1645 sinkpad = gst_element_get_static_pad(sinkbin, "sink");
1647 wfd_sink_error("failed to get sink pad from %s",
1648 GST_STR_NULL(GST_ELEMENT_NAME(sinkbin)));
1652 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
1653 wfd_sink_error("failed to link %s and %s",
1654 GST_STR_NULL(GST_PAD_NAME(srcpad)),
1655 GST_STR_NULL(GST_PAD_NAME(sinkpad)));
1658 gst_object_unref(GST_OBJECT(srcpad));
1660 gst_object_unref(GST_OBJECT(sinkpad));
1663 wfd_sink_error("there is no sinkbin...");
1670 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(decodebin))) {
1671 wfd_sink_error("failed to sync %s state with parent",
1672 GST_STR_NULL(GST_PAD_NAME(decodebin)));
1678 if (!gst_element_sync_state_with_parent(GST_ELEMENT_CAST(sinkbin))) {
1679 wfd_sink_error("failed to sync %s state with parent",
1680 GST_STR_NULL(GST_PAD_NAME(sinkbin)));
1685 if (name[0] == 'v') {
1686 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "video-pad-added-pipeline");
1687 } else if (name[0] == 'a') {
1688 MMWFDSINK_GENERATE_DOT_IF_ENABLED(wfd_sink, "audio-pad-added-pipeline");
1691 MMWFDSINK_FREEIF(name);
1693 wfd_sink_debug_fleave();
1699 MMWFDSINK_FREEIF(name);
1702 gst_object_unref(GST_OBJECT(srcpad));
1706 gst_object_unref(GST_OBJECT(sinkpad));
1709 /* need to notify to app */
1710 MMWFDSINK_POST_MESSAGE(wfd_sink,
1711 MM_ERROR_WFD_INTERNAL,
1712 MMWFDSINK_CURRENT_STATE(wfd_sink));
1718 __mm_wfd_sink_change_av_format(GstElement *wfdrtspsrc, gpointer *need_to_flush, gpointer data)
1720 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1722 wfd_sink_debug_fenter();
1724 wfd_sink_return_if_fail(wfd_sink);
1725 wfd_sink_return_if_fail(need_to_flush);
1727 if (MMWFDSINK_CURRENT_STATE(wfd_sink) == MM_WFD_SINK_STATE_PLAYING) {
1728 wfd_sink_debug("need to flush pipeline");
1729 *need_to_flush = (gpointer) TRUE;
1731 wfd_sink_debug("don't need to flush pipeline");
1732 *need_to_flush = (gpointer) FALSE;
1736 wfd_sink_debug_fleave();
1741 __mm_wfd_sink_update_stream_info(GstElement *wfdrtspsrc, GstStructure *str, gpointer data)
1743 mm_wfd_sink_t *wfd_sink = (mm_wfd_sink_t *)data;
1744 MMWFDSinkStreamInfo *stream_info = NULL;
1745 gint is_valid_audio_format = FALSE;
1746 gint is_valid_video_format = FALSE;
1747 gint audio_codec = MM_WFD_SINK_AUDIO_CODEC_NONE;
1748 gint video_codec = MM_WFD_SINK_VIDEO_CODEC_NONE;
1749 gchar *audio_format;
1750 gchar *video_format;
1752 wfd_sink_debug_fenter();
1754 wfd_sink_return_if_fail(str && GST_IS_STRUCTURE(str));
1755 wfd_sink_return_if_fail(wfd_sink);
1757 stream_info = &wfd_sink->stream_info;
1759 audio_codec = wfd_sink->stream_info.audio_stream_info.codec;
1760 video_codec = wfd_sink->stream_info.video_stream_info.codec;
1762 if (gst_structure_has_field(str, "audio_format")) {
1763 is_valid_audio_format = TRUE;
1764 audio_format = g_strdup(gst_structure_get_string(str, "audio_format"));
1765 if (g_strrstr(audio_format, "AAC"))
1766 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AAC;
1767 else if (g_strrstr(audio_format, "AC3"))
1768 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_AC3;
1769 else if (g_strrstr(audio_format, "LPCM"))
1770 stream_info->audio_stream_info.codec = MM_WFD_SINK_AUDIO_CODEC_LPCM;
1772 wfd_sink_error("invalid audio format(%s)...", audio_format);
1773 is_valid_audio_format = FALSE;
1776 if (is_valid_audio_format == TRUE) {
1777 if (gst_structure_has_field(str, "audio_rate"))
1778 gst_structure_get_int(str, "audio_rate", &stream_info->audio_stream_info.sample_rate);
1779 if (gst_structure_has_field(str, "audio_channels"))
1780 gst_structure_get_int(str, "audio_channels", &stream_info->audio_stream_info.channels);
1781 if (gst_structure_has_field(str, "audio_bitwidth"))
1782 gst_structure_get_int(str, "audio_bitwidth", &stream_info->audio_stream_info.bitwidth);
1784 if (audio_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
1785 if (audio_codec != stream_info->audio_stream_info.codec) {
1786 wfd_sink_debug("audio codec is changed...need to change audio decodebin");
1789 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_A_PIPELINE);
1792 wfd_sink_debug("audio_format : %s \n \t rate : %d \n \t channels : %d \n \t bitwidth : %d \n \t",
1794 stream_info->audio_stream_info.sample_rate,
1795 stream_info->audio_stream_info.channels,
1796 stream_info->audio_stream_info.bitwidth);
1800 if (gst_structure_has_field(str, "video_format")) {
1801 is_valid_video_format = TRUE;
1802 video_format = g_strdup(gst_structure_get_string(str, "video_format"));
1803 if (!g_strrstr(video_format, "H264")) {
1804 wfd_sink_error("invalid video format(%s)...", video_format);
1805 is_valid_video_format = FALSE;
1808 if (is_valid_video_format == TRUE) {
1809 stream_info->video_stream_info.codec = MM_WFD_SINK_VIDEO_CODEC_H264;
1811 if (gst_structure_has_field(str, "video_width"))
1812 gst_structure_get_int(str, "video_width", &stream_info->video_stream_info.width);
1813 if (gst_structure_has_field(str, "video_height"))
1814 gst_structure_get_int(str, "video_height", &stream_info->video_stream_info.height);
1815 if (gst_structure_has_field(str, "video_framerate"))
1816 gst_structure_get_int(str, "video_framerate", &stream_info->video_stream_info.frame_rate);
1818 if (video_codec != MM_WFD_SINK_AUDIO_CODEC_NONE) {
1819 if (video_codec != stream_info->video_stream_info.codec) {
1820 wfd_sink_debug("video codec is changed...need to change video decodebin");
1823 WFD_SINK_MANAGER_APPEND_CMD(wfd_sink, WFD_SINK_MANAGER_CMD_PREPARE_V_PIPELINE);
1826 wfd_sink_debug("video_format : %s \n \t width : %d \n \t height : %d \n \t frame_rate : %d \n \t",
1828 stream_info->video_stream_info.width,
1829 stream_info->video_stream_info.height,
1830 stream_info->video_stream_info.frame_rate);
1834 WFD_SINK_MANAGER_SIGNAL_CMD(wfd_sink);
1836 wfd_sink_debug_fleave();
1839 static int __mm_wfd_sink_prepare_wfdrtspsrc(mm_wfd_sink_t *wfd_sink, GstElement *wfdrtspsrc)
1841 GstStructure *audio_param = NULL;
1842 GstStructure *video_param = NULL;
1843 GstStructure *hdcp_param = NULL;
1844 gint hdcp_version = 0;
1846 guint CEA_resolution = 0;
1847 guint VESA_resolution = 0;
1848 guint HH_resolution = 0;
1850 wfd_sink_debug_fenter();
1852 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1853 wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1854 wfd_sink_return_val_if_fail(wfdrtspsrc, MM_ERROR_WFD_NOT_INITIALIZED);
1856 g_object_set(G_OBJECT(wfdrtspsrc), "debug", wfd_sink->ini.set_debug_property, NULL);
1857 g_object_set(G_OBJECT(wfdrtspsrc), "latency", wfd_sink->ini.jitter_buffer_latency, NULL);
1858 g_object_set(G_OBJECT(wfdrtspsrc), "do-request", wfd_sink->ini.enable_retransmission, NULL);
1859 g_object_set(G_OBJECT(wfdrtspsrc), "enable-pad-probe", wfd_sink->ini.enable_wfdrtspsrc_pad_probe, NULL);
1860 g_object_set(G_OBJECT(wfdrtspsrc), "udp-buffer-size", 2097152, NULL);
1862 audio_param = gst_structure_new("audio_param",
1863 "audio_codec", G_TYPE_UINT, wfd_sink->ini.audio_codec,
1864 "audio_latency", G_TYPE_UINT, wfd_sink->ini.audio_latency,
1865 "audio_channels", G_TYPE_UINT, wfd_sink->ini.audio_channel,
1866 "audio_sampling_frequency", G_TYPE_UINT, wfd_sink->ini.audio_sampling_frequency,
1869 CEA_resolution = wfd_sink->ini.video_cea_support;
1870 VESA_resolution = wfd_sink->ini.video_vesa_support;
1871 HH_resolution = wfd_sink->ini.video_hh_support;
1873 __mm_wfd_sink_prepare_video_resolution(wfd_sink->supportive_resolution,
1874 &CEA_resolution, &VESA_resolution, &HH_resolution);
1876 wfd_sink_debug("set video resolution CEA[%x] VESA[%x] HH[%x]", CEA_resolution, VESA_resolution, HH_resolution);
1878 video_param = gst_structure_new("video_param",
1879 "video_codec", G_TYPE_UINT, wfd_sink->ini.video_codec,
1880 "video_native_resolution", G_TYPE_UINT, wfd_sink->ini.video_native_resolution,
1881 "video_cea_support", G_TYPE_UINT, CEA_resolution,
1882 "video_vesa_support", G_TYPE_UINT, VESA_resolution,
1883 "video_hh_support", G_TYPE_UINT, HH_resolution,
1884 "video_profile", G_TYPE_UINT, wfd_sink->ini.video_profile,
1885 "video_level", G_TYPE_UINT, wfd_sink->ini.video_level,
1886 "video_latency", G_TYPE_UINT, wfd_sink->ini.video_latency,
1887 "video_vertical_resolution", G_TYPE_INT, wfd_sink->ini.video_vertical_resolution,
1888 "video_horizontal_resolution", G_TYPE_INT, wfd_sink->ini.video_horizontal_resolution,
1889 "video_minimum_slicing", G_TYPE_INT, wfd_sink->ini.video_minimum_slicing,
1890 "video_slice_enc_param", G_TYPE_INT, wfd_sink->ini.video_slice_enc_param,
1891 "video_framerate_control_support", G_TYPE_INT, wfd_sink->ini.video_framerate_control_support,
1894 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_version", &hdcp_version);
1895 mm_attrs_get_int_by_name(wfd_sink->attrs, "hdcp_port", &hdcp_port);
1896 wfd_sink_debug("set hdcp version %d with %d port", hdcp_version, hdcp_port);
1898 hdcp_param = gst_structure_new("hdcp_param",
1899 "hdcp_version", G_TYPE_INT, hdcp_version,
1900 "hdcp_port_no", G_TYPE_INT, hdcp_port,
1903 g_object_set(G_OBJECT(wfdrtspsrc), "audio-param", audio_param, NULL);
1904 g_object_set(G_OBJECT(wfdrtspsrc), "video-param", video_param, NULL);
1905 g_object_set(G_OBJECT(wfdrtspsrc), "hdcp-param", hdcp_param, NULL);
1907 g_signal_connect(wfdrtspsrc, "update-media-info",
1908 G_CALLBACK(__mm_wfd_sink_update_stream_info), wfd_sink);
1910 g_signal_connect(wfdrtspsrc, "change-av-format",
1911 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",
1926 G_CALLBACK(__mm_wfd_sink_demux_pad_added), wfd_sink);
1928 wfd_sink_debug_fleave();
1930 return MM_ERROR_NONE;
1933 static void __mm_wfd_sink_queue_overrun(GstElement *element, gpointer u_data)
1935 wfd_sink_debug_fenter();
1937 return_if_fail(element);
1939 wfd_sink_warning("%s is overrun",
1940 GST_STR_NULL(GST_ELEMENT_NAME(element)));
1942 wfd_sink_debug_fleave();
1947 static void __mm_wfd_sink_prepare_queue(mm_wfd_sink_t *wfd_sink, GstElement *queue)
1949 wfd_sink_debug_fenter();
1951 wfd_sink_return_if_fail(wfd_sink);
1952 wfd_sink_return_if_fail(queue);
1954 /* set maximum buffer size of queue as 3sec */
1955 g_object_set(G_OBJECT(queue), "max-size-bytes", 0, NULL);
1956 g_object_set(G_OBJECT(queue), "max-size-buffers", 0, NULL);
1957 g_object_set(G_OBJECT(queue), "max-size-time", (guint64)3000000000ULL, NULL);
1958 g_signal_connect(queue, "overrun",
1959 G_CALLBACK(__mm_wfd_sink_queue_overrun), wfd_sink);
1961 wfd_sink_debug_fleave();
1967 static int __mm_wfd_sink_create_pipeline(mm_wfd_sink_t *wfd_sink)
1969 MMWFDSinkGstElement *mainbin = NULL;
1970 GList *element_bucket = NULL;
1974 wfd_sink_debug_fenter();
1976 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
1977 wfd_sink_return_val_if_fail(wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
1979 /* Create pipeline */
1980 wfd_sink->pipeline = (MMWFDSinkGstPipelineInfo *) g_malloc0(sizeof(MMWFDSinkGstPipelineInfo));
1981 if (wfd_sink->pipeline == NULL)
1984 memset(wfd_sink->pipeline, 0, sizeof(MMWFDSinkGstPipelineInfo));
1986 /* create mainbin */
1987 mainbin = (MMWFDSinkGstElement *) g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1988 if (mainbin == NULL)
1991 memset(mainbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_M_NUM);
1993 /* create pipeline */
1994 mainbin[WFD_SINK_M_PIPE].id = WFD_SINK_M_PIPE;
1995 mainbin[WFD_SINK_M_PIPE].gst = gst_pipeline_new("wfdsink");
1996 if (!mainbin[WFD_SINK_M_PIPE].gst) {
1997 wfd_sink_error("failed to create pipeline");
2001 /* create wfdrtspsrc */
2002 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_SRC, "wfdrtspsrc", "wfdsink_source", TRUE);
2003 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_SRC].gst, "src");
2004 if (mainbin[WFD_SINK_M_SRC].gst) {
2005 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_wfdrtspsrc(wfd_sink, mainbin[WFD_SINK_M_SRC].gst)) {
2006 wfd_sink_error("failed to prepare wfdrtspsrc...");
2011 /* create rtpmp2tdepay */
2012 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEPAY, "rtpmp2tdepay", "wfdsink_depay", TRUE);
2013 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2014 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEPAY].gst, "sink");
2016 MMWFDSINK_TS_DATA_DUMP(wfd_sink, mainbin[WFD_SINK_M_DEPAY].gst, "src");
2018 /* create tsdemuxer*/
2019 MMWFDSINK_CREATE_ELEMENT(mainbin, WFD_SINK_M_DEMUX, wfd_sink->ini.name_of_tsdemux, "wfdsink_demux", TRUE);
2020 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, mainbin[WFD_SINK_M_DEMUX].gst, "sink");
2021 if (mainbin[WFD_SINK_M_DEMUX].gst) {
2022 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_demux(wfd_sink, mainbin[WFD_SINK_M_DEMUX].gst)) {
2023 wfd_sink_error("failed to prepare demux...");
2028 /* adding created elements to pipeline */
2029 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(mainbin[WFD_SINK_M_PIPE].gst), element_bucket, FALSE)) {
2030 wfd_sink_error("failed to add elements");
2034 /* linking elements in the bucket by added order. */
2035 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2036 wfd_sink_error("failed to link elements");
2040 /* connect bus callback */
2041 bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[WFD_SINK_M_PIPE].gst));
2043 wfd_sink_error("cannot get bus from pipeline.");
2047 /* add bus message callback*/
2048 gst_bus_add_watch(bus, (GstBusFunc)_mm_wfd_sink_msg_callback, wfd_sink);
2050 /* set sync handler to get tag synchronously */
2051 gst_bus_set_sync_handler(bus, _mm_wfd_bus_sync_callback, wfd_sink, NULL);
2053 g_list_free(element_bucket);
2054 gst_object_unref(GST_OBJECT(bus));
2056 /* now we have completed mainbin. take it */
2057 wfd_sink->pipeline->mainbin = mainbin;
2059 wfd_sink_debug_fleave();
2061 return MM_ERROR_NONE;
2065 wfd_sink_error("ERROR : releasing pipeline");
2068 g_list_free(element_bucket);
2069 element_bucket = NULL;
2073 gst_object_unref(GST_OBJECT(bus));
2076 /* release element which are not added to bin */
2077 for (i = 1; i < WFD_SINK_M_NUM; i++) { /* NOTE : skip pipeline */
2078 if (mainbin != NULL && mainbin[i].gst) {
2079 GstObject *parent = NULL;
2080 parent = gst_element_get_parent(mainbin[i].gst);
2083 gst_object_unref(GST_OBJECT(mainbin[i].gst));
2084 mainbin[i].gst = NULL;
2086 gst_object_unref(GST_OBJECT(parent));
2091 /* release mainbin with it's childs */
2092 if (mainbin != NULL && mainbin[WFD_SINK_M_PIPE].gst)
2093 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
2095 MMWFDSINK_FREEIF(mainbin);
2097 MMWFDSINK_FREEIF(wfd_sink->pipeline);
2099 return MM_ERROR_WFD_INTERNAL;
2102 int __mm_wfd_sink_link_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2104 MMWFDSinkGstElement *a_decodebin = NULL;
2105 MMWFDSinkGstElement *first_element = NULL;
2106 MMWFDSinkGstElement *last_element = NULL;
2107 GList *element_bucket = NULL;
2108 GstPad *sinkpad = NULL;
2109 GstPad *srcpad = NULL;
2110 GstPad *ghostpad = 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_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data;
2197 if (!first_element) {
2198 wfd_sink_error("failed to get first element of the audio decodebin");
2202 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2204 wfd_sink_error("failed to get sink pad from element(%s)",
2205 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2209 ghostpad = gst_ghost_pad_new("sink", sinkpad);
2211 wfd_sink_error("failed to create ghostpad of audio decodebin");
2215 if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
2216 wfd_sink_error("failed to add ghostpad to audio decodebin");
2219 gst_object_unref(GST_OBJECT(sinkpad));
2223 /* get last element's src for creating ghostpad */
2224 last_element = (MMWFDSinkGstElement *)g_list_last(element_bucket)->data;
2225 if (!last_element) {
2226 wfd_sink_error("failed to get last element of the audio decodebin");
2230 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2232 wfd_sink_error("failed to get src pad from element(%s)",
2233 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
2237 ghostpad = gst_ghost_pad_new("src", srcpad);
2239 wfd_sink_error("failed to create ghostpad of audio decodebin");
2243 if (FALSE == gst_element_add_pad(a_decodebin[WFD_SINK_A_D_BIN].gst, ghostpad)) {
2244 wfd_sink_error("failed to add ghostpad to audio decodebin");
2247 gst_object_unref(GST_OBJECT(srcpad));
2250 g_list_free(element_bucket);
2253 wfd_sink->audio_decodebin_is_linked = TRUE;
2255 wfd_sink_debug_fleave();
2257 return MM_ERROR_NONE;
2262 gst_object_unref(GST_OBJECT(srcpad));
2266 gst_object_unref(GST_OBJECT(sinkpad));
2269 g_list_free(element_bucket);
2271 return MM_ERROR_WFD_INTERNAL;
2274 static int __mm_wfd_sink_prepare_audiosink(mm_wfd_sink_t *wfd_sink, GstElement *audio_sink)
2276 wfd_sink_debug_fenter();
2278 /* check audiosink is created */
2279 wfd_sink_return_val_if_fail(audio_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2280 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2282 g_object_set(G_OBJECT(audio_sink), "provide-clock", FALSE, NULL);
2283 g_object_set(G_OBJECT(audio_sink), "buffer-time", 100000LL, NULL);
2284 g_object_set(G_OBJECT(audio_sink), "slave-method", 2, NULL);
2285 g_object_set(G_OBJECT(audio_sink), "async", wfd_sink->ini.audio_sink_async, NULL);
2286 g_object_set(G_OBJECT(audio_sink), "ts-offset", (gint64)wfd_sink->ini.sink_ts_offset, NULL);
2288 wfd_sink_debug_fleave();
2290 return MM_ERROR_NONE;
2293 static int __mm_wfd_sink_destroy_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2295 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2296 MMWFDSinkGstElement *a_decodebin = NULL;
2297 GstObject *parent = NULL;
2300 wfd_sink_debug_fenter();
2302 wfd_sink_return_val_if_fail(wfd_sink,
2303 MM_ERROR_WFD_NOT_INITIALIZED);
2305 if (wfd_sink->pipeline &&
2306 wfd_sink->pipeline->a_decodebin &&
2307 wfd_sink->pipeline->a_decodebin[WFD_SINK_A_D_BIN].gst) {
2308 a_decodebin = wfd_sink->pipeline->a_decodebin;
2310 wfd_sink_debug("audio decodebin is not created, nothing to destroy");
2311 return MM_ERROR_NONE;
2314 parent = gst_element_get_parent(a_decodebin[WFD_SINK_A_D_BIN].gst);
2316 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
2318 if (GST_STATE(a_decodebin[WFD_SINK_A_D_BIN].gst) >= GST_STATE_READY) {
2319 wfd_sink_debug("try to change state of audio decodebin to NULL");
2320 ret = gst_element_set_state(a_decodebin[WFD_SINK_A_D_BIN].gst, GST_STATE_NULL);
2321 if (ret != GST_STATE_CHANGE_SUCCESS) {
2322 wfd_sink_error("failed to change state of audio decodebin to NULL");
2323 return MM_ERROR_WFD_INTERNAL;
2327 /* release element which are not added to bin */
2328 for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */
2329 if (a_decodebin[i].gst) {
2330 parent = gst_element_get_parent(a_decodebin[i].gst);
2332 wfd_sink_debug("unref %s(current ref %d)",
2333 GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
2334 ((GObject *) a_decodebin[i].gst)->ref_count);
2335 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
2336 a_decodebin[i].gst = NULL;
2338 wfd_sink_debug("unref %s(current ref %d)",
2339 GST_STR_NULL(GST_ELEMENT_NAME(a_decodebin[i].gst)),
2340 ((GObject *) a_decodebin[i].gst)->ref_count);
2341 gst_object_unref(GST_OBJECT(parent));
2346 /* release audio decodebin with it's childs */
2347 if (a_decodebin[WFD_SINK_A_D_BIN].gst)
2348 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
2351 wfd_sink_debug("audio decodebin has parent(%s), unref it ",
2352 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2354 gst_object_unref(GST_OBJECT(parent));
2357 wfd_sink->audio_decodebin_is_linked = FALSE;
2359 MMWFDSINK_FREEIF(wfd_sink->pipeline->a_decodebin);
2361 wfd_sink_debug_fleave();
2363 return MM_ERROR_NONE;
2366 static int __mm_wfd_sink_create_audio_decodebin(mm_wfd_sink_t *wfd_sink)
2368 MMWFDSinkGstElement *a_decodebin = NULL;
2369 gint audio_codec = WFD_AUDIO_UNKNOWN;
2370 GList *element_bucket = NULL;
2371 gboolean link = TRUE;
2374 wfd_sink_debug_fenter();
2376 wfd_sink_return_val_if_fail(wfd_sink &&
2378 MM_ERROR_WFD_NOT_INITIALIZED);
2380 /* check audio decodebin could be linked now */
2381 switch (wfd_sink->stream_info.audio_stream_info.codec) {
2382 case MM_WFD_SINK_AUDIO_CODEC_AAC:
2383 audio_codec = WFD_AUDIO_AAC;
2386 case MM_WFD_SINK_AUDIO_CODEC_AC3:
2387 audio_codec = WFD_AUDIO_AC3;
2390 case MM_WFD_SINK_AUDIO_CODEC_LPCM:
2391 audio_codec = WFD_AUDIO_LPCM;
2394 case MM_WFD_SINK_AUDIO_CODEC_NONE:
2396 wfd_sink_debug("audio decodebin could NOT be linked now, just create");
2397 audio_codec = wfd_sink->ini.audio_codec;
2403 a_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
2405 wfd_sink_error("failed to allocate memory for audio decodebin");
2406 return MM_ERROR_WFD_NO_FREE_SPACE;
2409 memset(a_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_D_NUM);
2411 /* create audio decodebin */
2412 a_decodebin[WFD_SINK_A_D_BIN].id = WFD_SINK_A_D_BIN;
2413 a_decodebin[WFD_SINK_A_D_BIN].gst = gst_bin_new("audio_deocebin");
2414 if (!a_decodebin[WFD_SINK_A_D_BIN].gst) {
2415 wfd_sink_error("failed to create audio decodebin");
2420 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_QUEUE, "queue", "audio_queue", FALSE);
2421 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_QUEUE].gst, "sink");
2422 if (a_decodebin[WFD_SINK_A_D_QUEUE].gst)
2423 __mm_wfd_sink_prepare_queue(wfd_sink, a_decodebin[WFD_SINK_A_D_QUEUE].gst);
2426 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_HDCP, wfd_sink->ini.name_of_audio_hdcp, "audio_hdcp", FALSE);
2427 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_HDCP].gst, "sink");
2430 audio_codec = wfd_sink->ini.audio_codec;
2431 if (audio_codec & WFD_AUDIO_LPCM) {
2432 /* create LPCM converter */
2433 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_CONVERTER, wfd_sink->ini.name_of_lpcm_converter, "audio_lpcm_convert", FALSE);
2434 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "sink");
2435 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_CONVERTER].gst, "src");
2437 /* create LPCM filter */
2438 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_LPCM_FILTER, wfd_sink->ini.name_of_lpcm_filter, "audio_lpcm_filter", FALSE);
2439 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "sink");
2440 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_LPCM_FILTER].gst, "src");
2443 if (audio_codec & WFD_AUDIO_AAC) {
2444 /* create AAC parse */
2445 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_PARSE, wfd_sink->ini.name_of_aac_parser, "audio_aac_parser", FALSE);
2446 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "sink");
2447 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_PARSE].gst, "src");
2449 /* create AAC decoder */
2450 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AAC_DEC, wfd_sink->ini.name_of_aac_decoder, "audio_aac_dec", FALSE);
2451 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "sink");
2452 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AAC_DEC].gst, "src");
2455 if (audio_codec & WFD_AUDIO_AC3) {
2456 /* create AC3 parser */
2457 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_PARSE, wfd_sink->ini.name_of_ac3_parser, "audio_ac3_parser", FALSE);
2458 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "sink");
2459 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_PARSE].gst, "src");
2461 /* create AC3 decoder */
2462 MMWFDSINK_CREATE_ELEMENT(a_decodebin, WFD_SINK_A_D_AC3_DEC, wfd_sink->ini.name_of_ac3_decoder, "audio_ac3_dec", FALSE);
2463 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "sink");
2464 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_decodebin[WFD_SINK_A_D_AC3_DEC].gst, "src");
2467 g_list_free(element_bucket);
2470 wfd_sink->pipeline->a_decodebin = a_decodebin;
2472 /* link audio decodebin if audio codec is fixed */
2474 if (MM_ERROR_NONE != __mm_wfd_sink_link_audio_decodebin(wfd_sink)) {
2475 wfd_sink_error("failed to link audio decodebin, destroy audio decodebin");
2476 __mm_wfd_sink_destroy_audio_decodebin(wfd_sink);
2477 return MM_ERROR_WFD_INTERNAL;
2481 wfd_sink_debug_fleave();
2483 return MM_ERROR_NONE;
2486 wfd_sink_error("failed to create audio decodebin, release all");
2488 g_list_free(element_bucket);
2490 /* release element which are not added to bin */
2491 for (i = 1; i < WFD_SINK_A_D_NUM; i++) { /* NOTE : skip bin */
2492 if (a_decodebin != NULL && a_decodebin[i].gst) {
2493 GstObject *parent = NULL;
2494 parent = gst_element_get_parent(a_decodebin[i].gst);
2497 gst_object_unref(GST_OBJECT(a_decodebin[i].gst));
2498 a_decodebin[i].gst = NULL;
2500 gst_object_unref(GST_OBJECT(parent));
2505 /* release audioo decodebin with it's childs */
2506 if (a_decodebin != NULL && a_decodebin[WFD_SINK_A_D_BIN].gst)
2507 gst_object_unref(GST_OBJECT(a_decodebin[WFD_SINK_A_D_BIN].gst));
2509 MMWFDSINK_FREEIF(a_decodebin);
2511 return MM_ERROR_WFD_INTERNAL;
2514 static int __mm_wfd_sink_destroy_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
2516 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2517 MMWFDSinkGstElement *a_sinkbin = NULL;
2518 GstObject *parent = NULL;
2521 wfd_sink_debug_fenter();
2523 wfd_sink_return_val_if_fail(wfd_sink,
2524 MM_ERROR_WFD_NOT_INITIALIZED);
2526 if (wfd_sink->pipeline &&
2527 wfd_sink->pipeline->a_sinkbin &&
2528 wfd_sink->pipeline->a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2529 a_sinkbin = wfd_sink->pipeline->a_sinkbin;
2531 wfd_sink_debug("audio sinkbin is not created, nothing to destroy");
2532 return MM_ERROR_NONE;
2536 parent = gst_element_get_parent(a_sinkbin[WFD_SINK_A_S_BIN].gst);
2538 wfd_sink_debug("audio decodebin has no parent.. need to relase by itself");
2540 if (GST_STATE(a_sinkbin[WFD_SINK_A_S_BIN].gst) >= GST_STATE_READY) {
2541 wfd_sink_debug("try to change state of audio decodebin to NULL");
2542 ret = gst_element_set_state(a_sinkbin[WFD_SINK_A_S_BIN].gst, GST_STATE_NULL);
2543 if (ret != GST_STATE_CHANGE_SUCCESS) {
2544 wfd_sink_error("failed to change state of audio decodebin to NULL");
2545 return MM_ERROR_WFD_INTERNAL;
2549 /* release element which are not added to bin */
2550 for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */
2551 if (a_sinkbin[i].gst) {
2552 parent = gst_element_get_parent(a_sinkbin[i].gst);
2554 wfd_sink_debug("unref %s(current ref %d)",
2555 GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
2556 ((GObject *) a_sinkbin[i].gst)->ref_count);
2557 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
2558 a_sinkbin[i].gst = NULL;
2560 wfd_sink_debug("unref %s(current ref %d)",
2561 GST_STR_NULL(GST_ELEMENT_NAME(a_sinkbin[i].gst)),
2562 ((GObject *) a_sinkbin[i].gst)->ref_count);
2563 gst_object_unref(GST_OBJECT(parent));
2568 /* release audio decodebin with it's childs */
2569 if (a_sinkbin[WFD_SINK_A_S_BIN].gst)
2570 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
2573 wfd_sink_debug("audio sinkbin has parent(%s), unref it ",
2574 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
2576 gst_object_unref(GST_OBJECT(parent));
2579 MMWFDSINK_FREEIF(wfd_sink->pipeline->a_sinkbin);
2581 wfd_sink_debug_fleave();
2583 return MM_ERROR_NONE;
2586 static int __mm_wfd_sink_create_audio_sinkbin(mm_wfd_sink_t *wfd_sink)
2588 MMWFDSinkGstElement *a_sinkbin = NULL;
2589 MMWFDSinkGstElement *first_element = NULL;
2590 GList *element_bucket = NULL;
2591 GstPad *ghostpad = NULL;
2595 wfd_sink_debug_fenter();
2597 wfd_sink_return_val_if_fail(wfd_sink &&
2599 MM_ERROR_WFD_NOT_INITIALIZED);
2602 a_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
2604 wfd_sink_error("failed to allocate memory for audio sinkbin");
2605 return MM_ERROR_WFD_NO_FREE_SPACE;
2608 memset(a_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_A_S_NUM);
2610 /* create audio sinkbin */
2611 a_sinkbin[WFD_SINK_A_S_BIN].id = WFD_SINK_A_S_BIN;
2612 a_sinkbin[WFD_SINK_A_S_BIN].gst = gst_bin_new("audio_sinkbin");
2613 if (!a_sinkbin[WFD_SINK_A_S_BIN].gst) {
2614 wfd_sink_error("failed to create audio sinkbin");
2618 /* create resampler */
2619 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_RESAMPLER, wfd_sink->ini.name_of_audio_resampler, "audio_resampler", TRUE);
2620 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "sink");
2621 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_RESAMPLER].gst, "src");
2624 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_VOLUME, wfd_sink->ini.name_of_audio_volume, "audio_volume", TRUE);
2625 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "sink");
2626 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_VOLUME].gst, "src");
2629 MMWFDSINK_CREATE_ELEMENT(a_sinkbin, WFD_SINK_A_S_SINK, wfd_sink->ini.name_of_audio_sink, "audio_sink", TRUE);
2630 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, a_sinkbin[WFD_SINK_A_S_SINK].gst, "sink");
2631 if (a_sinkbin[WFD_SINK_A_S_SINK].gst) {
2632 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_audiosink(wfd_sink, a_sinkbin[WFD_SINK_A_S_SINK].gst)) {
2633 wfd_sink_error("failed to set audio sink property....");
2638 /* adding created elements to audio sinkbin */
2639 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(a_sinkbin[WFD_SINK_A_S_BIN].gst), element_bucket, FALSE)) {
2640 wfd_sink_error("failed to add elements to audio sinkbin");
2644 /* linking elements in the bucket by added order. */
2645 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2646 wfd_sink_error("failed to link elements fo the audio sinkbin");
2650 /* get first element's of the audio sinkbin */
2651 first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data;
2652 if (!first_element) {
2653 wfd_sink_error("failed to get first element of the audio sinkbin");
2657 /* get first element's sinkpad for creating ghostpad */
2658 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2660 wfd_sink_error("failed to get sink pad from element(%s)",
2661 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2665 ghostpad = gst_ghost_pad_new("sink", pad);
2667 wfd_sink_error("failed to create ghostpad of audio sinkbin");
2671 if (FALSE == gst_element_add_pad(a_sinkbin[WFD_SINK_A_S_BIN].gst, ghostpad)) {
2672 wfd_sink_error("failed to add ghostpad to audio sinkbin");
2675 gst_object_unref(GST_OBJECT(pad));
2677 g_list_free(element_bucket);
2680 wfd_sink->pipeline->a_sinkbin = a_sinkbin;
2682 wfd_sink_debug_fleave();
2684 return MM_ERROR_NONE;
2687 wfd_sink_error("failed to create audio sinkbin, releasing all");
2690 gst_object_unref(GST_OBJECT(pad));
2694 gst_object_unref(GST_OBJECT(ghostpad));
2698 g_list_free(element_bucket);
2699 element_bucket = NULL;
2701 /* release element which are not added to bin */
2702 for (i = 1; i < WFD_SINK_A_S_NUM; i++) { /* NOTE : skip bin */
2703 if (a_sinkbin != NULL && a_sinkbin[i].gst) {
2704 GstObject *parent = NULL;
2705 parent = gst_element_get_parent(a_sinkbin[i].gst);
2708 gst_object_unref(GST_OBJECT(a_sinkbin[i].gst));
2709 a_sinkbin[i].gst = NULL;
2711 gst_object_unref(GST_OBJECT(parent));
2716 /* release audio sinkbin with it's childs */
2717 if (a_sinkbin != NULL && a_sinkbin[WFD_SINK_A_S_BIN].gst)
2718 gst_object_unref(GST_OBJECT(a_sinkbin[WFD_SINK_A_S_BIN].gst));
2720 MMWFDSINK_FREEIF(a_sinkbin);
2722 return MM_ERROR_WFD_INTERNAL;
2725 int __mm_wfd_sink_link_video_decodebin(mm_wfd_sink_t *wfd_sink)
2727 MMWFDSinkGstElement *v_decodebin = NULL;
2728 MMWFDSinkGstElement *first_element = NULL;
2729 MMWFDSinkGstElement *last_element = NULL;
2730 GList *element_bucket = NULL;
2731 GstPad *sinkpad = NULL;
2732 GstPad *srcpad = NULL;
2733 GstPad *ghostpad = NULL;
2735 wfd_sink_debug_fenter();
2737 wfd_sink_return_val_if_fail(wfd_sink &&
2738 wfd_sink->pipeline &&
2739 wfd_sink->pipeline->v_decodebin &&
2740 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst,
2741 MM_ERROR_WFD_NOT_INITIALIZED);
2743 if (wfd_sink->video_decodebin_is_linked) {
2744 wfd_sink_debug("video decodebin is already linked... nothing to do");
2745 return MM_ERROR_NONE;
2748 /* take video decodebin */
2749 v_decodebin = wfd_sink->pipeline->v_decodebin;
2751 /* check video queue */
2752 if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
2753 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_QUEUE]);
2755 /* check video hdcp */
2756 if (v_decodebin[WFD_SINK_V_D_HDCP].gst)
2757 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_HDCP]);
2759 /* check video codec */
2760 switch (wfd_sink->stream_info.video_stream_info.codec) {
2761 case MM_WFD_SINK_VIDEO_CODEC_H264:
2762 if (v_decodebin[WFD_SINK_V_D_PARSE].gst)
2763 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_PARSE]);
2764 if (v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst) {
2765 GstCaps *caps = NULL;
2767 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_CAPSSETTER]);
2768 caps = gst_caps_new_simple("video/x-h264",
2769 "width", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.width,
2770 "height", G_TYPE_INT, wfd_sink->stream_info.video_stream_info.height,
2771 "framerate", GST_TYPE_FRACTION, wfd_sink->stream_info.video_stream_info.frame_rate, 1, NULL);
2772 g_object_set(G_OBJECT(v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst), "caps", caps, NULL);
2773 gst_object_unref(GST_OBJECT(caps));
2775 if (v_decodebin[WFD_SINK_V_D_DEC].gst)
2776 element_bucket = g_list_append(element_bucket, &v_decodebin[WFD_SINK_V_D_DEC]);
2780 wfd_sink_error("video codec is not decied yet. cannot link video decpdebin...");
2781 return MM_ERROR_WFD_INTERNAL;
2785 if (element_bucket == NULL) {
2786 wfd_sink_error("there are no elements to be linked in the video decodebin, destroy it");
2787 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
2788 wfd_sink_error("failed to destroy video decodebin");
2794 /* adding elements to video decodebin */
2795 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_decodebin[WFD_SINK_V_D_BIN].gst), element_bucket, FALSE)) {
2796 wfd_sink_error("failed to add elements to video decodebin");
2800 /* linking elements in the bucket by added order. */
2801 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
2802 wfd_sink_error("failed to link elements of the video decodebin");
2806 /* get first element's sinkpad for creating ghostpad */
2807 first_element = (MMWFDSinkGstElement *)g_list_first(element_bucket)->data;
2808 if (!first_element) {
2809 wfd_sink_error("failed to get first element of the video decodebin");
2813 sinkpad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
2815 wfd_sink_error("failed to get sink pad from element(%s)",
2816 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
2820 ghostpad = gst_ghost_pad_new("sink", sinkpad);
2822 wfd_sink_error("failed to create ghostpad of video decodebin");
2826 if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
2827 wfd_sink_error("failed to add ghostpad to video decodebin");
2830 gst_object_unref(GST_OBJECT(sinkpad));
2834 /* get last element's src for creating ghostpad */
2835 last_element = (MMWFDSinkGstElement *)g_list_last(element_bucket)->data;
2836 if (!last_element) {
2837 wfd_sink_error("failed to get last element of the video decodebin");
2841 srcpad = gst_element_get_static_pad(GST_ELEMENT(last_element->gst), "src");
2843 wfd_sink_error("failed to get src pad from element(%s)",
2844 GST_STR_NULL(GST_ELEMENT_NAME(last_element->gst)));
2848 ghostpad = gst_ghost_pad_new("src", srcpad);
2850 wfd_sink_error("failed to create ghostpad of video decodebin");
2854 if (FALSE == gst_element_add_pad(v_decodebin[WFD_SINK_V_D_BIN].gst, ghostpad)) {
2855 wfd_sink_error("failed to add ghostpad to video decodebin");
2858 gst_object_unref(GST_OBJECT(srcpad));
2861 g_list_free(element_bucket);
2864 wfd_sink->video_decodebin_is_linked = TRUE;
2866 wfd_sink_debug_fleave();
2868 return MM_ERROR_NONE;
2873 gst_object_unref(GST_OBJECT(srcpad));
2876 if (sinkpad != NULL)
2877 gst_object_unref(GST_OBJECT(sinkpad));
2880 g_list_free(element_bucket);
2882 return MM_ERROR_WFD_INTERNAL;
2885 static int __mm_wfd_sink_prepare_videodec(mm_wfd_sink_t *wfd_sink, GstElement *video_dec)
2887 wfd_sink_debug_fenter();
2889 /* check video decoder is created */
2890 wfd_sink_return_val_if_fail(video_dec, MM_ERROR_WFD_INVALID_ARGUMENT);
2891 wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2893 wfd_sink_debug_fleave();
2895 return MM_ERROR_NONE;
2898 static int __mm_wfd_sink_prepare_videosink(mm_wfd_sink_t *wfd_sink, GstElement *video_sink)
2900 gboolean visible = TRUE;
2901 gint surface_type = MM_DISPLAY_SURFACE_X;
2904 wfd_sink_debug_fenter();
2906 /* check videosink is created */
2907 wfd_sink_return_val_if_fail(video_sink, MM_ERROR_WFD_INVALID_ARGUMENT);
2908 wfd_sink_return_val_if_fail(wfd_sink && wfd_sink->attrs, MM_ERROR_WFD_NOT_INITIALIZED);
2910 /* update display surface */
2911 /* mm_attrs_get_int_by_name(wfd_sink->attrs, "display_surface_type", &surface_type); */
2912 wfd_sink_debug("check display surface type attribute: %d", surface_type);
2913 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_visible", &visible);
2914 wfd_sink_debug("check display visible attribute: %d", visible);
2916 /* configuring display */
2917 switch (surface_type) {
2918 case MM_DISPLAY_SURFACE_EVAS: {
2919 void *object = NULL;
2922 /* common case if using evas surface */
2923 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", &object);
2924 mm_attrs_get_int_by_name(wfd_sink->attrs, "display_evas_do_scaling", &scaling);
2926 wfd_sink_debug("set video param : evas-object %x", object);
2927 g_object_set(G_OBJECT(video_sink), "evas-object", object, NULL);
2929 wfd_sink_error("no evas object");
2930 return MM_ERROR_WFD_INTERNAL;
2935 case MM_DISPLAY_SURFACE_X: {
2939 mm_attrs_get_data_by_name(wfd_sink->attrs, "display_overlay", (void **)&object);
2942 wfd_sink_debug("xid = %lu", xid);
2943 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), xid);
2945 wfd_sink_warning("Handle is NULL. Set xid as 0.. but, it's not recommended.");
2946 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), 0);
2951 case MM_DISPLAY_SURFACE_NULL: {
2953 wfd_sink_error("Not Supported Surface.");
2954 return MM_ERROR_WFD_INTERNAL;
2958 wfd_sink_error("Not Supported Surface.(default case)");
2959 return MM_ERROR_WFD_INTERNAL;
2964 g_object_set(G_OBJECT(video_sink), "qos", FALSE, NULL);
2965 g_object_set(G_OBJECT(video_sink), "async", wfd_sink->ini.video_sink_async, NULL);
2966 g_object_set(G_OBJECT(video_sink), "max-lateness", (gint64)wfd_sink->ini.video_sink_max_lateness, NULL);
2967 g_object_set(G_OBJECT(video_sink), "visible", visible, NULL);
2968 g_object_set(G_OBJECT(video_sink), "ts-offset", (gint64)(wfd_sink->ini.sink_ts_offset), NULL);
2970 wfd_sink_debug_fleave();
2972 return MM_ERROR_NONE;
2975 static int __mm_wfd_sink_destroy_video_decodebin(mm_wfd_sink_t *wfd_sink)
2977 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2978 MMWFDSinkGstElement *v_decodebin = NULL;
2979 GstObject *parent = NULL;
2982 wfd_sink_debug_fenter();
2984 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
2986 if (wfd_sink->pipeline &&
2987 wfd_sink->pipeline->v_decodebin &&
2988 wfd_sink->pipeline->v_decodebin[WFD_SINK_V_D_BIN].gst) {
2989 v_decodebin = wfd_sink->pipeline->v_decodebin;
2991 wfd_sink_debug("video decodebin is not created, nothing to destroy");
2992 return MM_ERROR_NONE;
2996 parent = gst_element_get_parent(v_decodebin[WFD_SINK_V_D_BIN].gst);
2998 wfd_sink_debug("video decodebin has no parent.. need to relase by itself");
3000 if (GST_STATE(v_decodebin[WFD_SINK_V_D_BIN].gst) >= GST_STATE_READY) {
3001 wfd_sink_debug("try to change state of video decodebin to NULL");
3002 ret = gst_element_set_state(v_decodebin[WFD_SINK_V_D_BIN].gst, GST_STATE_NULL);
3003 if (ret != GST_STATE_CHANGE_SUCCESS) {
3004 wfd_sink_error("failed to change state of video decodebin to NULL");
3005 return MM_ERROR_WFD_INTERNAL;
3008 /* release element which are not added to bin */
3009 for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */
3010 if (v_decodebin[i].gst) {
3011 parent = gst_element_get_parent(v_decodebin[i].gst);
3013 wfd_sink_debug("unref %s(current ref %d)",
3014 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
3015 ((GObject *) v_decodebin[i].gst)->ref_count);
3016 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
3017 v_decodebin[i].gst = NULL;
3019 wfd_sink_debug("unref %s(current ref %d)",
3020 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[i].gst)),
3021 ((GObject *) v_decodebin[i].gst)->ref_count);
3022 gst_object_unref(GST_OBJECT(parent));
3026 /* release video decodebin with it's childs */
3027 if (v_decodebin[WFD_SINK_V_D_BIN].gst) {
3028 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
3029 wfd_sink_debug("unref %s(current ref %d)",
3030 GST_STR_NULL(GST_ELEMENT_NAME(v_decodebin[WFD_SINK_V_D_BIN].gst)),
3031 ((GObject *)v_decodebin[WFD_SINK_V_D_BIN].gst)->ref_count);
3034 wfd_sink_debug("video decodebin has parent(%s), unref it",
3035 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3037 gst_object_unref(GST_OBJECT(parent));
3040 wfd_sink->video_decodebin_is_linked = FALSE;
3042 MMWFDSINK_FREEIF(wfd_sink->pipeline->v_decodebin);
3044 wfd_sink_debug_fleave();
3046 return MM_ERROR_NONE;
3049 static int __mm_wfd_sink_create_video_decodebin(mm_wfd_sink_t *wfd_sink)
3051 MMWFDSinkGstElement *v_decodebin = NULL;
3052 guint video_codec = WFD_VIDEO_UNKNOWN;
3053 GList *element_bucket = NULL;
3054 gboolean link = TRUE;
3057 wfd_sink_debug_fenter();
3059 wfd_sink_return_val_if_fail(wfd_sink &&
3061 MM_ERROR_WFD_NOT_INITIALIZED);
3063 if (wfd_sink->pipeline->v_decodebin) {
3064 wfd_sink_debug("video decodebin is already created... nothing to do");
3065 return MM_ERROR_NONE;
3068 /* check audio decodebin could be linked now */
3069 switch (wfd_sink->stream_info.video_stream_info.codec) {
3070 case MM_WFD_SINK_VIDEO_CODEC_H264:
3071 video_codec = WFD_VIDEO_H264;
3074 case MM_WFD_SINK_VIDEO_CODEC_NONE:
3076 wfd_sink_debug("video decodebin could NOT be linked now, just create");
3077 video_codec = wfd_sink->ini.video_codec;
3083 v_decodebin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
3085 wfd_sink_error("failed to allocate memory for video decodebin");
3086 return MM_ERROR_WFD_NO_FREE_SPACE;
3089 memset(v_decodebin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_D_NUM);
3091 /* create video decodebin */
3092 v_decodebin[WFD_SINK_V_D_BIN].id = WFD_SINK_V_D_BIN;
3093 v_decodebin[WFD_SINK_V_D_BIN].gst = gst_bin_new("video_decodebin");
3094 if (!v_decodebin[WFD_SINK_V_D_BIN].gst) {
3095 wfd_sink_error("failed to create video decodebin");
3100 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_QUEUE, "queue", "video_queue", FALSE);
3101 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_QUEUE].gst, "sink");
3102 if (v_decodebin[WFD_SINK_V_D_QUEUE].gst)
3103 __mm_wfd_sink_prepare_queue(wfd_sink, v_decodebin[WFD_SINK_V_D_QUEUE].gst);
3106 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_HDCP, wfd_sink->ini.name_of_video_hdcp, "video_hdcp", FALSE);
3107 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "sink");
3108 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_HDCP].gst, "src");
3110 if (video_codec & WFD_VIDEO_H264) {
3112 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_PARSE, wfd_sink->ini.name_of_video_parser, "video_parser", FALSE);
3113 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "sink");
3114 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_PARSE].gst, "src");
3116 /* create capssetter */
3117 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_CAPSSETTER, wfd_sink->ini.name_of_video_capssetter, "video_capssetter", FALSE);
3118 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "sink");
3119 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_CAPSSETTER].gst, "src");
3122 MMWFDSINK_CREATE_ELEMENT(v_decodebin, WFD_SINK_V_D_DEC, wfd_sink->ini.name_of_video_decoder, "video_dec", FALSE);
3123 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "sink");
3124 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_decodebin[WFD_SINK_V_D_DEC].gst, "src");
3125 if (v_decodebin[WFD_SINK_V_D_DEC].gst) {
3126 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videodec(wfd_sink, v_decodebin[WFD_SINK_V_D_DEC].gst)) {
3127 wfd_sink_error("failed to set video decoder property...");
3133 g_list_free(element_bucket);
3136 wfd_sink->pipeline->v_decodebin = v_decodebin;
3138 /* link video decodebin if video codec is fixed */
3140 if (MM_ERROR_NONE != __mm_wfd_sink_link_video_decodebin(wfd_sink)) {
3141 wfd_sink_error("failed to link video decodebin, destroy video decodebin");
3142 __mm_wfd_sink_destroy_video_decodebin(wfd_sink);
3143 return MM_ERROR_WFD_INTERNAL;
3147 wfd_sink_debug_fleave();
3149 return MM_ERROR_NONE;
3153 wfd_sink_error("failed to create video decodebin, releasing all");
3155 g_list_free(element_bucket);
3157 /* release element which are not added to bin */
3158 for (i = 1; i < WFD_SINK_V_D_NUM; i++) { /* NOTE : skip bin */
3159 if (v_decodebin != NULL && v_decodebin[i].gst) {
3160 GstObject *parent = NULL;
3161 parent = gst_element_get_parent(v_decodebin[i].gst);
3164 gst_object_unref(GST_OBJECT(v_decodebin[i].gst));
3165 v_decodebin[i].gst = NULL;
3167 gst_object_unref(GST_OBJECT(parent));
3172 /* release video decodebin with it's childs */
3173 if (v_decodebin != NULL && v_decodebin[WFD_SINK_V_D_BIN].gst)
3174 gst_object_unref(GST_OBJECT(v_decodebin[WFD_SINK_V_D_BIN].gst));
3176 MMWFDSINK_FREEIF(v_decodebin);
3178 return MM_ERROR_WFD_INTERNAL;
3181 static int __mm_wfd_sink_destroy_video_sinkbin(mm_wfd_sink_t *wfd_sink)
3183 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3184 MMWFDSinkGstElement *v_sinkbin = NULL;
3185 GstObject *parent = NULL;
3188 wfd_sink_debug_fenter();
3190 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3192 if (wfd_sink->pipeline &&
3193 wfd_sink->pipeline->v_sinkbin &&
3194 wfd_sink->pipeline->v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3195 v_sinkbin = wfd_sink->pipeline->v_sinkbin;
3197 wfd_sink_debug("video sinkbin is not created, nothing to destroy");
3198 return MM_ERROR_NONE;
3202 parent = gst_element_get_parent(v_sinkbin[WFD_SINK_V_S_BIN].gst);
3204 wfd_sink_debug("video sinkbin has no parent.. need to relase by itself");
3206 if (GST_STATE(v_sinkbin[WFD_SINK_V_S_BIN].gst) >= GST_STATE_READY) {
3207 wfd_sink_debug("try to change state of video sinkbin to NULL");
3208 ret = gst_element_set_state(v_sinkbin[WFD_SINK_V_S_BIN].gst, GST_STATE_NULL);
3209 if (ret != GST_STATE_CHANGE_SUCCESS) {
3210 wfd_sink_error("failed to change state of video sinkbin to NULL");
3211 return MM_ERROR_WFD_INTERNAL;
3214 /* release element which are not added to bin */
3215 for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */
3216 if (v_sinkbin[i].gst) {
3217 parent = gst_element_get_parent(v_sinkbin[i].gst);
3219 wfd_sink_debug("unref %s(current ref %d)",
3220 GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
3221 ((GObject *) v_sinkbin[i].gst)->ref_count);
3222 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
3223 v_sinkbin[i].gst = NULL;
3225 wfd_sink_debug("unref %s(current ref %d)",
3226 GST_STR_NULL(GST_ELEMENT_NAME(v_sinkbin[i].gst)),
3227 ((GObject *) v_sinkbin[i].gst)->ref_count);
3228 gst_object_unref(GST_OBJECT(parent));
3232 /* release video sinkbin with it's childs */
3233 if (v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3234 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
3237 wfd_sink_debug("video sinkbin has parent(%s), unref it ",
3238 GST_STR_NULL(GST_OBJECT_NAME(GST_OBJECT(parent))));
3240 gst_object_unref(GST_OBJECT(parent));
3243 MMWFDSINK_FREEIF(wfd_sink->pipeline->v_sinkbin);
3245 wfd_sink_debug_fleave();
3247 return MM_ERROR_NONE;
3250 static int __mm_wfd_sink_create_video_sinkbin(mm_wfd_sink_t *wfd_sink)
3252 MMWFDSinkGstElement *first_element = NULL;
3253 MMWFDSinkGstElement *v_sinkbin = NULL;
3254 GList *element_bucket = NULL;
3256 GstPad *ghostpad = NULL;
3259 wfd_sink_debug_fenter();
3261 wfd_sink_return_val_if_fail(wfd_sink &&
3263 MM_ERROR_WFD_NOT_INITIALIZED);
3266 v_sinkbin = (MMWFDSinkGstElement *)g_malloc0(sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
3268 wfd_sink_error("failed to allocate memory for video sinkbin");
3269 return MM_ERROR_WFD_NO_FREE_SPACE;
3272 memset(v_sinkbin, 0, sizeof(MMWFDSinkGstElement) * WFD_SINK_V_S_NUM);
3274 /* create video sinkbin */
3275 v_sinkbin[WFD_SINK_V_S_BIN].id = WFD_SINK_V_S_BIN;
3276 v_sinkbin[WFD_SINK_V_S_BIN].gst = gst_bin_new("video_sinkbin");
3277 if (!v_sinkbin[WFD_SINK_V_S_BIN].gst) {
3278 wfd_sink_error("failed to create video sinkbin");
3282 /* create convert */
3283 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_CONVERT, wfd_sink->ini.name_of_video_converter, "video_convert", TRUE);
3284 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "sink");
3285 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_CONVERT].gst, "src");
3288 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_FILTER, wfd_sink->ini.name_of_video_filter, "video_filter", TRUE);
3289 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "sink");
3290 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_FILTER].gst, "src");
3291 if (v_sinkbin[WFD_SINK_V_S_FILTER].gst) {
3292 GstCaps *caps = NULL;
3293 caps = gst_caps_new_simple("video/x-raw",
3294 "format", G_TYPE_STRING, "SN12", NULL);
3295 g_object_set(G_OBJECT(v_sinkbin[WFD_SINK_V_S_FILTER].gst), "caps", caps, NULL);
3296 gst_object_unref(GST_OBJECT(caps));
3300 MMWFDSINK_CREATE_ELEMENT(v_sinkbin, WFD_SINK_V_S_SINK, wfd_sink->ini.name_of_video_sink, "video_sink", TRUE);
3301 MMWFDSINK_PAD_PROBE(wfd_sink, NULL, v_sinkbin[WFD_SINK_V_S_SINK].gst, "sink");
3302 if (v_sinkbin[WFD_SINK_V_S_SINK].gst) {
3303 if (MM_ERROR_NONE != __mm_wfd_sink_prepare_videosink(wfd_sink, v_sinkbin[WFD_SINK_V_S_SINK].gst)) {
3304 wfd_sink_error("failed to set video sink property....");
3309 /* adding created elements to video sinkbin */
3310 if (!__mm_wfd_sink_gst_element_add_bucket_to_bin(GST_BIN_CAST(v_sinkbin[WFD_SINK_V_S_BIN].gst), element_bucket, FALSE)) {
3311 wfd_sink_error("failed to add elements to video sinkbin");
3315 /* linking elements in the bucket by added order. */
3316 if (__mm_wfd_sink_gst_element_link_bucket(element_bucket) == -1) {
3317 wfd_sink_error("failed to link elements of the video sinkbin");
3321 /* get first element's sinkpad for creating ghostpad */
3322 first_element = (MMWFDSinkGstElement *)g_list_nth_data(element_bucket, 0);
3323 if (!first_element) {
3324 wfd_sink_error("failed to get first element of the video sinkbin");
3328 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3330 wfd_sink_error("failed to get pad from first element(%s) of the video sinkbin",
3331 GST_STR_NULL(GST_ELEMENT_NAME(first_element->gst)));
3335 ghostpad = gst_ghost_pad_new("sink", pad);
3337 wfd_sink_error("failed to create ghostpad of the video sinkbin");
3341 if (FALSE == gst_element_add_pad(v_sinkbin[WFD_SINK_V_S_BIN].gst, ghostpad)) {
3342 wfd_sink_error("failed to add ghostpad to video sinkbin");
3346 gst_object_unref(GST_OBJECT(pad));
3348 g_list_free(element_bucket);
3352 wfd_sink->pipeline->v_sinkbin = v_sinkbin;
3354 wfd_sink_debug_fleave();
3356 return MM_ERROR_NONE;
3360 wfd_sink_error("failed to create video sinkbin, releasing all");
3363 gst_object_unref(GST_OBJECT(pad));
3367 gst_object_unref(GST_OBJECT(ghostpad));
3370 g_list_free(element_bucket);
3372 /* release element which are not added to bin */
3373 for (i = 1; i < WFD_SINK_V_S_NUM; i++) { /* NOTE : skip bin */
3374 if (v_sinkbin != NULL && v_sinkbin[i].gst) {
3375 GstObject *parent = NULL;
3376 parent = gst_element_get_parent(v_sinkbin[i].gst);
3379 gst_object_unref(GST_OBJECT(v_sinkbin[i].gst));
3380 v_sinkbin[i].gst = NULL;
3382 gst_object_unref(GST_OBJECT(parent));
3387 /* release video sinkbin with it's childs */
3388 if (v_sinkbin != NULL && v_sinkbin[WFD_SINK_V_S_BIN].gst)
3389 gst_object_unref(GST_OBJECT(v_sinkbin[WFD_SINK_V_S_BIN].gst));
3391 MMWFDSINK_FREEIF(v_sinkbin);
3393 return MM_ERROR_WFD_INTERNAL;
3396 static int __mm_wfd_sink_destroy_pipeline(mm_wfd_sink_t *wfd_sink)
3398 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
3400 wfd_sink_debug_fenter();
3402 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3404 /* cleanup gst stuffs */
3405 if (wfd_sink->pipeline) {
3406 MMWFDSinkGstElement *mainbin = wfd_sink->pipeline->mainbin;
3409 ret = gst_element_set_state(mainbin[WFD_SINK_M_PIPE].gst, GST_STATE_NULL);
3410 if (ret != GST_STATE_CHANGE_SUCCESS) {
3411 wfd_sink_error("failed to change state of mainbin to NULL");
3412 return MM_ERROR_WFD_INTERNAL;
3415 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_decodebin(wfd_sink)) {
3416 wfd_sink_error("failed to destroy video decodebin");
3417 return MM_ERROR_WFD_INTERNAL;
3420 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_decodebin(wfd_sink)) {
3421 wfd_sink_error("failed to destroy audio decodebin");
3422 return MM_ERROR_WFD_INTERNAL;
3425 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_video_sinkbin(wfd_sink)) {
3426 wfd_sink_error("failed to destroy video sinkbin");
3427 return MM_ERROR_WFD_INTERNAL;
3430 if (MM_ERROR_NONE != __mm_wfd_sink_destroy_audio_sinkbin(wfd_sink)) {
3431 wfd_sink_error("failed to destroy audio sinkbin");
3432 return MM_ERROR_WFD_INTERNAL;
3435 gst_object_unref(GST_OBJECT(mainbin[WFD_SINK_M_PIPE].gst));
3437 MMWFDSINK_FREEIF(mainbin);
3440 MMWFDSINK_FREEIF(wfd_sink->pipeline);
3443 wfd_sink->audio_decodebin_is_linked = FALSE;
3444 wfd_sink->video_decodebin_is_linked = FALSE;
3445 wfd_sink->need_to_reset_basetime = FALSE;
3447 wfd_sink_debug_fleave();
3449 return MM_ERROR_NONE;
3453 __mm_wfd_sink_dump_pipeline_state(mm_wfd_sink_t *wfd_sink)
3455 GstIterator *iter = NULL;
3456 gboolean done = FALSE;
3458 GstElement *item = NULL;
3459 GstElementFactory *factory = NULL;
3461 GstState state = GST_STATE_VOID_PENDING;
3462 GstState pending = GST_STATE_VOID_PENDING;
3463 GstClockTime time = 200 * GST_MSECOND;
3465 wfd_sink_debug_fenter();
3467 wfd_sink_return_if_fail(wfd_sink &&
3468 wfd_sink->pipeline &&
3469 wfd_sink->pipeline->mainbin &&
3470 wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3472 iter = gst_bin_iterate_recurse(GST_BIN(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst));
3476 switch (gst_iterator_next(iter, (gpointer)&item)) {
3477 case GST_ITERATOR_OK:
3478 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
3480 factory = gst_element_get_factory(item) ;
3482 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
3483 GST_STR_NULL(GST_OBJECT_NAME(factory)),
3484 GST_STR_NULL(GST_ELEMENT_NAME(item)),
3485 gst_element_state_get_name(state),
3486 gst_element_state_get_name(pending),
3487 GST_OBJECT_REFCOUNT_VALUE(item));
3489 gst_object_unref(item);
3491 case GST_ITERATOR_RESYNC:
3492 gst_iterator_resync(iter);
3494 case GST_ITERATOR_ERROR:
3497 case GST_ITERATOR_DONE:
3507 item = GST_ELEMENT_CAST(wfd_sink->pipeline->mainbin[WFD_SINK_M_PIPE].gst);
3509 gst_element_get_state(GST_ELEMENT(item), &state, &pending, time);
3511 factory = gst_element_get_factory(item) ;
3513 wfd_sink_error("%s:%s : From:%s To:%s refcount : %d",
3514 GST_OBJECT_NAME(factory),
3515 GST_ELEMENT_NAME(item),
3516 gst_element_state_get_name(state),
3517 gst_element_state_get_name(pending),
3518 GST_OBJECT_REFCOUNT_VALUE(item));
3522 gst_iterator_free(iter);
3524 wfd_sink_debug_fleave();
3530 _mm_wfds_sink_get_state_name(MMWFDSinkStateType state)
3533 case MM_WFD_SINK_STATE_NONE:
3535 case MM_WFD_SINK_STATE_NULL:
3537 case MM_WFD_SINK_STATE_PREPARED:
3539 case MM_WFD_SINK_STATE_CONNECTED:
3541 case MM_WFD_SINK_STATE_PLAYING:
3543 case MM_WFD_SINK_STATE_PAUSED:
3545 case MM_WFD_SINK_STATE_DISCONNECTED:
3546 return "DISCONNECTED";
3552 static void __mm_wfd_sink_prepare_video_resolution(gint resolution, guint *CEA_resolution,
3553 guint *VESA_resolution, guint *HH_resolution)
3555 if (resolution == MM_WFD_SINK_RESOLUTION_UNKNOWN) return;
3557 *CEA_resolution = 0;
3558 *VESA_resolution = 0;
3561 if (resolution & MM_WFD_SINK_RESOLUTION_1920x1080_P30)
3562 *CEA_resolution |= WFD_CEA_1920x1080P30;
3564 if (resolution & MM_WFD_SINK_RESOLUTION_1280x720_P30)
3565 *CEA_resolution |= WFD_CEA_1280x720P30;
3567 if (resolution & MM_WFD_SINK_RESOLUTION_960x540_P30)
3568 *HH_resolution |= WFD_HH_960x540P30;
3570 if (resolution & MM_WFD_SINK_RESOLUTION_864x480_P30)
3571 *HH_resolution |= WFD_HH_864x480P30;
3573 if (resolution & MM_WFD_SINK_RESOLUTION_720x480_P60)
3574 *CEA_resolution |= WFD_CEA_720x480P60;
3576 if (resolution & MM_WFD_SINK_RESOLUTION_640x480_P60)
3577 *CEA_resolution |= WFD_CEA_640x480P60;
3579 if (resolution & MM_WFD_SINK_RESOLUTION_640x360_P30)
3580 *HH_resolution |= WFD_HH_640x360P30;
3583 int _mm_wfd_sink_set_resolution(mm_wfd_sink_t *wfd_sink, MMWFDSinkResolution resolution)
3585 MMWFDSinkStateType cur_state = MM_WFD_SINK_STATE_NONE;
3587 wfd_sink_debug_fenter();
3589 wfd_sink_return_val_if_fail(wfd_sink, MM_ERROR_WFD_NOT_INITIALIZED);
3591 MMWFDSINK_PRINT_STATE(wfd_sink);
3592 cur_state = MMWFDSINK_CURRENT_STATE(wfd_sink);
3593 if (cur_state != MM_WFD_SINK_STATE_NULL) {
3594 wfd_sink_error("This function must be called when MM_WFD_SINK_STATE_NULL");
3595 return MM_ERROR_WFD_INVALID_STATE;
3598 wfd_sink->supportive_resolution = resolution;
3600 wfd_sink_debug_fleave();
3602 return MM_ERROR_NONE;