enable opus encoder 58/230758/4 accepted/tizen/unified/20200422.215417 submit/tizen/20200422.081514
authorHyuntae Kim <ht1211.kim@samsung.com>
Tue, 14 Apr 2020 04:53:29 +0000 (13:53 +0900)
committerHyuntae Kim <ht1211.kim@samsung.com>
Wed, 22 Apr 2020 07:35:29 +0000 (16:35 +0900)
Change-Id: I140b4a6df22aed2af7ab65d64a2f58e8e9b7d9d9

CMakeLists.txt
include/media_codec_port.h
packaging/capi-media-codec.spec
src/media_codec_ini.c
src/media_codec_port.c
src/media_codec_port_gst.c
test/media_codec_test.c

index f2b72046b7a8f3e0dbde728c99c234b4e7e7a2d4..d39a08966ca30caf3d4931a563a075a9f63af108 100644 (file)
@@ -10,7 +10,7 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX})
 SET(INC_DIR include)
 INCLUDE_DIRECTORIES(${INC_DIR})
 
-SET(dependents "dlog glib-2.0 mm-common libtbm capi-media-tool iniparser gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 capi-system-info gstreamer-allocators-1.0")
+SET(dependents "dlog glib-2.0 mm-common libtbm capi-media-tool iniparser gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-pbutils-1.0 gstreamer-tag-1.0 capi-system-info gstreamer-allocators-1.0")
 SET(pc_dependents "capi-base-common capi-media-tool")
 IF(TIZEN_FEATURE_MM_RESOURCE_MANAGER)
 SET(dependents "${dependents} mm-resource-manager")
index 986bdd33e7efb8859d260d6f5d09aaac7e95eb5e..b34afa91665c014c4a1268784268daae0b8e727f 100644 (file)
@@ -104,6 +104,7 @@ typedef enum {
        WMAV2,
        WMAPRO,
        WMALSL,
+       OPUS,
        H261,
        H263,
        H264,
index 548d4c68c8af9f4dffbb746034eb15748a94bdf6..3da38bad4836da29f472377e5ac1bf84806197a6 100644 (file)
@@ -4,7 +4,7 @@
 
 Name:       capi-media-codec
 Summary:    A Media Codec library in Tizen Native API
-Version:    0.6.11
+Version:    0.6.12
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
@@ -19,6 +19,8 @@ BuildRequires:  pkgconfig(libtbm)
 BuildRequires:  pkgconfig(gstreamer-1.0)
 BuildRequires:  pkgconfig(gstreamer-plugins-base-1.0)
 BuildRequires:  pkgconfig(gstreamer-app-1.0)
+BuildRequires:  pkgconfig(gstreamer-pbutils-1.0)
+BuildRequires:  pkgconfig(gstreamer-tag-1.0)
 BuildRequires:  pkgconfig(capi-system-info)
 BuildRequires:  pkgconfig(iniparser)
 %if "%{tizen_profile_name}" != "tv"
@@ -28,6 +30,7 @@ BuildRequires:  pkgconfig(mm-resource-manager)
 #BuildRequires:  pkgconfig(capi-mediademuxer)
 #BuildRequires:  pkgconfig(capi-mediamuxer)
 
+
 %description
 A Media Codec library in Tizen Native API
 
index ce51083c74277bf763720885db9accbba3158677..35bc0b0f2f7bfb6bbf53e3b5b7e76b595c785d43 100644 (file)
@@ -71,6 +71,7 @@ static codec_list_t general_codec_list[] = {
        {"wmav1", MEDIACODEC_WMAV1},
        {"wmav2", MEDIACODEC_WMAV2},
        {"wmapro", MEDIACODEC_WMAPRO},
+       {"opus", MEDIACODEC_OPUS},
 };
 
 /* internal functions, macros here */
@@ -287,6 +288,9 @@ media_format_mimetype_e _mc_convert_media_format_str_to_int(char *sformat)
        } else if (!strcmp(sformat, "WMAPRO")) {
                iformat = MEDIA_FORMAT_WMAPRO;
                goto endf;
+       } else if (!strcmp(sformat, "OPUS")) {
+               iformat = MEDIA_FORMAT_OPUS;
+               goto endf;
        }
 
 endf:
index d78a1d467300048a465983d9278451f62ca52a60..70b5cc31e4ae10dc1641cba883278602b82b9112 100644 (file)
@@ -399,7 +399,7 @@ int mc_prepare(MMHandleType mediacodec)
                break;
 
        case MEDIACODEC_PORT_TYPE_GST:
-               mc_gst_prepare(mc_handle);
+               ret = mc_gst_prepare(mc_handle);
                break;
 
        default:
@@ -1047,6 +1047,8 @@ codec_type_e codec_type_to_simple_enumeration(mediacodec_codec_type_e media_code
                return VP9;
        case MEDIACODEC_VC1:
                return VC1;
+       case MEDIACODEC_OPUS:
+               return OPUS;
        default:
                return NONE;
        }
@@ -1111,6 +1113,8 @@ mediacodec_codec_type_e simple_to_codec_type_enumeration(codec_type_e codec_id)
                return MEDIACODEC_VP9;
        case VC1:
                return MEDIACODEC_VC1;
+       case OPUS:
+               return MEDIACODEC_OPUS;
        default:
                return NONE;
        }
@@ -1178,6 +1182,11 @@ gboolean _check_support_audio_info(mediacodec_codec_type_e codec_id, int sampler
                s_bit_depth = 32;       /* NOTE: avdec_flac surpports S32LE as format */
                break;
        }
+       case MEDIACODEC_OPUS:
+       {
+               s_bit_depth = 16;       /* NOTE: opusenc/ opusdec support S16LE as format according to opus specification*/
+               break;
+       }
        default:
                break;
        }
index bd2cf503924e1b9a0d1f4c613d32e6e66b77b45a..5f2078f558d0dcedfdcf0e978e931cb8a9e7790b 100644 (file)
@@ -26,6 +26,8 @@
 #include <gst/gst.h>
 #include <gst/gstelement.h>
 #include <gst/app/gstappsrc.h>
+#include <gst/pbutils/pbutils.h>
+#include <gst/tag/tag.h>
 
 /*
  * Internal Implementation
@@ -37,7 +39,7 @@ static media_packet_h _mc_get_input_buffer(mc_gst_core_t *core);
 
 static gboolean __mc_gst_init_gstreamer();
 static int _mc_output_media_packet_new(mc_gst_core_t *core, bool video, bool encoder, media_format_mimetype_e out_mime);
-static mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, gchar *factory_name);
+static mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, const gchar *factory_name);
 static mc_ret_e _mc_gst_destroy_pipeline(mc_gst_core_t *core);
 static void __mc_gst_buffer_add(GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data);
 static int __mc_output_buffer_finalize_cb(media_packet_h packet, int error_code, void *user_data);
@@ -172,6 +174,9 @@ int(*adec_flac_vtable[])() = {&__mc_fill_input_buffer_with_packet,
 int(*adec_wma_vtable[])() = {&__mc_fill_input_buffer_with_packet,                    /* WMA Decoder Vtable */
                                                        &__mc_fill_packet_with_output_buffer};
 
+int(*aenc_opus_vtable[])() =  {&__mc_fill_input_buffer_with_packet,                  /* Opus Encoder Vtable */
+                                                       &__mc_fill_aenc_packet_with_output_buffer};
+
 #define MEDIACODEC_ELEMENT_SET_STATE(x_element, x_state)                                          \
        do {                                                                                            \
                LOGD("setting state [%s:%d] to [%s]\n", #x_state, x_state, GST_ELEMENT_NAME(x_element)); \
@@ -238,12 +243,13 @@ static int __mc_fill_input_buffer_with_packet(mc_gst_core_t *core, media_packet_
                return MC_ERROR;
        }
 
-       if (buf_data != NULL) {
-               gst_buffer_append_memory(mcbuffer->buffer,
-                               gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, buf_data, buf_size, 0,
-                                       buf_size, mcbuffer, (GDestroyNotify)__mc_input_buffer_finalize_cb));
-               LOGD("packet data apended");
-       }
+       if (buf_data == NULL)
+               return MC_ERROR;
+
+       gst_buffer_append_memory(mcbuffer->buffer,
+               gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY, buf_data, buf_size, 0,
+                       buf_size, mcbuffer, (GDestroyNotify)__mc_input_buffer_finalize_cb));
+       LOGD("packet data apended");
 
        return ret;
 }
@@ -616,6 +622,9 @@ static int __mc_fill_aenc_packet_with_output_buffer(mc_gst_core_t *core, void *d
 
                        s = gst_caps_get_structure(peercaps, 0);
                        codec_data = gst_structure_get_value(s, "codec_data");
+                       if (codec_data  == NULL && gst_structure_has_field(s, "streamheader"))
+                               codec_data = gst_structure_get_value(s, "streamheader");
+
                        core->codec_data = GST_BUFFER(g_value_dup_boxed(codec_data));
                        gst_caps_unref(peercaps);
                }
@@ -817,6 +826,31 @@ int __mc_set_caps_streamheader(mc_gst_core_t *core, GstMCBuffer *mcbuffer, guint
                __mc_gst_caps_set_buffer_array(core->caps, "streamheader", header1, header2, NULL);
                gst_buffer_unref(header1);
                gst_buffer_unref(header2);
+       } else if (core->codec_id == MEDIACODEC_OPUS) {
+               const GstTagList *tags;
+               GstTagList *empty_tags = NULL;
+               GstBuffer *header, *comments;
+               guint8 *decoding_channel_mapping = NULL;
+               mc_gst_port_def_t *port_def = &core->ports[in_port_index]->port_def;
+
+               header = gst_codec_utils_opus_create_header(port_def->info.audio.samplerate,
+                       port_def->info.audio.channel,
+                       0, /* channel mapping family */
+                       1, /* stream count */
+                       0, /* coupled count */
+                       decoding_channel_mapping,
+                       0, /* FIXME: look ahead configured value */
+                       0);
+               tags = gst_tag_setter_get_tag_list(GST_TAG_SETTER(core->codec));
+               if (!tags)
+                       tags = empty_tags = gst_tag_list_new_empty();
+               comments = gst_tag_list_to_vorbiscomment_buffer(tags, (const guint8 *) "OpusTags",
+                       8, "Encoded with GStreamer opusenc");
+               core->caps = gst_codec_utils_opus_create_caps_from_header(header, comments);
+               if (empty_tags)
+                       gst_tag_list_unref(empty_tags);
+               gst_buffer_unref(header);
+               gst_buffer_unref(comments);
        } else {
                LOGE("Not support case of Stream header Caps");
        }
@@ -1143,6 +1177,7 @@ static int _mc_set_codec_data(mc_gst_core_t *core, GstMCBuffer *mcbuffer, bool c
                break;
        case MEDIACODEC_VORBIS:
        case MEDIACODEC_FLAC:
+       case MEDIACODEC_OPUS:
                if (codec_config) {
                        ret = __mc_set_caps_streamheader(core, mcbuffer, VORBIS_CODECDATA_SIZE);
                        if (ret != MC_ERROR_NONE)
@@ -1449,6 +1484,16 @@ GstCaps *_mc_gst_aud_caps_new(mc_gst_core_t *core, mediacodec_codec_type_e codec
                                NULL);
                }
                break;
+       case MEDIACODEC_OPUS:
+               if (core->encoder) {
+                       gst_caps_set_simple(caps,
+                               "format", G_TYPE_STRING, _mc_bit_to_string(port_def->info.audio.bit_depth),
+                               "layout", G_TYPE_STRING, "interleaved", NULL);
+               } else {
+                       LOGD("[MC_NOT_SUPPORTED] opus decoder is not supported yet!!!");
+                       return NULL;
+               }
+               break;
        default:
                break;
        }
@@ -1502,7 +1547,7 @@ GstCaps *_mc_gst_vid_caps_new(mc_gst_core_t *core, mediacodec_codec_type_e codec
                        LOGE("format : %s", port_def->info.video.format);
                } else {
                        gst_caps_set_simple(caps,
-                               "parsed", G_TYPE_BOOLEAN, TRUE,                                         /* FIXME different from sw */
+                               "parsed", G_TYPE_BOOLEAN, TRUE,  /* FIXME different from sw */
                                "alignment", G_TYPE_STRING, "au",
                                "stream-format", G_TYPE_STRING, "byte-stream",
                                "framerate", GST_TYPE_FRACTION, 30, 1,
@@ -1524,11 +1569,10 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
 
        switch (id) {
        case MEDIACODEC_AAC:
-               if (encoder) {
+               if (encoder)
                        core->vtable = aenc_aac_vtable;
-               } else {
+               else
                        core->vtable = adec_aac_vtable;
-               }
                break;
        case MEDIACODEC_AAC_HE:
        case MEDIACODEC_AAC_HE_PS:
@@ -1549,11 +1593,10 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                break;
        case MEDIACODEC_AMR_NB:
                LOGD("amrnb vtable");
-               if (encoder) {
+               if (encoder)
                        core->vtable = aenc_amrnb_vtable;
-               } else {
+               else
                        core->vtable = adec_amrnb_vtable;
-               }
                break;
        case MEDIACODEC_AMR_WB:
                LOGD("amrwb vtable - Only support decoder");
@@ -1566,12 +1609,10 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                break;
        case MEDIACODEC_VORBIS:
                LOGD("vorbis vtable");
-               if (encoder) {
-                       LOGD("[MC_NOT_SUPPORTED] vorbis encoder is not supported yet!!!");
+               if (encoder)
                        return MC_NOT_SUPPORTED;
-               } else {
+               else
                        core->vtable = adec_vorbis_vtable;
-               }
                break;
        case MEDIACODEC_FLAC:
                LOGD("flac vtable");
@@ -1582,6 +1623,13 @@ 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)
+                       core->vtable = aenc_opus_vtable;
+               else
+                       core->vtable = adec_vtable;
+               break;
        case MEDIACODEC_WMAV1:
        case MEDIACODEC_WMAV2:
        case MEDIACODEC_WMAPRO:
@@ -1599,31 +1647,28 @@ static int _mc_link_vtable(mc_gst_core_t *core, mediacodec_codec_type_e id, gboo
                if (encoder) {
                        core->vtable = is_hw ? venc_h263_hw_vtable : venc_h263_sw_vtable;
                } else {
-                       if (is_hw) {
+                       if (is_hw)
                                core->vtable = vdec_h263_hw_vtable;
-                       } else {
+                       else
                                core->vtable = vdec_h263_sw_vtable;
-                       }
                }
                break;
        case MEDIACODEC_MPEG4:
                LOGD("mpeg4 vtable");
-               if (encoder) {
+               if (encoder)
                        core->vtable = is_hw ? venc_mpeg4_hw_vtable : venc_mpeg4_sw_vtable;
-               } else {
+               else
                        core->vtable = is_hw ? vdec_mpeg4_hw_vtable : vdec_mpeg4_sw_vtable;
-               }
                break;
        case MEDIACODEC_H264:
                LOGD("h264 vtable");
                if (encoder) {
                        core->vtable = is_hw ? venc_h264_hw_vtable : venc_vtable;
                } else {
-                       if (is_hw) {
+                       if (is_hw)
                                core->vtable = vdec_h264_hw_vtable;
-                       } else {
+                       else
                                core->vtable = vdec_h264_sw_vtable;
-                       }
                }
                break;
        default:
@@ -2017,7 +2062,7 @@ ERROR:
        return FALSE;
 }
 
-mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, gchar *factory_name)
+mc_ret_e _mc_gst_create_pipeline(mc_gst_core_t *core, const gchar *factory_name)
 {
        GstBus *bus = NULL;
 
@@ -2703,6 +2748,11 @@ static GstMCBuffer *gst_mediacodec_buffer_new(mc_gst_core_t *core, media_packet_
 
        mcbuffer = (GstMCBuffer *)g_malloc0(sizeof(GstMCBuffer));
 
+       if (mcbuffer == NULL) {
+               LOGE("malloc fail");
+               return NULL;
+       }
+
        mcbuffer->buffer = gst_buffer_new();
        mcbuffer->buf_size = 0;
 
@@ -3355,8 +3405,14 @@ int _mc_get_mime(mc_gst_core_t *core)
        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!!!!");
+               LOGE("NOT SUPPORTED!!!! 0x%x ", core->codec_id);
                break;
        }
        return mime;
index dc46195bdf16d17f23901b2ab2842a23ba6c4024..bab398889c883916ec535eac0c32eab894e3b6d9 100644 (file)
@@ -47,6 +47,7 @@
 #define ADTS_HEADER_SIZE      7
 #define AMRNB_PCM_INPUT_SIZE      320
 #define AMRWB_PCM_INPUT_SIZE      640
+#define OPUS_PCM_INPUT_SIZE 4096
 
 #define CHECK_BIT(x, y) (((x) >> (y)) & 0x01)
 #define GET_IS_ENCODER(x) CHECK_BIT(x, 0)
@@ -568,6 +569,22 @@ void amrenc_extractor(App *app, guint8 **data, int *size, gboolean *have_frame,
        app->offset += *size;
 }
 
+void opusenc_extractor(App *app, guint8 **data, int *size, gboolean *have_frame, gboolean *codec_data)
+{
+       gint read_size = OPUS_PCM_INPUT_SIZE;
+       gint offset = app->length - app->offset;
+
+       *have_frame = TRUE;
+       *data = app->data + app->offset;
+
+       if (read_size >= offset)
+               *size = offset;
+       else
+               *size = read_size;
+
+       app->offset += *size;
+}
+
 /**
  * Extract Input data for AAC decoder
  * (case of (LC profile) ADTS format)
@@ -816,6 +833,18 @@ int  _configure(App *app, int codecid, int flag, gboolean *hardware, media_forma
                        mime = MEDIA_FORMAT_AMR_WB;
                }
                break;
+       case MEDIACODEC_OPUS:
+               if (encoder) {
+                       extractor = opusenc_extractor;
+                       mime = MEDIA_FORMAT_OPUS;       /* FIXME need to check according to verdor */
+                       *codec_mime = MEDIA_FORMAT_OPUS;
+                       app->is_amr_nb = FALSE;
+               } else {
+                       mime = MEDIA_FORMAT_OPUS;
+                       *codec_mime = MEDIA_FORMAT_OPUS;
+               }
+               break;
+
        default:
                LOGE("NOT SUPPORTED!!!!");
                break;
@@ -1438,6 +1467,7 @@ void _mediacodec_prepare(App *app, gboolean frame_all)
                media_format_set_audio_channel(fmt, app->channel);
                media_format_set_audio_samplerate(fmt, app->samplerate);
                media_format_set_audio_bit(fmt, app->bit);
+               media_format_set_audio_avg_bps(fmt, app->bitrate);
 
                media_format_create(&codec_format);
                media_format_set_audio_mime(codec_format, codec_mime);
@@ -2003,17 +2033,18 @@ void displaymenu(void)
                g_print("               WMAV2  =  13\n");
                g_print("               WMAPRO =  14\n");
                g_print("               WMALSL =  15\n");
+               g_print("               OPUS   =  16\n");
                g_print("               -------------------\n");
-               g_print("               H261   =  16\n");
-               g_print("               H263   =  17\n");
-               g_print("               H264   =  18\n");
-               g_print("               MJPEG  =  19\n");
-               g_print("               MPEG1  =  20\n");
-               g_print("               MPEG2  =  21\n");
-               g_print("               MPEG4  =  22\n");
-               g_print("               HEVC   =  23\n");
-               g_print("               VP8    =  24\n");
-               g_print("               VP9    =  25\n");
+               g_print("               H261   =  17\n");
+               g_print("               H263   =  18\n");
+               g_print("               H264   =  19\n");
+               g_print("               MJPEG  =  20\n");
+               g_print("               MPEG1  =  21\n");
+               g_print("               MPEG2  =  22\n");
+               g_print("               MPEG4  =  23\n");
+               g_print("               HEVC   =  24\n");
+               g_print("               VP8    =  25\n");
+               g_print("               VP9    =  26\n");
                g_print("               -------------------\n");
                g_print("*** Flags : Select Combination Number (e.g. DEOCDER + TYPE_SW = 10)\n");
                g_print("               CODEC : ENCODER =  1       DECODER =  2\n");
@@ -2063,9 +2094,12 @@ void interpret(char *cmd)
                break;
        case CURRENT_STATUS_SET_CODEC:
        {
-               gint ids[] = { 0x1010, 0x1020, 0x1030, 0x1040, 0x1041, 0x1050, 0x1060, 0x1061, 0x1062,
-                                               0x1070, 0x1080, 0x1090, 0x10A0, 0x10A1, 0x10A2, 0x10A3, 0x2010, 0x2020,
-                                               0x2030, 0x2040, 0x2050, 0x2060, 0x2070, 0x2080, 0x2090, 0x20A0, 0x20B0 };
+               gint ids[] = { 0x1010, 0x1020, 0x1030, 0x1040, 0x1041,
+                       0x1050, 0x1060, 0x1061, 0x1062, 0x1070,
+                       0x1080, 0x1090, 0x10A0, 0x10A1, 0x10A2,
+                       0x10A3, 0x10D0, 0x2010, 0x2020, 0x2030,
+                       0x2040, 0x2050, 0x2060, 0x2070, 0x2080,
+                       0x2090, 0x20A0, 0x20B0 };
 
                if (cnt == 0) {
                        gint n_sizes = G_N_ELEMENTS(ids);
@@ -2488,6 +2522,8 @@ const char* codec_type_to_string(mediacodec_codec_type_e media_codec_id)
                return "VP9";
        case MEDIACODEC_VC1:
                return "VC1";
+       case MEDIACODEC_OPUS:
+               return "OPUS";
        default:
                return "NONE";
        }