对应ffmpeg的版本:
configuration: --prefix=/home/zeng/share/ffmpeg/ffmpeg/build/ --enable-ffplay
libavutil 57. 24.101 / 57. 24.101
libavcodec 59. 25.100 / 59. 25.100
libavformat 59. 20.101 / 59. 20.101
libavdevice 59. 6.100 / 59. 6.100
libavfilter 8. 29.100 / 8. 29.100
libswscale 6. 6.100 / 6. 6.100
libswresample 4. 6.100 / 4. 6.100
下面是头文件、接口封装及相关的测试程序
#ifndef __ANDROID_AMIXER_H__
#define __ANDROID_AMIXER_H__
typedef enum {
LogAresample_None = 0, //关闭日志输出
LogAresample_Urgent, //必须打的
LogAresample_Fatal, //致使级
LogAresample_Error, //错误级
LogAresample_Warning, //告警级
LogAresample_Info, //业务级
LogAresample_Debug, //调试级
LogAresample_Trace, //跟踪级
LogAresample_Detail, //详细级
LogAresample_Cnt
} LogAresample;
typedef enum {
Aresample_SAMPLE_FMT_NONE = -1,
Aresample_SAMPLE_FMT_U8, ///< unsigned 8 bits
Aresample_SAMPLE_FMT_S16, ///< signed 16 bits
Aresample_SAMPLE_FMT_S32, ///< signed 32 bits
Aresample_SAMPLE_FMT_FLT, ///< float
Aresample_SAMPLE_FMT_DBL, ///< double
Aresample_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
Aresample_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
Aresample_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
Aresample_SAMPLE_FMT_FLTP, ///< float, planar
Aresample_SAMPLE_FMT_DBLP, ///< double, planar
Aresample_SAMPLE_FMT_S64, ///< signed 64 bits
Aresample_SAMPLE_FMT_S64P, ///< signed 64 bits, planar
} AresampleSampleFormat;
typedef int32_t (*AresamplePrint)(void *, const char *);
//从句柄获取重采样后的一帧数据
int32_t recvAresampleFilter(void *oObj, void *data, int32_t *size);
//将一帧待重采样的数据添加到句柄
int32_t sendAresampleFilter(void *oObj, void *data, int32_t size);
//销毁重采样句柄
void destoryAresampleFilter(void *oObj);
//初始化重采样句柄
void *InitAresampleFilter(int32_t outFrameMs,
int32_t inRate, int32_t inChan, AresampleSampleFormat inFormat,
int32_t outRate, int32_t outChan, AresampleSampleFormat outFormat);
//设置重采样日志相关的内容
int32_t setAresampleLog(void *priv, AresamplePrint print);
#endif /*__ANDROID_AMIXER_H__*/
#include <unistd.h>
#include <stdint.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mem.h>
#include <libavutil/avstring.h>
#include "aresample.h"
/* #include <memwatch.h> */
/*************************************************/
/**************LogPrintf**************************/
/*************************************************/
static void *gPriv = NULL;
static AresamplePrint gPrint;
static LogAresample gLevel = LogAresample_Info;
static int AresampleLogPrintf(LogAresample level,
const char *file, const char *func,
int line, const char *format, ...) {
char logBuf[1024];
va_list args;
int funcLine = 0;
if (level > gLevel) return -1;
snprintf (logBuf, sizeof(logBuf), "[%s][%s][%d]", file, func, line);
funcLine = strlen(logBuf);
/*va_list*/
va_start(args, format);
vsnprintf(&logBuf[funcLine], sizeof(logBuf) - funcLine, format, args);
va_end(args);
/*va_list*/
if (gPrint) {
return gPrint(gPriv, logBuf);
}
return -1;
}
#define LogPrintf(level, ...)\
AresampleLogPrintf(level, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__);
#ifndef DEBUG0
#define DEBUG0(...)
#endif
#ifndef DEBUG1
#define DEBUG1(...) LogPrintf(LogAresample_Error, __VA_ARGS__);
#endif
#ifndef DEBUG2
#define DEBUG2(...) LogPrintf(LogAresample_Debug, __VA_ARGS__);
#endif
#ifndef ERRP
#define ERRP(con, ret, flag, ...) \
if (con) { \
DEBUG##flag(__VA_ARGS__) \
ret; \
}
#endif
static enum AVSampleFormat getAresampleFormat(AresampleSampleFormat aformat) {
enum AVSampleFormat format = AV_SAMPLE_FMT_NONE;
switch (aformat) {
case Aresample_SAMPLE_FMT_U8:
format = AV_SAMPLE_FMT_U8;
break;
case Aresample_SAMPLE_FMT_S16:
format = AV_SAMPLE_FMT_S16;
break;
case Aresample_SAMPLE_FMT_S32:
format = AV_SAMPLE_FMT_S32;
break;
case Aresample_SAMPLE_FMT_FLT:
format = AV_SAMPLE_FMT_FLT;
break;
case Aresample_SAMPLE_FMT_DBL:
format = AV_SAMPLE_FMT_DBL;
break;
case Aresample_SAMPLE_FMT_U8P:
format = AV_SAMPLE_FMT_U8P;
break;
case Aresample_SAMPLE_FMT_S16P:
format = AV_SAMPLE_FMT_S16P;
break;
case Aresample_SAMPLE_FMT_S32P:
format = AV_SAMPLE_FMT_S32P;
break;
case Aresample_SAMPLE_FMT_FLTP:
format = AV_SAMPLE_FMT_FLTP;
break;
case Aresample_SAMPLE_FMT_DBLP:
format = AV_SAMPLE_FMT_DBLP;
break;
case Aresample_SAMPLE_FMT_S64:
format = AV_SAMPLE_FMT_S64;
break;
case Aresample_SAMPLE_FMT_S64P:
format = AV_SAMPLE_FMT_S64P;
break;
default:break;
}
return format;
}
int32_t setAresampleLog(void *priv, AresamplePrint print) {
gPriv = priv;
gPrint = print;
return 0;
}
typedef struct {
void *handle;
void *sink;
void *source;
int32_t inRate;
enum AVSampleFormat inFormat;
AVChannelLayout inChLayout;
int32_t outRate;
enum AVSampleFormat outFormat;
AVChannelLayout outChLayout;
} AresampleFilter;
/*
* 参数1:输出帧长时长
* 参数2:输入采样率
* 参数3:输入通道数
* 参数4:输入采样格式
* 参数5:输出采样率
* 参数6:输出通道数
* 参数7:输出采样格式
*/
void *InitAresampleFilter(int32_t outFrameMs,
int32_t inRate, int32_t inChan, AresampleSampleFormat inFormat,
int32_t outRate, int32_t outChan, AresampleSampleFormat outFormat)
{
int32_t status = -1;
enum AVSampleFormat iFormat = AV_SAMPLE_FMT_NONE;
enum AVSampleFormat oFormat = AV_SAMPLE_FMT_NONE;
AresampleFilter *aresample = NULL;
AVFilterGraph *graph = NULL;
const char *inName = NULL;
const char *outName = NULL;
AVFilterContext *buffersinkCtx = NULL;
AVFilterInOut *input = NULL;
AVFilterInOut *output = NULL;
const AVFilter *abuffersink = NULL;
AVFilterContext *buffersrcCtx = NULL;
const AVFilter *abuffersrc = NULL;
AVChannelLayout inChLayout;
AVChannelLayout outChLayout;
char args[512];
char buf[64];
ERRP(1 != inChan && 2 != inChan, goto ERR0, 1,
"set channes [%d] invalid, range to [1-2]\n", inChan);
ERRP(1 != outChan && 2 != outChan, goto ERR0, 1,
"set channes [%d] invalid, range to [1-2]\n", outChan);
ERRP(8000 != inRate
&& 16000 != inRate
&& 32000 != inRate
&& 44100 != inRate
&& 48000 != inRate
&& 96000 != inRate, goto ERR0, 1,
"set inRate [%d] invalid, range to "
"[8000-16000-32000-44100-48000-96000]\n", inRate);
ERRP(8000 != outRate
&& 16000 != outRate
&& 32000 != outRate
&& 44100 != outRate
&& 48000 != outRate
&& 96000 != outRate, goto ERR0, 1,
"set outRate [%d] invalid, range to "
"[8000-16000-32000-44100-48000-96000]\n", outRate);
abuffersrc = avfilter_get_by_name("abuffer");
ERRP(abuffersrc == NULL, goto ERR0, 1,
"input get abuffer failure\n");
abuffersink = avfilter_get_by_name("abuffersink");
ERRP(abuffersink == NULL, goto ERR0, 1, "get abuffersin failure");
iFormat = getAresampleFormat(inFormat);
ERRP(AV_SAMPLE_FMT_NONE == iFormat, goto ERR0, 1, "get iFormat [%d] failure\n", inFormat);
printf ("iFormat:%d\n", iFormat);
oFormat = getAresampleFormat(outFormat);
ERRP(AV_SAMPLE_FMT_NONE == oFormat, goto ERR0, 1, "get oFormat [%d] failure\n", outFormat);
printf ("oFormat:%d\n", oFormat);
av_channel_layout_default(&inChLayout, inChan);
av_channel_layout_describe(&inChLayout, buf, sizeof(buf));
snprintf (args, sizeof(args) - 1,
"sample_rate=%d:sample_fmt=%s:channel_layout=%s",
inRate, av_get_sample_fmt_name(iFormat), buf);
printf ("args:%s\n", args);
graph = avfilter_graph_alloc();
ERRP(graph == NULL, goto ERR0, 1, "get graph instance failure\n");
inName = av_strdup("in0");
ERRP(inName == NULL, goto ERR1, 1, "inName strdup failure\n");
LogPrintf(LogAresample_Info, "get in:%s\n", inName);
status = avfilter_graph_create_filter(&buffersrcCtx,
abuffersrc, inName, args, NULL, graph);
ERRP(status < 0, goto ERR1, 1, "create source filter %s failure\n", inName);
outName = av_strdup("out0");
ERRP(outName == NULL, goto ERR1, 1, "parse out failure\n");
status = avfilter_graph_create_filter(&buffersinkCtx,
abuffersink, outName, NULL, NULL, graph);
ERRP(status < 0, goto ERR1, 1, "create sink filter %s failrue\n", outName);
status = av_opt_set_bin(buffersinkCtx, "sample_fmts",
(uint8_t*)&oFormat, sizeof(oFormat),
AV_OPT_SEARCH_CHILDREN);
ERRP (status < 0, goto ERR1, 1, "Cannot set output sample oFormat\n");
av_channel_layout_default(&outChLayout, outChan);
av_channel_layout_describe(&outChLayout, buf, sizeof(buf));
status = av_opt_set(buffersinkCtx, "ch_layouts", buf, AV_OPT_SEARCH_CHILDREN);
ERRP (status < 0, goto ERR1, 1, "Cannot set output sample format\n");
status = av_opt_set_bin(buffersinkCtx, "sample_rates",
(uint8_t*)&outRate, sizeof(outRate), AV_OPT_SEARCH_CHILDREN);
ERRP (status < 0, goto ERR1, 1, "Cannot set output sample rate\n");
output = avfilter_inout_alloc();
ERRP(output == NULL, goto ERR1, 1, "alloc inout failrue\n");
output->name = (char *)inName;
output->filter_ctx = buffersrcCtx;
output->pad_idx = 0;
output->next = NULL;
input = avfilter_inout_alloc();
ERRP(input == NULL, goto ERR1, 1, "alloc input inout failrue\n");
input->name = (char *)outName;
input->filter_ctx = buffersinkCtx;
input->pad_idx = 0;
input->next = NULL;
//已经将所有权交给了output和input
inName = NULL;
outName = NULL;
snprintf(args, sizeof(args), "[in0]aresample=%d[out0]", outRate);
args[sizeof(args) - 1] = '\0';
printf ("args:%s\n", args);
status = avfilter_graph_parse_ptr(graph, args, &input, &output, NULL);
ERRP(status < 0, goto ERR1, 1, "parse ptr(%s) failure\n", args);
status = avfilter_graph_config(graph, NULL);
ERRP(status < 0, goto ERR1, 1, "config ptr(%s) failure\n", args);
aresample = (AresampleFilter *) av_mallocz (sizeof(*aresample));
ERRP(aresample == NULL, goto ERR1, 1, "malloc AresampleFilter instance failure\n");
aresample->handle = graph;
aresample->sink = buffersinkCtx;
aresample->inRate = inRate;
aresample->inChLayout = inChLayout;
aresample->inFormat = iFormat;
aresample->outRate = outRate;
aresample->outChLayout = outChLayout;
aresample->outFormat = oFormat;
aresample->source = buffersrcCtx;
av_buffersink_set_frame_size(buffersinkCtx, outFrameMs * outRate / 1000);
LogPrintf(LogAresample_Info, "InitAresampleFilter suc\n");
return aresample;
ERR1:
if (input) avfilter_inout_free(&input);
if (output) avfilter_inout_free(&output);
if (outName) free((void *)outName);
if (inName) free((void *)inName);
if (graph) avfilter_graph_free(&graph);
ERR0:
return NULL;
}
void destoryAresampleFilter(void *oObj) {
AVFilterGraph *graph = NULL;
AresampleFilter *aresample = (AresampleFilter *)oObj;
if (aresample) {
graph = (AVFilterGraph *)aresample->handle;
if (graph) {
avfilter_graph_free(&graph);
}
av_free(aresample);
}
}
int32_t sendAresampleFilter(void *oObj, void *data, int32_t size) {
int32_t status = -1;
AVFrame *frame = NULL;
AVFilterContext *inCtx = NULL;
AresampleFilter *aresample = (AresampleFilter *)oObj;
ERRP(oObj == NULL, return -1, 0);
ERRP(data == NULL, return -1, 0);
frame = av_frame_alloc();
ERRP(frame == NULL, goto ERR0, 1, "av_frame_alloc failrue\n");
if (aresample) {
inCtx = (AVFilterContext *)aresample->source;
if (inCtx) {
frame->sample_rate = aresample->inRate;
frame->ch_layout = aresample->inChLayout;
frame->format = aresample->inFormat;
frame->nb_samples = size / (av_get_bytes_per_sample(aresample->inFormat) * aresample->inChLayout.nb_channels);
status = av_frame_get_buffer(frame, 0);
ERRP(status < 0, goto ERR1, 1, "av_frame_get_buffer failure\n");
memcpy(frame->data[0], data, size);
status = av_buffersrc_add_frame_flags(inCtx, frame, 0);
ERRP(status < 0, goto ERR1, 1, "av_buffersrc_add_frame_flags %d", status);
}
}
ERR1:
av_frame_free(&frame);
ERR0:
return status;
}
/*
此处有关于Planar的新处理,如果想代码更通用,建议采用该接口
int32_t sendAresampleFilter(void *oObj, void *data[], int32_t size) {
int32_t status = -1;
int32_t channels = 0;
int32_t isPlanar = 0;
AVFrame *frame = NULL;
AVFilterContext *inCtx = NULL;
AresampleFilter *aresample = (AresampleFilter *)oObj;
ERRP(oObj == NULL, return -1, 0);
ERRP(data == NULL, return -1, 0);
frame = av_frame_alloc();
ERRP(frame == NULL, goto ERR0, 1, "av_frame_alloc failrue\n");
if (aresample) {
inCtx = (AVFilterContext *)aresample->source;
if (inCtx) {
frame->sample_rate = aresample->inRate;
frame->ch_layout = aresample->inChLayout;
frame->format = aresample->inFormat;
frame->nb_samples = size / (av_get_bytes_per_sample(aresample->inFormat) * aresample->inChLayout.nb_channels);
printf ("frame->nb_samples:%d\n", frame->nb_samples);
status = av_frame_get_buffer(frame, 0);
ERRP(status < 0, goto ERR1, 1, "av_frame_get_buffer failure\n");
isPlanar = av_sample_fmt_is_planar(aresample->inFormat);
if (!isPlanar) {
memcpy(frame->data[0], data[0], size);
}
else {
for (channels = 0; channels < aresample->inChLayout.nb_channels; channels++) {
memcpy(frame->data[channels],
data[channels], size/aresample->inChLayout.nb_channels);
}
}
status = av_buffersrc_add_frame_flags(inCtx, frame, 0);
ERRP(status < 0, goto ERR1, 1, "av_buffersrc_add_frame_flags %d", status);
}
}
ERR1:
av_frame_free(&frame);
ERR0:
return status;
}
*/
int32_t recvAresampleFilter(void *oObj, void *data, int32_t *size) {
int32_t status = -1;
AVFrame *frame = NULL;
AVFilterContext *outCtx = NULL;
AresampleFilter *aresample = (AresampleFilter *)oObj;
ERRP(oObj == NULL, return -1, 0);
ERRP(data == NULL, return -1, 0);
frame = av_frame_alloc();
ERRP(frame == NULL, goto ERR0, 1, "av_frame_alloc failrue\n");
if (aresample) {
outCtx = (AVFilterContext *)aresample->sink;
if (outCtx) {
status = av_buffersink_get_frame_flags(outCtx, frame, 0);
ERRP(status < 0, goto ERR1, 1, "av_buffersink_get_frame_flags:%d", status);
*size = frame->nb_samples
* av_get_bytes_per_sample(frame->format)
* frame->ch_layout.nb_channels;
memcpy(data, frame->data[0], *size);
}
}
ERR1:
av_frame_free(&frame);
ERR0:
return status;
}
#ifdef TEST_ARESAMPLE
int32_t print(void *priv, const char *strings) {
printf ("%s", strings);
return 0;
}
int main(int args, char *argv[]) {
int32_t ret = -1;
void *pObj = NULL;
int32_t ibuffer[1920];
int16_t obuffer[1920];
if (args != 3) {
printf ("args == 3 ==> ./aresample in.pcm out.pcm\n");
return -1;
}
FILE *fpIn0 = fopen(argv[1], "r");
FILE *fpOut = fopen(argv[2], "w+");
setAresampleLog(NULL, print);
pObj = InitAresampleFilter(10, 96000, 1, Aresample_SAMPLE_FMT_S32, 48000, 1, Aresample_SAMPLE_FMT_S16);
if (pObj) {
printf ("pObj:%p\n", pObj);
while (1) {
int size = fread(ibuffer, 1, sizeof(ibuffer), fpIn0);
if (size != sizeof(ibuffer)) break;
ret = sendAresampleFilter(pObj, ibuffer, sizeof(ibuffer));
if (ret < 0) break;
ret = recvAresampleFilter(pObj, obuffer, &size);
if (ret < 0) break;
fwrite(obuffer, 1, size, fpOut);
}
}
fclose(fpIn0);
fclose(fpOut);
destoryAresampleFilter(pObj);
return 0;
}
#endif