]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
WIP add experimental vorbis codec
authorSeven Du <dujinfang@gmail.com>
Fri, 13 Mar 2015 18:57:29 +0000 (02:57 +0800)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:47:12 +0000 (12:47 -0500)
made it like a codec mod so we can share the same code in case opus is fully supported in webm
add -lvorbis -lvorbisenc to Makefile
the audio is still completely silence, hope we can find out why

src/mod/formats/mod_webm/mod_vorbis.c [new file with mode: 0644]
src/mod/formats/mod_webm/mod_webm.cpp
src/mod/formats/mod_webm/mod_webm.h [new file with mode: 0644]

diff --git a/src/mod/formats/mod_webm/mod_vorbis.c b/src/mod/formats/mod_webm/mod_vorbis.c
new file mode 100644 (file)
index 0000000..2f7dc8d
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2015, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Seven Du <dujinfang@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Seven Du <dujinfang@gmail.com>
+ *
+ *
+ * mod_vorbis.c -- Vorbis Audio Codec
+ *
+ */
+
+#include <switch.h>
+#include <vorbis/vorbisenc.h>
+
+// SWITCH_MODULE_LOAD_FUNCTION(mod_vorbis_load);
+// SWITCH_MODULE_DEFINITION(mod_vorbis, mod_vorbis_load, NULL, NULL);
+
+#define SCC_GET_CODEC_PRIVATE SCC_VIDEO_BANDWIDTH
+
+typedef struct vorbis_context_s {
+       ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
+       ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
+       ogg_packet       op; /* one raw packet of data for decode */
+       vorbis_info      vi; /* struct that stores all the static vorbis bitstream settings */
+       vorbis_comment   vc; /* struct that stores all the user comments */
+       vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+       vorbis_block     vb; /* local working space for packet->PCM decode */
+
+       ogg_packet header;
+       ogg_packet header_comm;
+       ogg_packet header_code;
+
+       uint8_t *codec_private_data;
+       uint16_t codec_private_data_len;
+} vorbis_context_t;
+
+static void xiph_lacing(uint x, uint8_t **buffer)
+{
+       uint8_t *p = *buffer;
+
+       while (x >= 255) {
+               *p++ = 255;
+               x -= 255;
+       }
+
+       *p++ = x;
+       *buffer = p;
+}
+
+static switch_status_t switch_vorbis_control(switch_codec_t *codec,
+                                                                                 switch_codec_control_command_t cmd,
+                                                                                 switch_codec_control_type_t ctype,
+                                                                                 void *cmd_data,
+                                                                                 switch_codec_control_type_t *rtype,
+                                                                                 void **ret_data)
+{
+       vorbis_context_t *context = (vorbis_context_t *)codec->private_info;
+
+       switch(cmd) {
+       case SCC_GET_CODEC_PRIVATE:
+       {
+               uint32_t len = 0;
+               uint8_t *p;
+
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%ld %ld %ld\n",
+                       context->header.bytes, context->header_comm.bytes, context->header_code.bytes);
+
+               len = context->header.bytes + context->header_comm.bytes + context->header_code.bytes;
+               len += 20;
+
+               if (!context->codec_private_data) {
+                       // uint16_t size;
+
+                       p = context->codec_private_data = switch_core_alloc(codec->memory_pool, len);
+                       switch_assert(p);
+
+#if 0
+                       // ffmpeg also can decode this one
+                       size = context->header.bytes;
+                       *(uint16_t *)p = htons(size);
+                       p+=2;
+                       memcpy(p, context->header.packet, context->header.bytes);
+                       p += context->header.bytes;
+
+                       size = context->header_comm.bytes;
+                       *(uint16_t *)p = htons(size);
+                       p+=2;
+                       memcpy(p, context->header_comm.packet, context->header_comm.bytes);
+                       p += context->header_comm.bytes;
+
+                       size = context->header_code.bytes;
+                       *(uint16_t *)p = htons(size);
+                       p+=2;
+                       memcpy(p, context->header_code.packet, context->header_code.bytes);
+                       p += context->header_code.bytes;
+#else
+                       // SPEC
+                       // http://www.matroska.org/technical/specs/codecid/index.html
+                       // A_VORBIS
+                       *p++ = 2;
+                       xiph_lacing(context->header.bytes, &p);
+                       xiph_lacing(context->header_comm.bytes, &p);
+                       memcpy(p, context->header.packet, context->header.bytes);
+                       p += context->header.bytes;
+                       memcpy(p, context->header_comm.packet, context->header_comm.bytes);
+                       p += context->header_comm.bytes;
+                       memcpy(p, context->header_code.packet, context->header_code.bytes);
+                       p += context->header_code.bytes;
+#endif
+
+                       context->codec_private_data_len = p - context->codec_private_data;
+               }
+
+               switch_assert(context->codec_private_data_len < 20000);
+
+               *(int16_t *)cmd_data = context->codec_private_data_len;
+               *ret_data = (void *)context->codec_private_data;
+       }
+       break;
+       default: break;
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_vorbis_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
+{
+       int encoding, decoding;
+       vorbis_context_t *context;
+       int ret = 0;
+
+       encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+       decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+       if (!(encoding || decoding)) {
+               return SWITCH_STATUS_FALSE;
+       } else {
+               if (codec->fmtp_in) {
+                       codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
+               }
+       }
+
+       context = switch_core_alloc(codec->memory_pool, sizeof(*context));
+       memset(context, 0, sizeof(*context));
+       codec->private_info = context;
+
+       vorbis_info_init(&context->vi);
+
+       // https://xiph.org/vorbis/doc/vorbisenc/examples.html
+       ret=vorbis_encode_init_vbr(&context->vi,
+               codec->implementation->number_of_channels,
+               codec->implementation->actual_samples_per_second, 0.4);
+
+#if 0
+       ret = vorbis_encode_init(&context->vi,
+               codec->implementation->number_of_channels,
+               codec->implementation->actual_samples_per_second,
+               -1,128000,-1);
+#endif
+
+       if (ret) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VORBIS codec init error, ret = %d\n", ret);
+               goto error;
+       }
+
+       vorbis_comment_init(&context->vc);
+       vorbis_comment_add_tag(&context->vc, "ENCODER", "FreeSWITCH");
+
+       ret = vorbis_analysis_init(&context->vd, &context->vi);
+       if (ret) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VORBIS analysis init error, ret = %d\n", ret);
+               goto error;
+       }
+
+       ret = vorbis_block_init(&context->vd, &context->vb);
+       if (ret) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VORBIS block init error, ret = %d\n", ret);
+               goto error;
+       }
+
+       // headers
+       vorbis_analysis_headerout(&context->vd, &context->vc, &context->header, &context->header_comm, &context->header_code);
+
+       ogg_stream_init(&context->os, rand());
+
+       {//hack so we can use the codec control
+               switch_codec_implementation_t **impl = (switch_codec_implementation_t **)&codec->implementation;
+               (*impl)->codec_control = switch_vorbis_control;
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+
+error:
+       vorbis_block_clear(&context->vb);
+       vorbis_dsp_clear(&context->vd);
+       vorbis_comment_clear(&context->vc);
+       vorbis_info_clear(&context->vi);
+
+       return SWITCH_STATUS_GENERR;
+}
+
+static switch_status_t switch_vorbis_encode(switch_codec_t *codec,
+                                                                                 switch_codec_t *other_codec,
+                                                                                 void *decoded_data,
+                                                                                 uint32_t decoded_data_len,
+                                                                                 uint32_t decoded_rate, void *encoded_data, uint32_t *encoded_data_len, uint32_t *encoded_rate,
+                                                                                 unsigned int *flag)
+{
+       vorbis_context_t *context = (vorbis_context_t *)codec->private_info;
+       int i;
+       uint32_t len = 0;
+    uint16_t *data = (uint16_t *)decoded_data;
+       int channels = codec->implementation->number_of_channels;
+    float **buffer = vorbis_analysis_buffer(&context->vd, decoded_data_len);
+
+       // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%u\n", decoded_data_len);
+
+       for (i = 0; i < decoded_data_len * channels; i += channels) {
+               buffer[0][i] = *(data + i) / 32768.f;
+               if (channels > 1) {
+                       buffer[1][i] = *(data + i + 1) / 32768.f;
+               }
+       }
+
+       vorbis_analysis_wrote(&context->vd, decoded_data_len);
+
+       while (vorbis_analysis_blockout(&context->vd, &context->vb) == 1) {
+               /* analysis, assume we want to use bitrate management */
+               vorbis_analysis(&context->vb, NULL);
+               vorbis_bitrate_addblock(&context->vb);
+
+               while (vorbis_bitrate_flushpacket(&context->vd, &context->op)){
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "got %ld bytes pts: %lld\n", context->op.bytes, context->op.granulepos);
+
+                       if (len + context->op.bytes > *encoded_data_len) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "buffer overflow %u\n", *encoded_data_len);
+                               break;
+                       }
+
+                       memcpy((uint8_t *)decoded_data + len, context->op.packet, context->op.bytes);
+                       len += context->op.bytes;
+               }
+       }
+
+       *encoded_data_len = len;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t switch_vorbis_decode(switch_codec_t *codec,
+                                                                                 switch_codec_t *other_codec,
+                                                                                 void *encoded_data,
+                                                                                 uint32_t encoded_data_len,
+                                                                                 uint32_t encoded_rate, void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate,
+                                                                                 unsigned int *flag)
+{
+       return SWITCH_STATUS_FALSE;
+}
+
+static switch_status_t switch_vorbis_destroy(switch_codec_t *codec)
+{
+       vorbis_context_t *context = (vorbis_context_t *)codec->private_info;
+
+       vorbis_block_clear(&context->vb);
+       vorbis_dsp_clear(&context->vd);
+       vorbis_comment_clear(&context->vc);
+       vorbis_info_clear(&context->vi);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_vorbis_load)
+{
+       switch_codec_interface_t *codec_interface;
+       int mpf = 20000, spf = 160, bpf = 320, counta, countb;
+       int rates[] = {0, 8000, 44100, 48000, 88200, 96000, 176400, 192000};
+       switch_payload_t ianacode[4] = { 0, 99, 99, 99 };
+
+       /* connect my internal structure to the blank pointer passed to me */
+       // *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+       SWITCH_ADD_CODEC(codec_interface, "VORBIS");
+
+       for (counta = 1; counta <= 3; counta++) {
+               for (countb = 1; countb > 0; countb--) {
+                       switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO,    /* enumeration defining the type of the codec */
+                                                                                                ianacode[counta],      /* the IANA code number */
+                                                                                                "VORBIS",      /* the IANA code name */
+                                                                                                NULL,  /* default fmtp to send (can be overridden by the init function) */
+                                                                                                rates[counta], /* samples transferred per second */
+                                                                                                rates[counta], /* actual samples transferred per second */
+                                                                                                0,     /* bits transferred per second */
+                                                                                                mpf * countb,  /* number of microseconds per frame */
+                                                                                                spf * countb,  /* number of samples per frame */
+                                                                                                bpf * countb,  /* number of bytes per frame decompressed */
+                                                                                                0,     /* number of bytes per frame compressed */
+                                                                                                1,     /* number of channels represented */
+                                                                                                1,     /* number of frames per network packet */
+                                                                                                switch_vorbis_init,    /* function to initialize a codec handle using this implementation */
+                                                                                                switch_vorbis_encode,  /* function to encode raw data into encoded data */
+                                                                                                switch_vorbis_decode,  /* function to decode encoded data into raw data */
+                                                                                                switch_vorbis_destroy);        /* deinitalize a codec handle using this implementation */
+               }
+               spf = spf * 2;
+       }
+
+       for (counta = 1; counta <= 3; counta++) {
+               for (countb = 1; countb > 0; countb--) {
+                       switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO,    /* enumeration defining the type of the codec */
+                                                                                                ianacode[counta],      /* the IANA code number */
+                                                                                                "vorbis",      /* the IANA code name */
+                                                                                                NULL,  /* default fmtp to send (can be overridden by the init function) */
+                                                                                                rates[counta], /* samples transferred per second */
+                                                                                                rates[counta], /* actual samples transferred per second */
+                                                                                                0,     /* bits transferred per second */
+                                                                                                mpf * countb,  /* number of microseconds per frame */
+                                                                                                spf * countb,  /* number of samples per frame */
+                                                                                                bpf * countb,  /* number of bytes per frame decompressed */
+                                                                                                0,     /* number of bytes per frame compressed */
+                                                                                                2,     /* number of channels represented */
+                                                                                                1,     /* number of frames per network packet */
+                                                                                                switch_vorbis_init,    /* function to initialize a codec handle using this implementation */
+                                                                                                switch_vorbis_encode,  /* function to encode raw data into encoded data */
+                                                                                                switch_vorbis_decode,  /* function to decode encoded data into raw data */
+                                                                                                switch_vorbis_destroy);        /* deinitalize a codec handle using this implementation */
+               }
+               spf = spf * 2;
+       }
+
+       /* indicate that the module should continue to be loaded */
+       return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
index 6013fc7829c7e93122852e38e9bdfdab2517eae0..689b5e091493b17b285d0efc249f25fe150f989f 100644 (file)
@@ -37,6 +37,7 @@
 
 // using mkvmuxer::int64;
 // using mkvmuxer::uint64;
+#include "mod_webm.h"
 
 #ifdef _MSC_VER
 // Disable MSVC warnings that suggest making code non-portable.
@@ -49,8 +50,8 @@ SWITCH_MODULE_DEFINITION(mod_webm, mod_webm_load, NULL, NULL);
 #define IS_VP8_KEY_FRAME(byte) ((((byte) & 0x01) ^ 0x01) ? true : false)
 #define IS_VP9_KEY_FRAME(byte) (((byte) & 0x01) ? true : false)
 
-#define AUDIO_CODEC "OPUS"
-// #define AUDIO_CODEC "VORBIS"
+// #define AUDIO_CODEC "OPUS"
+#define AUDIO_CODEC "VORBIS"
 
 struct webm_file_context {
        switch_memory_pool_t *pool;
@@ -190,6 +191,14 @@ static switch_status_t webm_file_open(switch_file_handle_t *handle, const char *
                }
        }
 
+       if (!strcmp(AUDIO_CODEC, "VORBIS")) {
+               uint16_t size = 0;
+               uint8_t *codec_private_data = NULL;
+               switch_core_codec_control(&context->audio_codec, SCC_GET_CODEC_PRIVATE, SCCT_INT, (void *)&size, NULL, (void **)&codec_private_data);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "======codec_private_data size: %d data: %p\n", size, codec_private_data);
+               context->audio->SetCodecPrivate(codec_private_data, size);
+       }
+
        if (1) { // for better quality?
                int bw = 4096;
                switch_core_codec_control(&context->video_codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, (void *)&bw, NULL, NULL);
@@ -474,6 +483,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_webm_load)
        file_interface->file_set_string = webm_file_set_string;
        file_interface->file_get_string = webm_file_get_string;
 
+       mod_vorbis_load(module_interface, pool);
+
        /* indicate that the module should continue to be loaded */
        return SWITCH_STATUS_SUCCESS;
 }
diff --git a/src/mod/formats/mod_webm/mod_webm.h b/src/mod/formats/mod_webm/mod_webm.h
new file mode 100644 (file)
index 0000000..3224987
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2015, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Seven Du <dujinfang@gmail.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Seven Du <dujinfang@gmail.com>
+ *
+ *
+ * mod_webm.h -- Webm headers
+ *
+ */
+
+#include <switch.h>
+
+#define SCC_GET_CODEC_PRIVATE SCC_VIDEO_BANDWIDTH
+
+typedef struct vorbis_context_s vorbis_context_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_vorbis_load);
+
+#ifdef __cplusplus
+}
+#endif