webrtc_test: Add H264 test case for media packet source 69/252069/10
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 22 Jan 2021 08:12:15 +0000 (17:12 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 4 Feb 2021 02:20:45 +0000 (11:20 +0900)
__DEBUG_VALIDATE_MEDIA_PACKET__ definition is added to test
the media packet for H264 encoded data only with local rendering
pipeline.

[Version] 0.1.101
[Issue Type] Test application

Change-Id: I8f3d4ffd9113ec61f1d224f9a43f7d6942591067
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/capi-media-webrtc.spec
test/webrtc_test.c

index 525930fdbd9de19d9b3b17dcb49c3e3493796afa..a6c5422208877d156ce4ee6abc4465378c949a0e 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.1.100
+Version:    0.1.101
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index cd1c1607b1501a665dc6c0232dd8404f1b16bbc9..87c22aa5338370377a10c4cd78ba95c072b6c82f 100644 (file)
@@ -33,6 +33,8 @@
 #endif
 #define PACKAGE "webrtc_test"
 
+//#define __DEBUG_VALIDATE_MEDIA_PACKET__
+
 #ifdef LOG_TAG
 #undef LOG_TAG
 #endif
@@ -115,9 +117,15 @@ typedef struct {
 
        webrtc_h webrtc;
        GstElement *src_pipeline;
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+       GstElement *render_pipeline;
+       GstElement *appsrc;
+#endif
        GstElement *src;
        GstElement *sink;
+       GstElement *demux;
        gulong handoff_signal_id;
+       gulong pad_added_signal_id;
        bool is_overflowed;
        bool is_stop_requested;
        GCond cond;
@@ -328,6 +336,10 @@ static void __release_packet_source(int conn_idx, unsigned int source_idx)
                __disconnect_signal((GObject *)packet_source->sink, packet_source->handoff_signal_id);
                packet_source->handoff_signal_id = 0;
        }
+       if (packet_source->pad_added_signal_id > 0) {
+               __disconnect_signal((GObject *)packet_source->demux, packet_source->pad_added_signal_id);
+               packet_source->pad_added_signal_id = 0;
+       }
        g_clear_object(&packet_source->src_pipeline);
        packet_source->src_pipeline = NULL;
 
@@ -503,7 +515,7 @@ static void _webrtc_remove_media_source(int index, unsigned int source_id)
 }
 
 #define VIDEO_WIDTH       352
-#define VIDEO_HIGHT       288
+#define VIDEO_HEIGHT      288
 #define VIDEO_FRAME_RATE  30
 #define AUDIO_CHANNEL     1
 #define AUDIO_SAMPLERATE  8000
@@ -534,9 +546,12 @@ static int __create_formats(media_format_mimetype_e type, media_format_h *format
                }
 
        } else if (type & MEDIA_FORMAT_VIDEO) {
+               /* assume that h264 video file of 640x480 resolution */
+               int width = (type == MEDIA_FORMAT_H264_SP) ? 640 : VIDEO_WIDTH;
+               int height = (type == MEDIA_FORMAT_H264_SP) ? 480 : VIDEO_HEIGHT;
                ret = media_format_set_video_mime(*format, type);
-               ret |= media_format_set_video_width(*format, VIDEO_WIDTH);
-               ret |= media_format_set_video_height(*format, VIDEO_HIGHT);
+               ret |= media_format_set_video_width(*format, width);
+               ret |= media_format_set_video_height(*format, height);
                ret |= media_format_set_video_frame_rate(*format, VIDEO_FRAME_RATE);
                if (ret != MEDIA_FORMAT_ERROR_NONE) {
                        g_print("failed to set video format\n");
@@ -571,6 +586,9 @@ static void _webrtc_media_packet_source_set_format(int index, unsigned int sourc
        case 3:
                type = MEDIA_FORMAT_PCM_S16LE;
                break;
+       case 4:
+               type = MEDIA_FORMAT_H264_SP;
+               break;
        default:
                g_print("invalid value[%d]\n", value);
                return;
@@ -1454,73 +1472,70 @@ static int __media_packet_finalize_cb(media_packet_h packet, int error_code, voi
        return MEDIA_PACKET_FINALIZE;
 }
 
-static void __stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
+static media_packet_h __make_media_packet(media_packet_source_s *packet_source, GstBuffer *buffer)
 {
        int ret;
-       media_packet_h packet;
-       media_packet_source_s *packet_source = (media_packet_source_s *)data;
+       media_packet_h packet = NULL;
        guchar *data_ptr;
        gsize size;
        GstClockTime pts;
+       GstClockTime dts;
        GstClockTime duration;
        GstMapInfo buff_info = GST_MAP_INFO_INIT;
        bool has_tbm_surface;
        tbm_surface_info_s ts_info;
 
-       if (!object || !buffer || !pad || !packet_source) {
-               g_printerr("invalid parameters, object[%p], buffer[%p], pad[%p], packet_source[%p]\n", object, buffer, pad, packet_source);
-               return;
-       }
-
-       if (packet_source->is_stop_requested) {
-               g_print("stop requested, skip this buffer[%p]\n", buffer);
-               return;
+       if (!packet_source) {
+               g_printerr("packet_source is NULL\n");
+               return NULL;
        }
-
-       g_mutex_lock(&packet_source->mutex);
-       if (packet_source->is_overflowed) {
-               g_print("wait...\n");
-               g_cond_wait(&packet_source->cond, &packet_source->mutex);
-               g_print("wake up...\n");
+       if (!buffer) {
+               g_printerr("buffer is NULL\n");
+               return NULL;
        }
-       g_mutex_unlock(&packet_source->mutex);
-
-       size = gst_buffer_get_size(buffer);
-       pts = GST_BUFFER_PTS(buffer);
-       duration = GST_BUFFER_DURATION(buffer);
-
-       g_print("__stream_handoff_cb(), buffer[%p], size[%u], pts[%llu], duration[%llu]\n", buffer, size, pts, duration);
 
        ret = media_packet_create_alloc(packet_source->format, __media_packet_finalize_cb, packet_source, &packet);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
                g_printerr("failed to media_packet_create_alloc()\n");
-               return;
+               return NULL;
        }
 
        gst_buffer_ref(buffer);
 
+       size = gst_buffer_get_size(buffer);
+       pts = GST_BUFFER_PTS(buffer);
+       dts = GST_BUFFER_DTS(buffer);
+       duration = GST_BUFFER_DURATION(buffer);
+       g_print("buffer[%p], size[%u], pts[%llu], dts[%llu], duration[%llu]\n", buffer, size, pts, dts, duration);
+
        ret = media_packet_set_pts(packet, pts);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
                g_printerr("failed to media_packet_set_pts()\n");
-               goto exit;
+               goto error;
+       }
+
+       ret = media_packet_set_dts(packet, dts);
+       if (ret != MEDIA_PACKET_ERROR_NONE) {
+               g_printerr("failed to media_packet_set_dts()\n");
+               goto error;
        }
 
        ret = media_packet_set_duration(packet, duration);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
                g_printerr("failed to media_packet_set_duration()\n");
-               goto exit;
+               goto error;
        }
 
        ret = media_packet_set_buffer_size(packet, size);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
                g_printerr("failed to media_packet_set_buffer_size()\n");
-               goto exit;
+               goto error;
        }
 
        ret = media_packet_get_buffer_data_ptr(packet, (void **)&data_ptr);
        if (ret != MEDIA_PACKET_ERROR_NONE) {
                g_printerr("failed to media_packet_get_buffer_data_ptr()\n");
-               goto exit;
+               goto error;
        }
 
        media_packet_has_tbm_surface_buffer(packet, &has_tbm_surface);
@@ -1532,7 +1547,7 @@ static void __stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *p
                ret = tbm_surface_get_info(ts, &ts_info);
                if (ret != TBM_SURFACE_ERROR_NONE) {
                        g_printerr("failed to tbm_surface_get_info()\n");
-                       goto exit;
+                       goto error;
                }
                g_print("tbm surface[%p, %ux%u, size:%u, format:%u, num_planes:%u] found\n",
                        ts, ts_info.width, ts_info.height, ts_info.size, ts_info.format, ts_info.num_planes);
@@ -1551,18 +1566,186 @@ static void __stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *p
                        memcpy(data_ptr, buff_info.data, size);
                }
                gst_buffer_unmap(buffer, &buff_info);
-       } else
+       } else {
                g_printerr("failed to gst_buffer_map()\n");
+               goto error;
+       }
 
-       ret = webrtc_media_packet_source_push_packet(packet_source->webrtc, packet_source->source_id, packet);
-       if (ret != WEBRTC_ERROR_NONE)
-               g_printerr("failed to webrtc_media_packet_source_push_packet()\n");
+       return packet;
 
-exit:
+error:
        media_packet_destroy(packet);
        gst_buffer_unref(buffer);
+       return NULL;
 }
 
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+static int __fill_gst_buffer_mapped_data_from_packet(GstBuffer *buffer, media_packet_h packet)
+{
+       bool has_tbm_surface = false;
+       tbm_surface_info_s ts_info;
+       guint64 size = 0;
+       GstMapInfo buff_info = GST_MAP_INFO_INIT;
+
+       if (!buffer) {
+               g_printerr("buffer is NULL\n");
+               return -1;
+       }
+       if (!packet) {
+               g_printerr("packet is NULL\n");
+               return -1;
+       }
+
+       media_packet_get_buffer_size(packet, &size);
+       media_packet_has_tbm_surface_buffer(packet, &has_tbm_surface);
+
+       if (has_tbm_surface) {
+               int ret = TBM_SURFACE_ERROR_NONE;
+               tbm_surface_h ts;
+
+               media_packet_get_tbm_surface(packet, &ts);
+               ret = tbm_surface_get_info(ts, &ts_info);
+               if (ret != TBM_SURFACE_ERROR_NONE) {
+                       g_printerr("failed to tbm_surface_get_info()\n");
+                       return -1;
+               }
+
+               g_printerr("tbm surface[%p, %ux%u, size:%u, format:%u, num_planes:%u] found\n",
+                       ts, ts_info.width, ts_info.height, ts_info.size, ts_info.format, ts_info.num_planes);
+       }
+
+       if (gst_buffer_map(buffer, &buff_info, GST_MAP_READWRITE)) {
+               if (has_tbm_surface) {
+                       int i;
+                       guint8 *ptr = buff_info.data;
+                       for (i = 0; i < ts_info.num_planes; i++) {
+                               g_print("plane[%d][ptr:%p size:%u]\n", i, ts_info.planes[i].ptr, ts_info.planes[i].size);
+                               memcpy(ptr, ts_info.planes[i].ptr, ts_info.planes[i].size);
+                               ptr += ts_info.planes[i].size;
+                       }
+
+               } else {
+                       guchar *data_ptr;
+                       media_packet_get_buffer_data_ptr(packet, (void **)&data_ptr);
+                       if (data_ptr == NULL) {
+                               g_printerr("invalid packet, data_ptr is NULL\n");
+                               gst_buffer_unmap(buffer, &buff_info);
+                               return -1;
+                       }
+                       memcpy(buff_info.data, data_ptr, size);
+               }
+
+               buff_info.size = size;
+
+               g_print("buffer[%p], buff_info[data:%p, size:%u]\n", buffer, buff_info.data, buff_info.size);
+
+               gst_buffer_unmap(buffer, &buff_info);
+       }
+
+       return 0;
+}
+
+GstBuffer *__get_buffer_from_packet(media_packet_h packet)
+{
+       int ret;
+       guchar *data_ptr;
+       GstBuffer *new_buffer;
+       guint64 pts = 0;
+       guint64 dts = 0;
+       guint64 duration = 0;
+       guint64 size = 0;
+
+       media_packet_get_buffer_data_ptr(packet, (void **)&data_ptr);
+       if (data_ptr == NULL) {
+               g_printerr("invalid packet, data_ptr is NULL\n");
+               return NULL;
+       }
+
+       media_packet_get_buffer_size(packet, &size);
+
+       new_buffer = gst_buffer_new_and_alloc(size);
+       if (!new_buffer) {
+               g_printerr("failed to gst_buffer_new_and_alloc()\n");
+               return NULL;
+       }
+
+       ret = __fill_gst_buffer_mapped_data_from_packet(new_buffer, packet);
+       if (ret == -1) {
+               g_printerr("failed to __fill_gst_buffer_mapped_data_from_packet()\n");
+               gst_buffer_unref(new_buffer);
+               return NULL;
+       }
+
+       media_packet_get_pts(packet, &pts);
+       GST_BUFFER_PTS(new_buffer) = pts;
+       media_packet_get_dts(packet, &dts);
+       GST_BUFFER_DTS(new_buffer) = dts;
+
+       media_packet_get_duration(packet, &duration);
+       GST_BUFFER_DURATION(new_buffer) = duration;
+
+       g_print("new gst buffer[%p, pts:%llu, dts:%llu, duration:%llu]\n", new_buffer, pts, dts, duration);
+
+       return new_buffer;
+}
+#endif /* __DEBUG_VALIDATE_MEDIA_PACKET__ */
+
+static void __stream_handoff_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
+{
+       media_packet_source_s *packet_source = (media_packet_source_s *)data;
+       media_packet_h packet;
+
+       if (!object || !buffer || !pad || !packet_source) {
+               g_printerr("invalid parameters, object[%p], buffer[%p], pad[%p], packet_source[%p]\n", object, buffer, pad, packet_source);
+               return;
+       }
+
+       if (packet_source->is_stop_requested) {
+               g_print("stop requested, skip this buffer[%p]\n", buffer);
+               return;
+       }
+
+       g_mutex_lock(&packet_source->mutex);
+       if (packet_source->is_overflowed) {
+               g_print("wait...\n");
+               g_cond_wait(&packet_source->cond, &packet_source->mutex);
+               g_print("wake up...\n");
+       }
+       g_mutex_unlock(&packet_source->mutex);
+
+       GstCaps *caps = gst_pad_get_current_caps(pad);
+       gchar *caps_str = gst_caps_to_string(caps);
+       g_print("__stream_handoff_cb(), buffer[%p] caps[%s]\n", buffer, caps_str);
+       g_free(caps_str);
+       gst_caps_unref(caps);
+
+       packet = __make_media_packet(packet_source, buffer);
+       if (!packet) {
+               g_printerr("failed to __make_media_packet()\n");
+               return;
+       }
+
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+       GstBuffer *buffer_from_packet = __get_buffer_from_packet(packet);
+       if (!buffer_from_packet) {
+               media_packet_destroy(packet);
+               g_printerr("buffer_from_packet is NULL\n");
+               return;
+       }
+
+       GstFlowReturn gst_ret = GST_FLOW_OK;
+       g_signal_emit_by_name(G_OBJECT(packet_source->appsrc), "push-buffer", buffer_from_packet, &gst_ret, NULL);
+       if (gst_ret != GST_FLOW_OK)
+               g_printerr("failed to 'push-buffer', gst_ret[0x%x]\n", gst_ret);
+
+       gst_buffer_unref(buffer_from_packet);
+
+#else
+       if (webrtc_media_packet_source_push_packet(packet_source->webrtc, packet_source->source_id, packet) != WEBRTC_ERROR_NONE)
+               g_printerr("failed to webrtc_media_packet_source_push_packet()\n");
+#endif
+       media_packet_destroy(packet);
+}
 
 static GstCaps *__make_raw_caps(media_format_h format)
 {
@@ -1645,50 +1828,160 @@ static GstCaps *__make_raw_caps(media_format_h format)
        return caps;
 }
 
-static GstElement* __make_src_pipeline(media_packet_source_s *packet_source)
+static void __demux_pad_added_cb(GstElement *object, GstPad *pad, gpointer data)
 {
-       media_format_type_e format_type;
-       GstElement *src;
+       media_packet_source_s *packet_source = (media_packet_source_s *)data;
+       GstPad *sinkpad;
+       const gchar *media_type;
+       GstElement *h264parse;
        GstElement *capsfilter;
-       const char *factory_name_src = "videotestsrc";
-       const char *factory_name_sink;
        GstCaps *caps;
-       gchar *caps_str;
+
+       g_print("__demux_pad_added_cb(), object[%s] pad[%s] packet_source[%p]\n",
+               GST_ELEMENT_NAME(object), GST_PAD_NAME(pad), packet_source);
+
+       media_type = gst_structure_get_name(gst_caps_get_structure(gst_pad_get_current_caps(pad), 0));
+
+       if (g_strrstr(media_type, "audio")) {
+               g_print("skip pad for audio");
+               return;
+       }
+
+       h264parse = gst_element_factory_make("h264parse", NULL);
+       if (!h264parse) {
+               g_printerr("failed to gst_element_factory_make(), h264parse\n");
+               return;
+       }
+
+       capsfilter = gst_element_factory_make("capsfilter", NULL);
+       if (!capsfilter) {
+               g_printerr("failed to gst_element_factory_make(), capsfilter\n");
+               return;
+       }
+       caps = gst_caps_new_simple("video/x-h264",
+               "stream-format", G_TYPE_STRING, "byte-stream",
+               "alignment", G_TYPE_STRING, "au",
+               NULL);
+
+       g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
+       gst_caps_unref(caps);
+
+
+       gst_bin_add_many(GST_BIN(packet_source->src_pipeline), h264parse, capsfilter, packet_source->sink, NULL);
+
+       sinkpad = gst_element_get_static_pad(h264parse, "sink");
+       if (!sinkpad) {
+               g_printerr("failed to get static pad\n");
+               return;
+       }
+
+       if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
+               g_printerr("failed to link pad\n");
+               return;
+       }
+       gst_object_unref(sinkpad);
+
+       if (!gst_element_link_many(h264parse, capsfilter, packet_source->sink, NULL)) {
+               g_printerr("failed to gst_element_link_many()\n");
+               return;
+       }
+
+       if (!gst_element_sync_state_with_parent(h264parse)) {
+               g_print("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(h264parse));
+               return;
+       }
+       if (!gst_element_sync_state_with_parent(capsfilter)) {
+               g_print("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(capsfilter));
+               return;
+       }
+       if (!gst_element_sync_state_with_parent(packet_source->sink)) {
+               g_print("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(packet_source->sink));
+               return;
+       }
+}
+
+#define TEST_640_480_VIDEO_MP4_PATH    "/opt/usr/home/owner/media/Videos/1.mp4"
+static GstElement* __build_h264_format_pipeline(media_packet_source_s *packet_source)
+{
+       GstElement *pipeline;
+       GstElement *src;
 
        if (!packet_source) {
                g_printerr("packet_source is NULL\n");
                return NULL;
        }
 
-       if (!packet_source->format) {
-               g_printerr("format is not set yet\n");
-               return NULL;
+       pipeline = gst_pipeline_new("h264-format-src-pipeline");
+
+       src = gst_element_factory_make("filesrc", NULL);
+       if (!src) {
+               g_printerr("failed to gst_element_factory_make(), filesrc\n");
+               goto error;
        }
 
-       packet_source->src_pipeline = gst_pipeline_new("src-pipeline");
-       if (!packet_source) {
-               g_printerr("failed to gst_pipeline_new()\n");
-               return NULL;
+       g_object_set(G_OBJECT(src), "location", TEST_640_480_VIDEO_MP4_PATH, NULL);
+
+       packet_source->demux = gst_element_factory_make("qtdemux", NULL);
+       if (!packet_source->demux) {
+               g_printerr("failed to gst_element_factory_make(), qtdemux\n");
+               goto error;
        }
 
-       if (media_format_get_type(packet_source->format, &format_type) != MEDIA_FORMAT_ERROR_NONE) {
-               g_printerr("failed to media_format_get_type()\n");
+       packet_source->pad_added_signal_id = _connect_signal((GObject *)packet_source->demux, "pad-added", G_CALLBACK(__demux_pad_added_cb), packet_source);
+       if (packet_source->pad_added_signal_id == 0)
+               goto error;
+
+       packet_source->sink = gst_element_factory_make("fakesink", NULL);
+       if (!packet_source->sink) {
+               g_printerr("failed to gst_element_factory_make(), fakesink\n");
+               goto error;
+       }
+
+       gst_bin_add_many(GST_BIN(pipeline), src, packet_source->demux, NULL);
+       if (!gst_element_link_many(src, packet_source->demux, NULL)) {
+               g_printerr("failed to gst_element_link_many(), filesrc, qtdemux\n");
+               goto error;
+       }
+
+       g_object_set(packet_source->sink, "signal-handoffs", TRUE, NULL);
+       packet_source->handoff_signal_id = _connect_signal((GObject *)packet_source->sink, "handoff", G_CALLBACK(__stream_handoff_cb), packet_source);
+       if (packet_source->handoff_signal_id == 0)
+               goto error;
+
+       return pipeline;
+
+error:
+       gst_object_unref(pipeline);
+       if (packet_source->pad_added_signal_id > 0) {
+               __disconnect_signal((GObject *)packet_source->demux, packet_source->pad_added_signal_id);
+               packet_source->pad_added_signal_id = 0;
+       }
+       return NULL;
+}
+
+static GstElement* __build_raw_format_pipeline(media_packet_source_s *packet_source, bool is_audio)
+{
+       GstElement *pipeline;
+       GstElement *src;
+       GstElement *capsfilter;
+       GstCaps *caps;
+       gchar *caps_str;
+
+       if (!packet_source) {
+               g_printerr("packet_source is NULL\n");
                return NULL;
        }
 
-       if (format_type == MEDIA_FORMAT_AUDIO)
-               factory_name_src = "audiotestsrc";
-       else if (format_type == MEDIA_FORMAT_VIDEO)
-               factory_name_src = "videotestsrc";
+       pipeline = gst_pipeline_new("raw-format-pipeline");
 
-       src = gst_element_factory_make(factory_name_src, NULL);
+       src = gst_element_factory_make(is_audio ? "audiotestsrc" : "videotestsrc", NULL);
        if (!src) {
-               g_printerr("failed to gst_element_factory_make(), %s\n", factory_name_src);
+               g_printerr("failed to gst_element_factory_make(), %s\n", is_audio ? "audiotestsrc" : "videotestsrc");
                goto error;
        }
 
        g_object_set(G_OBJECT(src), "is-live", TRUE, NULL);
-       if (format_type == MEDIA_FORMAT_VIDEO)
+       if (!is_audio)
                g_object_set(G_OBJECT(src), "pattern", 18, NULL); /* 18: ball */
 
        capsfilter = gst_element_factory_make("capsfilter", NULL);
@@ -1708,14 +2001,13 @@ static GstElement* __make_src_pipeline(media_packet_source_s *packet_source)
        g_object_set(G_OBJECT(capsfilter), "caps", caps, NULL);
        gst_caps_unref(caps);
 
-       factory_name_sink = "fakesink";
-       packet_source->sink = gst_element_factory_make(factory_name_sink, NULL);
+       packet_source->sink = gst_element_factory_make("fakesink", NULL);
        if (!packet_source->sink) {
-               g_printerr("failed to gst_element_factory_make(), %s\n", factory_name_sink);
+               g_printerr("failed to gst_element_factory_make(), fakesink\n");
                goto error;
        }
 
-       gst_bin_add_many(GST_BIN(packet_source->src_pipeline), src, capsfilter, packet_source->sink, NULL);
+       gst_bin_add_many(GST_BIN(pipeline), src, capsfilter, packet_source->sink, NULL);
        if (!gst_element_link_many(src, capsfilter, packet_source->sink, NULL)) {
                g_printerr("failed to gst_element_link_many()\n");
                goto error;
@@ -1726,14 +2018,129 @@ static GstElement* __make_src_pipeline(media_packet_source_s *packet_source)
        if (packet_source->handoff_signal_id == 0)
                goto error;
 
-       return packet_source->src_pipeline;
+       return pipeline;
 
 error:
-       gst_object_unref(packet_source->src_pipeline);
-       packet_source->src_pipeline = NULL;
+       gst_object_unref(pipeline);
+       return NULL;
+}
+
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+static GstElement* __build_appsrc_render_pipeline(media_packet_source_s *packet_source)
+{
+       GstElement *pipeline;
+       GstElement *src;
+       GstElement *dec;
+       GstElement *convert;
+       GstElement *sink;
+       GstCaps *caps;
+
+       if (!packet_source) {
+               g_printerr("packet_source is NULL\n");
+               return NULL;
+       }
+
+       pipeline = gst_pipeline_new("appsrc-render-pipeline");
+
+       src = gst_element_factory_make("appsrc", NULL);
+       if (!src) {
+               g_printerr("failed to gst_element_factory_make(), appsrc\n");
+               goto error;
+       }
+
+       caps = gst_caps_new_simple("video/x-h264",
+               "stream-format", G_TYPE_STRING, "byte-stream",
+               "alignment", G_TYPE_STRING, "au",
+               NULL);
+
+       g_object_set(G_OBJECT(src), "caps", caps, NULL);
 
+       dec = gst_element_factory_make("avdec_h264", NULL);
+       if (!dec) {
+               g_printerr("failed to gst_element_factory_make(), avdec_h264\n");
+               goto error;
+       }
+
+       convert = gst_element_factory_make("videoconvert", NULL);
+       if (!convert) {
+               g_printerr("failed to gst_element_factory_make(), videoconvert\n");
+               goto error;
+       }
+
+       sink = gst_element_factory_make("tizenwlsink", NULL);
+       if (!sink) {
+               g_printerr("failed to gst_element_factory_make(), tizenwlsink\n");
+               goto error;
+       }
+
+       gst_bin_add_many(GST_BIN(pipeline), src, dec, convert, sink, NULL);
+       if (!gst_element_link_many(src, dec, convert, sink, NULL)) {
+               g_printerr("failed to gst_element_link_many(), appsrc_render\n");
+               goto error;
+       }
+
+       packet_source->appsrc = src;
+
+       return pipeline;
+
+error:
+       gst_object_unref(pipeline);
        return NULL;
 }
+#endif
+
+static GstElement* __make_src_pipeline(media_packet_source_s *packet_source)
+{
+       media_format_type_e format_type;
+
+       if (!packet_source) {
+               g_printerr("packet_source is NULL\n");
+               return NULL;
+       }
+
+       if (!packet_source->format) {
+               g_printerr("format is not set yet\n");
+               return NULL;
+       }
+
+       if (media_format_get_type(packet_source->format, &format_type) != MEDIA_FORMAT_ERROR_NONE) {
+               g_printerr("failed to media_format_get_type()\n");
+               return NULL;
+       }
+
+       if (format_type == MEDIA_FORMAT_AUDIO) {
+               packet_source->src_pipeline = __build_raw_format_pipeline(packet_source, true);
+
+       } else if (format_type == MEDIA_FORMAT_VIDEO) {
+               media_format_mimetype_e mimetype;
+               int width;
+               int height;
+
+               media_format_get_video_info(packet_source->format, &mimetype, &width, &height, NULL, NULL);
+               switch (mimetype) {
+               case MEDIA_FORMAT_H264_SP:
+                       packet_source->src_pipeline = __build_h264_format_pipeline(packet_source);
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+                       packet_source->render_pipeline = __build_appsrc_render_pipeline(packet_source);
+#endif
+                       break;
+               case MEDIA_FORMAT_I420:
+               case MEDIA_FORMAT_NV12:
+                       packet_source->src_pipeline = __build_raw_format_pipeline(packet_source, false);
+                       break;
+               default:
+                       g_printerr("unsupported mimetype(0x%x)", mimetype);
+                       return NULL;
+               }
+       }
+
+       if (!packet_source->src_pipeline) {
+               g_printerr("packet_source->src_pipeline is NULL\n");
+               return NULL;
+       }
+
+       return packet_source->src_pipeline;
+}
 
 static void _start_pushing_packet(int index, int source_id)
 {
@@ -1757,6 +2164,10 @@ static void _start_pushing_packet(int index, int source_id)
        }
 
        state_change_ret = gst_element_set_state(g_conns[index].packet_sources[i].src_pipeline, GST_STATE_PLAYING);
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+       if (g_conns[index].packet_sources[i].render_pipeline)
+               state_change_ret = gst_element_set_state(g_conns[index].packet_sources[i].render_pipeline, GST_STATE_PLAYING);
+#endif
        if (state_change_ret == GST_STATE_CHANGE_FAILURE) {
                g_printerr("failed to set state to PLAYING\n");
                return;
@@ -1786,6 +2197,10 @@ static void _stop_pushing_packet(int index, int source_id)
        g_conns[index].packet_sources[i].is_stop_requested = true;
 
        gst_element_set_state(g_conns[index].packet_sources[i].src_pipeline, GST_STATE_PAUSED);
+#ifdef __DEBUG_VALIDATE_MEDIA_PACKET__
+       if (g_conns[index].packet_sources[i].render_pipeline)
+               gst_element_set_state(g_conns[index].packet_sources[i].render_pipeline, GST_STATE_PAUSED);
+#endif
 
        g_print("_stop_pushing_packet()\n");
 }
@@ -2403,7 +2818,7 @@ static void displaymenu()
                if (g_conns[g_conn_index].cnt == 0)
                        g_print("*** input source id.\n");
                else if (g_conns[g_conn_index].cnt == 1)
-                       g_print("*** input media format.(1:I420 2:NV12 3:PCM_S16LE)\n");
+                       g_print("*** input media format.(1:I420 2:NV12 3:PCM_S16LE 4:H264)\n");
 
        } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_GET_TRANSCEIVER_DIRECTION) {
                if (g_conns[g_conn_index].cnt == 0)