只留下某些音频的配置:
./configure --enable-shared --disable-yasm --enable-memalign-hack --enable-gpl --enable-cross-compile --prefix=/home/liqinghan/workspace/ffmpeg-3.2.2/_install --arch=arm --target-os=linux --cross-prefix=arm-hisiv400-linux- --disable-programs --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver --disable-doc --disable-htmlpages --disable-manpages --disable-podpages --disable-txtpages --disable-avdevice --disable-network --disable-dct --disable-dwt --disable-error-resilience --disable-lsp --disable-lzo --disable-faan --disable-pixelutils --disable-everything --disable-amd3dnow --disable-amd3dnowext --disable-power8 --disable-mmx --disable-mmxext --disable-debug --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm --enable-decoder=alac --enable-decoder=ac3 --enable-decoder=adpcm_ima_wav --enable-decoder=adpcm_4xm --enable-decoder=adpcm_g722 --enable-decoder=adpcm_g726 --enable-decoder=adpcm_yamaha --enable-decoder=flac --enable-decoder=g729 --enable-decoder=iac --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=pcm_alaw --enable-decoder=pcm_mulaw --enable-decoder=ape
音频解码接口:
#ifndef _AV_AUDIO_DECODER_H_
#define _AV_AUDIO_DECODER_H_
#pragma pack(push)
#pragma pack(1)
typedef struct {
int channel; //通道号
int sample_Rate; //采样率
int band_Width; //位宽
int frmsize; //一个帧的长度
int bits_per_coded_sample; //一个byte编码后占bit位
int num_point_per_pack; //包的点数
}AVaudioDeocerAttr;
#pragma pack(pop)
/*
Id:ffmepg对应编解码的id!!
*/
int audio_decoder_create(int id,AVaudioDeocerAttr decoderAttr);
int audio_decoder_destroy(void);
void audio_decode_start(void);
void audio_decode_stop(void);
/*
*collision: < 0 阻塞写入, 0: 非阻塞, >0:超时(us)
*/
int aduio_send_packet(char* packet,int size,int64_t pts,int collision);
int audio_send_packet_stop(void);
int audio_decode_getframe(char* buf,int *size,int64_t *pts);
#endif
内部实现:
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "libavutil/internal.h"
#include "libavcodec/avcodec.h"
#include "avaudiodecoder.h"
#if HAVE_SYS_RESOURCE_H
#include
#include
#include
#elif HAVE_GETPROCESSTIMES
#include
#endif
#if HAVE_GETPROCESSMEMORYINFO
#include
#include
#endif
#if HAVE_SETCONSOLECTRLHANDLER
#include
#endif
#if HAVE_SYS_SELECT_H
#include
#endif
#if HAVE_TERMIOS_H
#include
#include
#include
#include
#elif HAVE_KBHIT
#include
#endif
#if HAVE_PTHREADS
#include
#endif
#include
#define _AV_AUDIO_DECODER_DEBUG_(fmt,args...) \
do{ \
printf("[av_audio_decoder_debug]");\
printf(fmt,##args); \
}while(0)
static AVCodec *codec = NULL;
static AVCodecContext *codecContext= NULL;
static AVPacket avPkt;
static AVFrame *decodedFrame = NULL;
static int shmid;
static pthread_mutex_t mutex;
static int vb_initialized = 0;
#pragma pack(push)
#pragma pack(1)
//共享内存区!
typedef struct{
int writeable;
int memsize;
int bufsize;
int64_t pts;
char buf[0]; //定义一个不占为位置的符号,数据的起始地址
}AVshareMemBuf;
#pragma pack(pop)
static AVshareMemBuf* outMemBuf;
static AVshareMemBuf* userBuf;
static void* shmembuf;
static pthread_t pid;
static int getframectrl = 0;
static void* audio_decode_start_thread(void* param);
static void audio_get_frame_defaults(AVFrame *frame);
static void audio_decoder_vb_destroy(void);
static void audio_decoder_vb_create(int frmSize);
static int64_t get_cur_time(void);
static int64_t get_cur_time(void){
int64_t time;
struct timeval tv;
gettimeofday(&tv,NULL);
time = tv.tv_sec*1000*1000;
time = time + tv.tv_usec;
return time;
}
static void audio_get_frame_defaults(AVFrame *frame)
{
if (frame->extended_data != frame->data)
av_freep(&frame->extended_data);
memset(frame, 0, sizeof(*frame));
frame->pts =
frame->pkt_dts = AV_NOPTS_VALUE;
#if FF_API_PKT_PTS
FF_DISABLE_DEPRECATION_WARNINGS
frame->pkt_pts = AV_NOPTS_VALUE;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
frame->best_effort_timestamp = AV_NOPTS_VALUE;
frame->pkt_duration = 0;
frame->pkt_pos = -1;
frame->pkt_size = -1;
frame->key_frame = 1;
frame->sample_aspect_ratio = (AVRational){ 0, 1 };
frame->format = -1; /* unknown */
frame->extended_data = frame->data;
frame->color_primaries = AVCOL_PRI_UNSPECIFIED;
frame->color_trc = AVCOL_TRC_UNSPECIFIED;
frame->colorspace = AVCOL_SPC_UNSPECIFIED;
frame->color_range = AVCOL_RANGE_UNSPECIFIED;
frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
frame->flags = 0;
}
static void audio_decoder_vb_destroy(void){
shmdt(shmembuf);
vb_initialized = 0;
shmembuf =NULL;
}
static void audio_decoder_vb_create(int frmSize){
//
//we must create vb buffer for videoserver put!!!
//
if(vb_initialized) return;
shmid = shmget(0x7090, sizeof(AVshareMemBuf) + frmSize, IPC_CREAT | 0666);
//第二个参数shmaddr为NULL,内核会自动选择地址映射
shmembuf = shmat(shmid, NULL, 0);
userBuf = (AVshareMemBuf*)shmembuf;
userBuf->writeable = 1;
userBuf ->size = frmSize;
av_init_packet(&avPkt);
vb_initialized = 1;
}
int audio_decoder_create(int id,AVaudioDeocerAttr decoderAttr){
int audioSize;
//注册解码器,看源码可以知道就是定义每个解码器,参数和回调函数。
regster_all_audio_decoder();
codec = avcodec_find_decoder(id);
if(codec == NULL){
_AV_AUDIO_DECODER_DEBUG_("cannot find deocder \n");
return -1;
}
//给解码器申请上下文,就是处理空间
codecContext = avcodec_alloc_context3(codec);
codecContext->sample_rate = decoderAttr.sample_Rate;
codecContext->channels = decoderAttr.channel;
codecContext->bits_per_coded_sample = decoderAttr.bits_per_coded_sample;
//打开解码器
/* open it */
int s32Ret = avcodec_open2(codecContext, codec, NULL);
if ( s32Ret < 0 )
{
avcodec_free_context(&codecContext);
_AV_AUDIO_DECODER_DEBUG_("can not open codec\n");
return -1;
}
audioSize = decoderAttr.num_point_per_pack;
outMemBuf =(AVshareMemBuf*)malloc(sizeof(AVshareMemBuf) + audioSize);
outMemBuf->size = audioSize;
outMemBuf->writeable =1;
pthread_mutex_init (&mutex,NULL);
//创建VB
audio_decoder_vb_create(decoderAttr.frmsize);
return 0;
}
int audio_decoder_destroy(void){
avcodec_close(codecContext);
av_free(codecContext);
av_frame_free(&decodedFrame);
free(outMemBuf);
pthread_mutex_destroy(&mutex);
if(shmctl(shmid, IPC_RMID, 0) == -1)
{
_AV_AUDIO_DECODER_DEBUG_("shmctl(IPC_RMID) failed\n");
//exit(EXIT_FAILURE);
}
return 0;
}
int aduio_send_packet(char* packet,int size,int64_t pts,int collision){
audio_decoder_vb_create(size);
if(packet == NULL) {_AV_AUDIO_DECODER_DEBUG_("audio packet is null\n"); return -1;}
if(collision < 0){
while(userBuf->writeable == 0){
}
}
else if(collision ==0){
if(userBuf->writeable == 0) {
_AV_AUDIO_DECODER_DEBUG_("decoder buffer is full\n");
return -1;
}
}
else{
uint64_t time = get_cur_time();
while(userBuf->writeable == 0){
if((get_cur_time() - time) > collision) {
_AV_AUDIO_DECODER_DEBUG_("decoder buffer is full\n");
return -1;
}
}
}
if(userBuf->size < size){
_AV_AUDIO_DECODER_DEBUG_("userBuf->size:%d,size:%d,frame size is too larger\n",userBuf->size,size);
return -1;
}
memcpy(userBuf->buf,packet,size);
userBuf->writeable = 0;
userBuf->pts = pts;
userBuf->size = size;
return 0;
}
int audio_send_packet_stop(void){
audio_decoder_vb_destroy();
}
void audio_decode_start(void){
if(getframectrl) return;
getframectrl =1;
pthread_create(&pid,NULL,audio_decode_start_thread,NULL);
}
void audio_decode_stop(void){
if(getframectrl ==0) return;
getframectrl =0;
pthread_join(pid,NULL);
}
void* audio_decode_start_thread(void* param){
int got_frame = 0;
AVshareMemBuf* membuf = NULL;
membuf = (AVshareMemBuf*)malloc(sizeof(AVshareMemBuf) + userBuf->size);
while(getframectrl){
if(userBuf->writeable == 0){
membuf->pts = userBuf->pts;
membuf->size = userBuf->size;
memcpy(membuf->buf,userBuf->buf,membuf->size);
userBuf->writeable = 1;
avPkt.data = membuf->buf;
avPkt.size = membuf->size;
avPkt.pts = membuf->pts;
if (decodedFrame == NULL)
{
decodedFrame = av_frame_alloc();
if (decodedFrame == NULL)
{
_AV_AUDIO_DECODER_DEBUG_("malloc frame vb error!!!\n");
return 0;
}
}
else{
audio_get_frame_defaults(decodedFrame);
}
got_frame = 0 ;
int len = avcodec_decode_audio4(codecContext, decodedFrame, &got_frame, &avPkt);
if (len < 0)
{
// return 0;
_AV_AUDIO_DECODER_DEBUG_("decoder error!,you input frame is error!! \n");
}
if (got_frame)
{
/* if a frame has been decoded, output it */
int data_size = av_samples_get_buffer_size(NULL, codecContext->channels,
decodedFrame->nb_samples,
codecContext->sample_fmt, 1);
if(outMemBuf->size >= data_size){
//lock!!
if(outMemBuf->writeable){
pthread_mutex_lock(&mutex);
_AV_AUDIO_DECODER_DEBUG_("data_size:%d,outMemBuf->size:%d,codecContext->bits_per_raw_sample:%d\n",data_size,outMemBuf->size,codecContext->bits_per_raw_sample);
memcpy(outMemBuf->buf,decodedFrame->data[0],data_size);
outMemBuf->writeable = 0;
outMemBuf->pts = decodedFrame->pts;
pthread_mutex_unlock(&mutex);
}
else {
_AV_AUDIO_DECODER_DEBUG_("decoder buff is full \n");
}
}
else{
_AV_AUDIO_DECODER_DEBUG_("outMemBuf->size:%d,data_size:%d;after decoder packet size is error \n",outMemBuf->size,data_size);
}
}
}
}
free(membuf);
return NULL;
}
/*
*获取解码后数据,音频原始数据,(PCM码)
*/
int audio_decode_getframe(char* buf,int *size,int64_t *pts){
int ret =-1;
pthread_mutex_lock(&mutex);
if(outMemBuf->writeable == 0){
memcpy(buf,outMemBuf->buf,outMemBuf->size);
*pts = outMemBuf->pts;
*size = outMemBuf->size;
outMemBuf->writeable = 1;
ret = 0;
}
pthread_mutex_unlock(&mutex);
return ret;
}
Makefile:
CROSS_COMPILE=
SRC_DIR = ./
SRC := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRC:%.c=%.o)
OBJ := .o
A := a
C := c
CC := $(CROSS_COMPILE)gcc
#定义自己库名,生成两个,库动态和静态
SOLIB := avaudiodecoder.so
ALIB := avaudiodecoder.a
#添加ffmpeg依赖库
ffmpeg_obj += $(wildcard ../libavcodec/*.o)
ffmpeg_obj += $(wildcard ../libavcodec/arm/*.o)
ffmpeg_obj += $(wildcard ../libavutil/*.o)
ffmpeg_obj += $(wildcard ../libavutil/arm/*.o)
#####################################
LIBRARY_LINK = $(CROSS_COMPILE)ar -scr
#hisi3536lib#########
INC_FLAGS += -I..
#-g加上调试增加数据量,应该去掉
CFLAGS := -Wall -g -shared -fPIC
LD_FLAGS = -lpthread -lm -ldl
TCLLIB = $(SOLIB) $(ALIB)
all: $(TCLLIB)
%.o:%.c
$(CC) -c $(INC_FLAGS) $(CFLAGS) $<
$(SOLIB):$(OBJS)
$(CC) $(INC_FLAGS) $(CFLAGS) -o $@ $^ $(LD_FLAGS)
$(ALIB):$(OBJS) $(ffmpeg_obj)
$(LIBRARY_LINK) $@ $^ $(OBJS)
.PHONY : clean all
clean:
@rm -f *.so
@rm -f *.o
@rm -f *.a