Support MJPEG decoding 43/321143/4
authorJeongmo Yang <jm80.yang@samsung.com>
Fri, 14 Mar 2025 11:05:16 +0000 (20:05 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Thu, 3 Apr 2025 02:18:34 +0000 (11:18 +0900)
- Update media_codec_test for MJPEG decoding

[Version] 1.2.0
[Issue Type] New feature

Change-Id: Ifc0fa90687e96e1462949537a4e50ef53b4a676b
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
include/media_codec_bitstream.h
packaging/capi-media-codec.spec
src/media_codec_bitstream.c
src/media_codec_port_gst.c
test/media_codec_test.c

index 416c9b3b0ccd818111a5b5a9df89e6f059f101cd..32a735f7f3e52b0158e6cab0c96d17790ac17c20 100644 (file)
@@ -98,6 +98,7 @@ int _mc_check_h264_bytestream(unsigned char *nal, int byte_length, bool port, bo
 int _mc_check_valid_h263_frame(unsigned char *p, int size);
 bool _mc_check_h263_out_bytestream(unsigned char *p, int buf_length, bool* need_sync_flag);
 int _mc_check_mpeg4_out_bytestream(unsigned char *buf, int buf_length, bool* need_codec_data, bool *need_sync_flag);
+bool _mc_check_mjpeg_out_bytestream(unsigned char *buf, int buf_length);
 
 int _mc_get_h264_codecdata_size(guint8 *data, int size);
 
index 6dfca187e46816a6d87b18358dd497378fd05c77..cff35a2910beb1d3144e5bb6da912e85e23d28cd 100644 (file)
@@ -4,7 +4,7 @@
 
 Name:       capi-media-codec
 Summary:    A Media Codec library in Tizen Native API
-Version:    1.1.8
+Version:    1.2.0
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index da6d3b7a3aeb1e01686f37b8ae6cca25acea38cf..a2840486818b99393d6672ef1a2a0beccf6267e1 100644 (file)
@@ -379,6 +379,29 @@ bool _mc_check_h263_out_bytestream(unsigned char *p, int buf_length, bool* need_
        return TRUE;
 }
 
+bool _mc_check_mjpeg_out_bytestream(unsigned char *buf, int buf_length)
+{
+       if (!buf)
+               return false;
+
+       if (buf_length < 2) {
+               LOGE("Too short buf length[%d]", buf_length);
+               return false;
+       }
+
+       if (buf[0] != 0xFF || buf[1] != 0xD8) {
+               LOGE("No SOI marker[0xFFD8] vs [0x%02X%02X]", buf[0], buf[1]);
+               return false;
+       }
+
+       if (buf[buf_length - 2] != 0xFF || buf[buf_length - 1] != 0xD9) {
+               LOGE("No EOI marker[0xFFD9] vs [0x%02X%02X]", buf[buf_length-2], buf[buf_length-1]);
+               return false;
+       }
+
+       return true;
+}
+
 int _mc_get_h264_codecdata_size(guint8 *data, int size)
 {
        int offset = 0;
index 25b1c75df9b111684cafbfde40a6ae57deb899e8..da12e49e8ddf69cd01c70397e573294bbe2ac26e 100644 (file)
@@ -120,7 +120,10 @@ static int(*vdec_h264_sw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                       /
 static int(*vdec_mpeg4_sw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                  /* S/W MPEG4 Decoder Vtable */
                                                                &__mc_fill_vdec_packet_with_output_buffer};
 
-static int(*vdec_h263_sw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                   /* S/W MPEG4 Decoder Vtable */
+static int(*vdec_h263_sw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                   /* S/W H.263 Decoder Vtable */
+                                                               &__mc_fill_vdec_packet_with_output_buffer};
+
+static int(*vdec_mjpeg_sw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                  /* S/W MJPEG Decoder Vtable */
                                                                &__mc_fill_vdec_packet_with_output_buffer};
 
 static int(*vdec_h264_hw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                   /* H/W H.264 Decoder Vtable */
@@ -129,13 +132,19 @@ static int(*vdec_h264_hw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                      /
 static int(*vdec_mpeg4_hw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                  /* H/W MPEG4 Decoder Vtable */
                                                                &__mc_fill_vdec_packet_with_output_buffer};
 
-static int(*vdec_h263_hw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                   /* H/W MPEG4 Decoder Vtable */
+static int(*vdec_h263_hw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                   /* H/W H.263 Decoder Vtable */
+                                                               &__mc_fill_vdec_packet_with_output_buffer};
+
+static int(*vdec_mjpeg_hw_vtable[])() = {&__mc_fill_input_buffer_with_packet,                  /* H/W MJPEG Decoder Vtable */
                                                                &__mc_fill_vdec_packet_with_output_buffer};
 
 static int(*venc_mpeg4_sw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,             /* S/W MPEG4 Encoder Vtable */
                                                                &__mc_fill_venc_packet_with_output_buffer};
 
-static int(*venc_h263_sw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,              /* S/W MPEG4 Encoder Vtable */
+static int(*venc_h263_sw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,              /* S/W H.263 Encoder Vtable */
+                                                               &__mc_fill_venc_packet_with_output_buffer};
+
+static int(*venc_mjpeg_sw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,             /* S/W MJPEG Encoder Vtable */
                                                                &__mc_fill_venc_packet_with_output_buffer};
 
 static int(*venc_h264_hw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,              /* H/W H.264 Encoder Vtable */
@@ -144,7 +153,10 @@ static int(*venc_h264_hw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet
 static int(*venc_mpeg4_hw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,             /* H/W MPEG4 Encoder Vtable */
                                                                &__mc_fill_venc_packet_with_output_buffer};
 
-static int(*venc_h263_hw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,              /* H/W MPEG4 Encoder Vtable */
+static int(*venc_h263_hw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,              /* H/W H.263 Encoder Vtable */
+                                                               &__mc_fill_venc_packet_with_output_buffer};
+
+static int(*venc_mjpeg_hw_vtable[])() = {&__mc_fill_input_buffer_with_venc_packet,             /* H/W MJPEG Encoder Vtable */
                                                                &__mc_fill_venc_packet_with_output_buffer};
 
 __attribute__((unused))
@@ -511,9 +523,9 @@ static int __mc_fill_packet_with_output_buffer(mc_gst_core_t *core, void *data,
 static int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *data, int size, GstMCBuffer *mcbuffer)
 {
        gint ret = MC_ERROR_NONE;
-       bool codec_config = FALSE;
-       bool sync_flag = FALSE;
-       bool slice = FALSE;
+       bool codec_config = false;
+       bool sync_flag = false;
+       bool slice = false;
        gint mem_size = 0;
        gchar *ext_mem = NULL;
        gint data_size = 0;
@@ -524,27 +536,40 @@ static int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *d
 
        switch (core->ports[out_port_index]->port_def.coding_type) {
        case MEDIA_FORMAT_H264_SP:
+               /* fall through */
        case MEDIA_FORMAT_H264_MP:
+               /* fall through */
        case MEDIA_FORMAT_H264_HP:
                data_size = _mc_check_h264_bytestream((unsigned char *)data, size, 1, &codec_config, &sync_flag, &slice);
-
                if (data_size < 0) {
                        LOGE("No valid SPS/PPS ...");
                        return MC_INVALID_IN_BUF;
                }
                break;
+
        case MEDIA_FORMAT_MPEG4_SP:
+               /* fall through */
        case MEDIA_FORMAT_MPEG4_ASP:
                _mc_check_mpeg4_out_bytestream((unsigned char *)data, size, &codec_config, &sync_flag);
                break;
+
        case MEDIA_FORMAT_H263:
+               /* fall through */
        case MEDIA_FORMAT_H263P:
                if (!_mc_check_h263_out_bytestream((unsigned char *)data, size, &sync_flag))
                        return MC_INVALID_IN_BUF;
                break;
+
+       case MEDIA_FORMAT_MJPEG:
+               sync_flag = true;
+               if (!_mc_check_mjpeg_out_bytestream((unsigned char *)data, size))
+                       return MC_INVALID_IN_BUF;
+               break;
+
        default:
                return MC_INVALID_IN_BUF;
        }
+
        LOGD("codec_config : %d, sync_flag : %d, slice : %d", codec_config, sync_flag, slice);
 
        mem_size = GST_ROUND_UP_4(size);
@@ -556,6 +581,7 @@ static int __mc_fill_venc_packet_with_output_buffer(mc_gst_core_t *core, void *d
                g_free(ext_mem);
                return MC_ERROR;
        }
+
        mcbuffer->packet = packet;
        mcbuffer->ext_mem = ext_mem;
 
@@ -1669,6 +1695,7 @@ static gboolean _mc_gst_vid_caps_new(mc_gst_core_t *core, mediacodec_codec_type_
                                NULL);
                }
                break;
+
        case MEDIACODEC_MPEG4:
                if (core->encoder) {
                        gst_caps_set_simple(caps,
@@ -1683,13 +1710,14 @@ static gboolean _mc_gst_vid_caps_new(mc_gst_core_t *core, mediacodec_codec_type_
                                NULL);
                }
                break;
+
        case MEDIACODEC_H264:
                if (core->encoder) {
                        gst_caps_set_simple(caps,
                                "format", G_TYPE_STRING, port_def->info.video.format,
                                NULL);
                        g_object_set(GST_OBJECT(core->codec), "byte-stream", TRUE, NULL);
-                       LOGE("format : %s", port_def->info.video.format);
+                       LOGI("format[%s]", port_def->info.video.format);
                } else {
                        gst_caps_set_simple(caps,
                                "parsed", G_TYPE_BOOLEAN, TRUE,  /* FIXME different from sw */
@@ -1699,6 +1727,16 @@ static gboolean _mc_gst_vid_caps_new(mc_gst_core_t *core, mediacodec_codec_type_
                                NULL);
                }
                break;
+
+       case MEDIACODEC_MJPEG:
+               if (core->encoder) {
+                       gst_caps_set_simple(caps,
+                               "format", G_TYPE_STRING, port_def->info.video.format,
+                               NULL);
+                       LOGI("format[%s]", port_def->info.video.format);
+               }
+               break;
+
        default:
                break;
        }
@@ -1731,7 +1769,9 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                else
                        core->vtable = adec_aac_vtable;
                break;
+
        case MEDIACODEC_AAC_HE:
+               /* fall through */
        case MEDIACODEC_AAC_HE_PS:
                if (encoder) {
                        LOGD("[MC_NOT_SUPPORTED] he-aac-v12 encoder is not supported yet!!!");
@@ -1740,6 +1780,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                        core->vtable = adec_aacv12_vtable;
                }
                break;
+
        case MEDIACODEC_MP3:
                if (encoder) {
                        LOGD("[MC_NOT_SUPPORTED] mp3 encoder is not supported yet!!!");
@@ -1748,6 +1789,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                        core->vtable = adec_mp3_vtable;
                }
                break;
+
        case MEDIACODEC_AMR_NB:
                LOGD("amrnb vtable");
                if (encoder)
@@ -1755,6 +1797,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                else
                        core->vtable = adec_amrnb_vtable;
                break;
+
        case MEDIACODEC_AMR_WB:
                LOGD("amrwb vtable - Only support decoder");
                if (encoder) {
@@ -1764,6 +1807,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                        core->vtable = adec_amrwb_vtable;
                }
                break;
+
        case MEDIACODEC_VORBIS:
                LOGD("vorbis vtable");
                if (encoder)
@@ -1771,6 +1815,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                else
                        core->vtable = adec_vorbis_vtable;
                break;
+
        case MEDIACODEC_FLAC:
                LOGD("flac vtable");
                if (encoder) {
@@ -1780,6 +1825,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                        core->vtable = adec_flac_vtable;
                }
                break;
+
        case MEDIACODEC_OPUS:
                LOGD("opus vtable");
                if (encoder)
@@ -1788,8 +1834,11 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                        core->vtable = adec_vtable;
                break;
        case MEDIACODEC_WMAV1:
+               /* fall through */
        case MEDIACODEC_WMAV2:
+               /* fall through */
        case MEDIACODEC_WMAPRO:
+               /* fall through */
        case MEDIACODEC_WMALSL:
                LOGD("wma(V1 / V2 / LSL / PRO) vtable");
                if (encoder) {
@@ -1799,6 +1848,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                        core->vtable = adec_wma_vtable;
                }
                break;
+
        case MEDIACODEC_H263:
                LOGD("h263 vtable");
                if (encoder) {
@@ -1810,6 +1860,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                                core->vtable = vdec_h263_sw_vtable;
                }
                break;
+
        case MEDIACODEC_MPEG4:
                LOGD("mpeg4 vtable");
                if (encoder)
@@ -1817,6 +1868,7 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                else
                        core->vtable = is_hw ? vdec_mpeg4_hw_vtable : vdec_mpeg4_sw_vtable;
                break;
+
        case MEDIACODEC_H264:
                LOGD("h264 vtable");
                if (encoder) {
@@ -1828,6 +1880,19 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                                core->vtable = vdec_h264_sw_vtable;
                }
                break;
+
+       case MEDIACODEC_MJPEG:
+               LOGD("mjpeg vtable");
+               if (encoder) {
+                       core->vtable = is_hw ? venc_mjpeg_hw_vtable : venc_mjpeg_sw_vtable;
+               } else {
+                       if (is_hw)
+                               core->vtable = vdec_mjpeg_hw_vtable;
+                       else
+                               core->vtable = vdec_mjpeg_sw_vtable;
+               }
+               break;
+
        default:
                break;
        }
@@ -3642,20 +3707,28 @@ int _mc_get_mime(mc_gst_core_t *core)
                else
                        mime = MEDIA_FORMAT_H264_SP;
                break;
+
        case MEDIACODEC_MPEG4:
                if (core->encoder)
                        mime = (core->is_hw) ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
                else
                        mime = MEDIA_FORMAT_MPEG4_SP;
-
                break;
+
        case MEDIACODEC_H263:
                if (core->encoder)
                        mime = (core->is_hw) ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
                else
                        mime = MEDIA_FORMAT_H263P;
+               break;
 
+       case MEDIACODEC_MJPEG:
+               if (core->encoder)
+                       mime = (core->is_hw) ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
+               else
+                       mime = MEDIA_FORMAT_MJPEG;
                break;
+
        case MEDIACODEC_AAC:
                if (core->encoder)
                        mime = MEDIA_FORMAT_PCM_F32LE;  /*FIXME need to change PCM supported by chipset */
@@ -3663,42 +3736,54 @@ int _mc_get_mime(mc_gst_core_t *core)
                        mime = MEDIA_FORMAT_AAC;
 
                break;
+
        case MEDIACODEC_AAC_HE:
                if (core->encoder)
                        mime = MEDIA_FORMAT_PCM_F32LE;  /* FIXME need to change PCM supported by chipset */
                else
                        mime = MEDIA_FORMAT_AAC_HE;
-
                break;
+
        case MEDIACODEC_AAC_HE_PS:
                break;
+
        case MEDIACODEC_MP3:
                mime = MEDIA_FORMAT_MP3;
                break;
+
        case MEDIACODEC_VORBIS:
                break;
+
        case MEDIACODEC_FLAC:
                break;
+
        case MEDIACODEC_WMAV1:
                break;
+
        case MEDIACODEC_WMAV2:
                break;
+
        case MEDIACODEC_WMAPRO:
                break;
+
        case MEDIACODEC_WMALSL:
                break;
+
        case MEDIACODEC_AMR_NB:
                mime = MEDIA_FORMAT_AMR_NB;
                break;
+
        case MEDIACODEC_AMR_WB:
                mime = MEDIA_FORMAT_AMR_WB;
                break;
+
        case MEDIACODEC_OPUS:
                if (core->encoder)
                        mime = MEDIA_FORMAT_OPUS;
                else
                        mime = MEDIA_FORMAT_PCM_S16LE;
                break;
+
        default:
                LOGE("NOT SUPPORTED!!!! 0x%x ", core->codec_id);
                break;
index 105f7e44e7498c0af15e09e6496f2b20f882e100..bff0de34e935c866de2d167c17b15984d142aeec 100644 (file)
@@ -133,7 +133,8 @@ struct _App {
        glong start;
        glong finish;
        glong process_time;
-       gint frame_count;
+       gint frame_count_output;
+       gint frame_count_input;
 
        gint codecid;
        gint flag;
@@ -290,21 +291,29 @@ void h264_extractor(App *app, guint8 **data, gint *size, gboolean *have_frame, g
                g_print("nal_unit_type : SPS\n");
                state |= MC_EXIST_SPS;
                break;
+
        case NAL_PICTURE_PARAMETER_SET:
                g_print("nal_unit_type : PPS\n");
                state |= MC_EXIST_PPS;
                break;
+
        case NAL_SLICE_IDR:
+               /* fall through */
        case NAL_SEI:
                g_print ("nal_unit_type : IDR\n");
                state |= MC_EXIST_IDR;
                break;
+
        case NAL_SLICE_NO_PARTITIONING:
+               /* fall through */
        case NAL_SLICE_PART_A:
+               /* fall through */
        case NAL_SLICE_PART_B:
+               /* fall through */
        case NAL_SLICE_PART_C:
                state |= MC_EXIST_SLICE;
                break;
+
        default:
                g_print ("nal_unit_type : %x", nal_unit_type);
                break;
@@ -435,6 +444,66 @@ void mpeg4_extractor(App * app, guint8 **data, gint *size, gboolean * have_frame
        *have_frame = TRUE;
 }
 
+void mjpeg_extractor(App * app, guint8 **data, gint *size, gboolean * have_frame, gboolean *codec_data)
+{
+       size_t offset = 0;
+       size_t marker_len = 0;
+       size_t max = (size_t)(app->length - app->offset);
+       unsigned char marker[2] = {0, };
+       unsigned char num_comp = 0;
+       unsigned char *pMJPEG = app->data + app->offset;
+
+       if (app->offset == 0)
+               g_print("=== START(size:%d) ===\n", app->length);
+
+       if (pMJPEG[0] != 0xff || pMJPEG[1] != 0xd8) {
+               g_print("invalid SOI(StartOfImage,0xffd8) vs [0x%02x%02x]\n", pMJPEG[0], pMJPEG[1]);
+               *have_frame = FALSE;
+               return;
+       }
+
+       *data = pMJPEG;
+
+       /* set offset after SOI(StartOfImage) marker(2bytes) */
+       offset = 2;
+
+       while (offset < max) {
+               marker[0] = pMJPEG[offset++];
+               marker[1] = pMJPEG[offset++];
+
+               marker_len = (pMJPEG[offset] * 256) + pMJPEG[offset+1];
+
+               if (marker[0] == 0xff && marker[1] == 0xda) {
+                       /* set offset after Ls(ScanHeaderLength) */
+                       offset += 2;
+
+                       g_print("Found SOS(StartOfScan, 0xffda): Ls(ScanHeaderLength) %4zu, ", marker_len);
+
+                       /* Ns: Number of image components */
+                       num_comp = pMJPEG[offset++];
+
+                       g_print("Ns(Number of image components) %u\n", num_comp);
+
+                       /* set offset after scan header: (Ls * Ns) + 1(Ss) + 1(Se) + 0.5(Ah) + 0.5(Al) */
+                       offset += (marker_len * num_comp) + 3;
+
+                       while (offset < max) {
+                               if (pMJPEG[offset++] == 0xff && pMJPEG[offset++] == 0xd9) {
+                                       g_print("Found EOI(EndOfImage, 0xffd9): offset[%zu]\n", offset);
+                                       goto _DONE;
+                               }
+                       }
+               }
+
+               offset += marker_len;
+       }
+
+_DONE:
+       *size = offset;
+       app->offset += offset;
+       *have_frame = TRUE;
+}
+
 /**
   * Extract Input data for AMR-NB/WB decoder
   *  - AMR-NB  : mime type ("audio/AMR")          /   8Khz / 1 ch / 16 bits
@@ -739,17 +808,16 @@ void mp3dec_extractor(App *app, guint8 **data, int *size, gboolean *have_frame,
  app->offset += *size;
  }
  */
-int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_format_mimetype_e *codec_mime)
+int _configure(App *app, int codecid, int flag, gboolean *hardware, media_format_mimetype_e *codec_mime)
 {
-       gboolean encoder;
        media_format_mimetype_e mime = 0;
-       encoder = GET_IS_ENCODER(flag) ? 1 : 0;
+
+       app->is_encoder = GET_IS_ENCODER(flag);
        *hardware = GET_IS_HW(flag) ? 1 : 0;
-       app->is_encoder = encoder;
 
        switch (codecid) {
        case MEDIACODEC_H264:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = yuv_extractor;
                        mime = *hardware ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
                        *codec_mime = MEDIA_FORMAT_H264_SP;
@@ -758,8 +826,9 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_H264_SP;
                }
                break;
+
        case MEDIACODEC_MPEG4:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = yuv_extractor;
                        mime = *hardware ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
                        *codec_mime = MEDIA_FORMAT_MPEG4_SP;
@@ -768,8 +837,9 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_MPEG4_SP;
                }
                break;
+
        case MEDIACODEC_H263:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = yuv_extractor;
                        mime = *hardware ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
                        *codec_mime = MEDIA_FORMAT_H263;
@@ -778,8 +848,20 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_H263;
                }
                break;
+
+       case MEDIACODEC_MJPEG:
+               if (app->is_encoder) {
+                       extractor = yuv_extractor;
+                       mime = *hardware ? MEDIA_FORMAT_NV12 : MEDIA_FORMAT_I420;
+                       *codec_mime = MEDIA_FORMAT_MJPEG;
+               } else {
+                       extractor = mjpeg_extractor;
+                       mime = MEDIA_FORMAT_MJPEG;
+               }
+               break;
+
        case MEDIACODEC_AAC:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = aacenc_extractor;
                        mime = MEDIA_FORMAT_PCM_F32LE;  /* FIXME need to check according to verdor */
                        *codec_mime = MEDIA_FORMAT_AAC;
@@ -788,33 +870,43 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_AAC;
                }
                break;
+
        case MEDIACODEC_AAC_HE:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = aacenc_extractor;
                        mime = MEDIA_FORMAT_PCM_F32LE;  /* FIXME need to check according to verdor */
                        *codec_mime = MEDIA_FORMAT_AAC_HE;
                }
                break;
+
        case MEDIACODEC_AAC_HE_PS:
                break;
+
        case MEDIACODEC_MP3:
                extractor = mp3dec_extractor;
                mime = MEDIA_FORMAT_MP3;
                break;
+
        case MEDIACODEC_VORBIS:
                break;
+
        case MEDIACODEC_FLAC:
                break;
+
        case MEDIACODEC_WMAV1:
                break;
+
        case MEDIACODEC_WMAV2:
                break;
+
        case MEDIACODEC_WMAPRO:
                break;
+
        case MEDIACODEC_WMALSL:
                break;
+
        case MEDIACODEC_AMR_NB:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = amrenc_extractor;
                        mime = MEDIA_FORMAT_PCM_F32LE;  /* FIXME need to check according to verdor */
                        *codec_mime = MEDIA_FORMAT_AMR_NB;
@@ -824,8 +916,9 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_AMR_NB;
                }
                break;
+
        case MEDIACODEC_AMR_WB:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = amrenc_extractor;
                        mime = MEDIA_FORMAT_PCM_F32LE;  /* FIXME need to check according to verdor */
                        app->is_amr_nb = FALSE;
@@ -834,8 +927,9 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_AMR_WB;
                }
                break;
+
        case MEDIACODEC_OPUS:
-               if (encoder) {
+               if (app->is_encoder) {
                        extractor = opusenc_extractor;
                        mime = MEDIA_FORMAT_OPUS;       /* FIXME need to check according to verdor */
                        *codec_mime = MEDIA_FORMAT_OPUS;
@@ -850,6 +944,7 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                LOGE("NOT SUPPORTED!!!!");
                break;
        }
+
        return mime;
 }
 
@@ -937,6 +1032,7 @@ void _mediacodec_process_input(App *app)
 
                                }
                        }
+
                        mc_hex_dump("inbuf", tmp, 48);
 
                        ret = mediacodec_process_input(app->mc_handle[0], pkt, 1000);
@@ -963,21 +1059,24 @@ gboolean read_data(App *app)
        gint stride_width;
 
        if (app->offset == 0) {
-               app->frame_count = 0;
+               app->frame_count_input = 0;
+               app->frame_count_output = 0;
                app->start = clock();
        }
 
        g_print("----------read data------------\n");
        extractor(app, &tmp, &read, &have_frame, &codec_config);
 
-       if (app->offset >= app->length - 4) {
+       if (app->mime != MEDIA_FORMAT_MJPEG &&
+               (app->offset >= app->length - 4)) {
                /* EOS */
-               g_print("EOS\n");
+               g_print("EOS: frame count[%d]\n", app->frame_count_input);
                app->finish = clock();
-               g_print("Average FPS = %3.3f\n", ((double)app->frame_count*1000000/(app->finish - app->start)));
+               g_print("Average FPS = %3.3f\n", ((double)app->frame_count_output*1000000/(app->finish - app->start)));
                g_print("---------------------------\n");
                return FALSE;
        }
+
        g_print("length : %d, offset : %d\n", app->length, app->offset);
 
        if (app->offset + len > app->length)
@@ -1053,15 +1152,25 @@ gboolean read_data(App *app)
 
                        }
                }
+
                mc_hex_dump("inbuf", tmp, 48);
 
                ret = mediacodec_process_input(app->mc_handle[0], pkt, 0);
                if (ret != MEDIACODEC_ERROR_NONE)
                        return FALSE;
 
+               app->frame_count_input++;
                pts += ES_DEFAULT_VIDEO_PTS_OFFSET;
        }
 
+       g_print("[INPUT_BUFFER] frame count[%d]\n", app->frame_count_input);
+
+       if (app->mime == MEDIA_FORMAT_MJPEG &&
+               app->offset >= app->length) {
+               g_print("=== EOS: total input count[%d] ===\n", app->frame_count_input);
+               return FALSE;
+       }
+
        return TRUE;
 }
 
@@ -1211,7 +1320,7 @@ void _audio_outbuf_available_cb(media_packet_h pkt, void *user_data)
        if (app->enable_dump)
                output_dump(app, out_pkt);
 
-       app->frame_count++;
+       app->frame_count_output++;
        app->fbd++;
 
 
@@ -1243,7 +1352,7 @@ void _video_outbuf_available_cb(media_packet_h pkt, void *user_data)
        if (app->enable_dump)
                decoder_output_dump(app, out_pkt);
 
-       app->frame_count++;
+       app->frame_count_output++;
        app->fbd++;
 
 
@@ -1278,6 +1387,7 @@ void _mediacodec_outbuf_available_cb(media_packet_h pkt, void *user_data)
                else
                        output_dump(app, out_pkt);
        }
+
 #ifdef TIZEN_FEATURE_INTEGRATION
        if (app->enable_muxer) {
                if (mediamuxer_write_sample(app->muxer, app->track, out_pkt) != MEDIAMUXER_ERROR_NONE)
@@ -1285,15 +1395,15 @@ void _mediacodec_outbuf_available_cb(media_packet_h pkt, void *user_data)
                g_print("write sample!!!\n");
        }
 #endif
-       app->frame_count++;
-       app->fbd++;
 
+       app->frame_count_output++;
+       app->fbd++;
 
        g_mutex_unlock(&app->lock);
 
        media_packet_unref(out_pkt);
-       out_pkt = NULL;
-       g_print("done\n");
+
+       g_print("[OUTPUT_BUFFER] done - frame count[%d]\n", app->frame_count_output);
 
        return;
 }
@@ -1434,6 +1544,7 @@ void _mediacodec_prepare(App *app, gboolean frame_all)
                if (ret  != MEDIACODEC_ERROR_NONE)
                        g_print("mediacodec_configure failed\n");
                break;
+
        case VIDEO_ENC:
                media_format_set_video_mime(fmt, app->mime);
                media_format_set_video_width(fmt, app->width);
@@ -1453,6 +1564,7 @@ void _mediacodec_prepare(App *app, gboolean frame_all)
                        g_print("mediacodec_configure failed\n");
                media_format_unref(codec_format);
                break;
+
        case AUDIO_DEC:
                media_format_set_audio_mime(fmt, app->mime);
                media_format_set_audio_channel(fmt, app->channel);
@@ -1463,6 +1575,7 @@ void _mediacodec_prepare(App *app, gboolean frame_all)
                if (ret  != MEDIACODEC_ERROR_NONE)
                        g_print("mediacodec_configure failed\n");
                break;
+
        case AUDIO_ENC:
                media_format_set_audio_mime(fmt, app->mime);
                media_format_set_audio_channel(fmt, app->channel);
@@ -1482,6 +1595,7 @@ void _mediacodec_prepare(App *app, gboolean frame_all)
                        g_print("mediacodec_set_configure failed\n");
                media_format_unref(codec_format);
                break;
+
        default:
                g_print("invaild type\n");
                break;
@@ -2352,7 +2466,7 @@ void decoder_output_dump(App *app, media_packet_h pkt)
        FILE *fp = NULL;
        int ret = 0;
 
-       g_snprintf(filename, MAX_STRING_LEN, "/tmp/dec_output_dump_%d_%d.yuv", app->width, app->height);
+       g_snprintf(filename, MAX_STRING_LEN, "/home/owner/media/dec_output_dump_%d_%d.yuv", app->width, app->height);
        fp = fopen(filename, "ab");
 
        media_packet_get_video_plane_data_ptr(pkt, 0, (void **)&temp);