Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created September 5, 2016 09:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/6d8765f290a4e8ef6cbe01020b1d129e to your computer and use it in GitHub Desktop.
Save roxlu/6d8765f290a4e8ef6cbe01020b1d129e to your computer and use it in GitHub Desktop.
#include <AudioConverterFfmpeg.h>
namespace poly {
/* -------------------------------------------------------- */
static AVSampleFormat audiobitsize_to_avsampleformat(AudioBitSize bs, bool isInterleaved);
static uint64_t audiomode_to_avchannellayout(AudioMode mode);
static int audiomode_to_numchannels(AudioMode mode);
/* -------------------------------------------------------- */
AudioConverterFfmpeg::AudioConverterFfmpeg()
:listener(NULL)
,ctx(NULL)
,src_rate(-1)
,dst_rate(-1)
,dst_chanlayout(0)
,dst_format(AV_SAMPLE_FMT_NONE)
,dst_nchannels(-1)
,dst_nbytes_allocated(0)
,dst_linesize(-1)
,dst_max_samples(-1)
,dst_data(NULL)
{
}
AudioConverterFfmpeg::~AudioConverterFfmpeg() {
}
int AudioConverterFfmpeg::init(AudioSettings from, AudioSettings to, AudioConverterListener* lis) {
int r = 0;
if (NULL == lis) {
SX_ERROR("Listener is NULL.");
r = -1;
goto error;
}
convert_from = from;
convert_to = to;
listener = lis;
src_rate = audio_samplerate_get_int(from.samplerate);
dst_chanlayout = audiomode_to_avchannellayout(to.mode);
dst_rate = audio_samplerate_get_int(to.samplerate);
dst_format = audiobitsize_to_avsampleformat(to.bitsize, to.is_interleaved);
dst_nchannels = av_get_channel_layout_nb_channels(audiomode_to_avchannellayout(to.mode));
ctx = swr_alloc();
if (NULL == ctx) {
SX_ERROR("Failed to allocate the resample context.");
r = -2;
goto error;
}
av_opt_set_int(ctx, "in_channel_layout", audiomode_to_avchannellayout(from.mode), 0);
av_opt_set_int(ctx, "in_sample_rate", src_rate, 0);
av_opt_set_sample_fmt(ctx, "in_sample_fmt", audiobitsize_to_avsampleformat(from.bitsize, from.is_interleaved), 0);
av_opt_set_int(ctx, "out_channel_layout", dst_chanlayout, 0);
av_opt_set_int(ctx, "out_sample_rate", dst_rate, 0);
av_opt_set_sample_fmt(ctx, "out_sample_fmt", dst_format, 0);
if ( (r = swr_init(ctx)) < 0) {
SX_ERROR("Failed to initialize the resample context.");
r = -3;
goto error;
}
error:
if (r < 0) {
shutdown();
}
return r;
}
int AudioConverterFfmpeg::shutdown() {
int r = 0;
if (NULL != ctx) {
swr_free(&ctx);
ctx = NULL;
}
if (NULL != dst_data) {
free(dst_data);
dst_data = NULL;
}
src_rate = -1;
dst_rate = -1;
dst_format = AV_SAMPLE_FMT_NONE;
dst_nchannels = -1;
dst_nbytes_allocated = -1;
dst_linesize = -1;
dst_max_samples = -1;
return r;
}
int AudioConverterFfmpeg::convert(void* data, size_t nbytes, size_t nframes) {
if (NULL == data) {
SX_ERROR("data is NULL.");
return -1;
}
if (0 == nbytes) {
SX_ERROR("nbytes is 0.");
return -2;
}
if (0 == nframes) {
SX_ERROR("nframes is 0.");
return -3;
}
if (NULL == ctx) {
SX_ERROR("ctx is NULL.");
return -4;
}
int r = 0;
int delayed_samples = swr_get_delay(ctx, src_rate);
int num_dst_samples = av_rescale_rnd(delayed_samples + nframes, dst_rate, src_rate, AV_ROUND_UP);
int nbytes_needed = av_samples_get_buffer_size(NULL, dst_nchannels, nframes, dst_format, 1);
/* Allocate or reallocate the destination buffer. */
if (nbytes_needed > dst_nbytes_allocated) {
if (NULL == dst_data) {
dst_data = (uint8_t*)malloc(nbytes_needed);
if (NULL == dst_data) {
SX_ERROR("Failed to allocate the destination buffer of %d bytes.", nbytes_needed);
return -1;
}
}
else {
dst_data = (uint8_t*)realloc(dst_data, nbytes_needed);
if (NULL == dst_data) {
SX_ERROR("Failed to reallocate the destination buffer of %d bytes.", nbytes_needed);
return -2;
}
}
dst_nbytes_allocated = nbytes_needed;
}
r = swr_convert(ctx,
&dst_data,
num_dst_samples,
(const uint8_t**)data,
nframes
);
return r;
}
/* -------------------------------------------------------- */
static AVSampleFormat audiobitsize_to_avsampleformat(AudioBitSize bs, bool isInterleaved) {
if (false == isInterleaved) {
/* Planar */
switch (bs) {
case AUDIO_BITSIZE_S16: { return AV_SAMPLE_FMT_S16P; }
case AUDIO_BITSIZE_S32: { return AV_SAMPLE_FMT_S32P; }
case AUDIO_BITSIZE_F32: { return AV_SAMPLE_FMT_FLTP; }
default: {
SX_ERROR("Unhandled AudioBitSize; cannot convert to AVSampleFormat. (exiting).");
exit(EXIT_FAILURE);
}
};
}
else {
/* Non-Planar */
switch (bs) {
case AUDIO_BITSIZE_S16: { return AV_SAMPLE_FMT_S16; }
case AUDIO_BITSIZE_S32: { return AV_SAMPLE_FMT_S32; }
case AUDIO_BITSIZE_F32: { return AV_SAMPLE_FMT_FLT; }
default: {
SX_ERROR("Unhandled AudioBitSize; cannot convert to AVSampleFormat. (exiting).");
exit(EXIT_FAILURE);
}
}
}
}
static uint64_t audiomode_to_avchannellayout(AudioMode mode) {
if (AUDIO_MODE_STEREO == mode) {
return AV_CH_LAYOUT_STEREO;
}
else if (AUDIO_MODE_MONO == mode) {
return AV_CH_LAYOUT_MONO;
}
else {
SX_ERROR("Unhandled AudioMode; cannot convert to avchannellayout. (exiting).");
exit(EXIT_FAILURE);
}
}
static int audiomode_to_numchannels(AudioMode mode) {
if (AUDIO_MODE_STEREO == mode) {
return 2;
}
else if (AUDIO_MODE_MONO == mode) {
return 1;
}
else {
SX_ERROR("Unhandled AudioMode; cannot convert to number of channels.. (exiting).");
exit(EXIT_FAILURE);
}
}
/* -------------------------------------------------------- */
} /* namespace poly */
#ifndef POLY_AUDIO_CONVERTER_FFMPEG_H
#define POLY_AUDIO_CONVERTER_FFMPEG_H
#include <poly/AudioTypes.h>
#include <poly/AudioSettings.h>
#include <poly/AudioConverterListener.h>
extern "C" {
# include <libavutil/opt.h>
# include <libavutil/channel_layout.h>
# include <libswresample/swresample.h>
//#include <libavutil/samplefmt.h>
}
namespace poly {
class AudioConverterFfmpeg {
public:
AudioConverterFfmpeg();
~AudioConverterFfmpeg();
int init(AudioSettings convertFrom, AudioSettings convertTo, AudioConverterListener* lis);
int shutdown();
int convert(void* data, size_t nbytes, size_t nframes);
private:
AudioConverterListener* listener;
AudioSettings convert_from;
AudioSettings convert_to;
SwrContext* ctx;
int src_rate;
int dst_rate;
int64_t dst_chanlayout;
AVSampleFormat dst_format;
int dst_nchannels;
int dst_nbytes_allocated;
int dst_linesize;
uint8_t* dst_data;
int dst_max_samples;
};
} /* namespace poly */
#endif
Process 15070 stopped
* thread #8: tid = 0x563156, 0x000000010008b7dc test_ffmpeg_audio_converter_debug`___lldb_unnamed_function39$$test_ffmpeg_audio_converter_debug, name = 'com.apple.audio.IOThread.client', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
frame #0: 0x000000010008b7dc test_ffmpeg_audio_converter_debug`___lldb_unnamed_function39$$test_ffmpeg_audio_converter_debug
test_ffmpeg_audio_converter_debug`___lldb_unnamed_function39$$test_ffmpeg_audio_converter_debug:
-> 0x10008b7dc <+0>: movdqa xmm0, xmmword ptr [rsi + 8*rdx]
0x10008b7e1 <+5>: movdqa xmm2, xmmword ptr [rsi + 8*rdx + 0x10]
0x10008b7e7 <+11>: movdqa xmm1, xmm0
0x10008b7eb <+15>: shufps xmm0, xmm2, 0x88 ; xmm0 = xmm0[0,2],xmm2[0,2]
(lldb) bt
* thread #8: tid = 0x563156, 0x000000010008b7dc test_ffmpeg_audio_converter_debug`___lldb_unnamed_function39$$test_ffmpeg_audio_converter_debug, name = 'com.apple.audio.IOThread.client', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
* frame #0: 0x000000010008b7dc test_ffmpeg_audio_converter_debug`___lldb_unnamed_function39$$test_ffmpeg_audio_converter_debug
frame #1: 0x000000010007bda0 test_ffmpeg_audio_converter_debug`swri_audio_convert(ctx=0x0000607000006980, out=0x000062f0000033d0, in=0x000062f0000031b0, len=<unavailable>) + 576 at audioconvert.c:229
frame #2: 0x00000001000891b7 test_ffmpeg_audio_converter_debug`swr_convert_internal(s=0x000062f000000400, out=<unavailable>, out_count=558, in=0x000062f0000031b0, in_count=512) + 455 at swresample.c:634
frame #3: 0x00000001000889fd test_ffmpeg_audio_converter_debug`swr_convert(s=0x000062f000000400, out_arg=<unavailable>, out_count=558, in_arg=<unavailable>, in_count=0) + 941 at swresample.c:759
frame #4: 0x000000010005e5d3 test_ffmpeg_audio_converter_debug`poly::AudioConverterFfmpeg::convert(this=0x00000001000bf060, data=0x0000621000076d00, nbytes=4096, nframes=512) + 2419 at AudioConverterFfmpeg.cpp:151
frame #5: 0x0000000100007237 test_ffmpeg_audio_converter_debug`on_audio(data=0x0000621000076d00, nbytes=4096, nframes=512, user=0x0000000000000000) + 167 at test_ffmpeg_audio_converter.cpp:140
frame #6: 0x000000010001d1bd test_ffmpeg_audio_converter_debug`poly::read_callback(instream=0x000061700000f580, frameCountMin=512, frameCountMax=512) + 3805 at AudioCaptureSoundIo.cpp:521
frame #7: 0x0000000100069a01 test_ffmpeg_audio_converter_debug`read_callback_ca(userdata=0x000061700000f580, io_action_flags=0x0000700000322c54, in_time_stamp=0x00000001067280a0, in_bus_number=1, in_number_frames=512, io_data=0x0000000000000000) + 865 at coreaudio.c:1151
frame #8: 0x000000010647e799 CoreAudio`AUHAL::AUIOProc(unsigned int, AudioTimeStamp const*, AudioBufferList const*, AudioTimeStamp const*, AudioBufferList*, AudioTimeStamp const*, void*) + 2221
frame #9: 0x00007fff8c423ea3 CoreAudio`HALC_ProxyIOContext::IOWorkLoop() + 2535
frame #10: 0x00007fff8c4233ee CoreAudio`HALC_ProxyIOContext::IOThreadEntry(void*) + 88
frame #11: 0x00007fff8c4232c3 CoreAudio`HALB_IOThread::Entry(void*) + 75
frame #12: 0x00007fff8e010c13 libsystem_pthread.dylib`_pthread_body + 131
frame #13: 0x00007fff8e010b90 libsystem_pthread.dylib`_pthread_start + 168
frame #14: 0x00007fff8e00e375 libsystem_pthread.dylib`thread_start + 13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment