mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-14 08:05:37 +00:00
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:
parent
ca291c3f12
commit
29bddbd3fc
363
src/mod/formats/mod_webm/mod_vorbis.c
Normal file
363
src/mod/formats/mod_webm/mod_vorbis.c
Normal 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:
|
||||
*/
|
@ -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;
|
||||
}
|
||||
|
47
src/mod/formats/mod_webm/mod_webm.h
Normal file
47
src/mod/formats/mod_webm/mod_webm.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user