FFmpeg 裁剪——音频解码
配置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