WIP add experimental vorbis codec

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
This commit is contained in:
Seven Du 2015-03-14 02:57:29 +08:00 committed by Michael Jerris
parent ca291c3f12
commit 29bddbd3fc
3 changed files with 423 additions and 2 deletions

View File

@ -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:
*/

View 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;
}

View File

@ -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