配置ffmpeg,只留下某些音频的配置:

./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);

内部实现

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
 
 
#include "libavutil/internal.h"
#include "libavcodec/avcodec.h"
#include "avaudiodecoder.h"
 
#if HAVE_SYS_RESOURCE_H
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#elif HAVE_GETPROCESSTIMES
#include <windows.h>
#endif
#if HAVE_GETPROCESSMEMORYINFO
#include <windows.h>
#include <psapi.h>
#endif
#if HAVE_SETCONSOLECTRLHANDLER
#include <windows.h>
#endif
 
 
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
 
#if HAVE_TERMIOS_H
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#elif HAVE_KBHIT
#include <conio.h>
#endif
 
#if HAVE_PTHREADS
#include <pthread.h>
#endif
 
#include <time.h>
 
#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 := libavaudiodecoder.so
ALIB := libavaudiodecoder.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
INC_FLAGS += -I..
#-g加上调试增加数据量,应该去掉
CFLAGS := -Wall -g -shared  -fPIC   
LD_FLAGS =  -lpthread -lm -ldl
MYLIB = $(SOLIB) $(ALIB)
all: $(MYLIB)
%.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

 

版权声明:本文为liqinghan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/liqinghan/p/10018532.html