FFmpeg 裁剪——音频解码
配置ffmpeg,只留下某些音频的配置:
./configure --enable-shared --disable-yasm --enable-memalign-hack --enable-gpl --enable-cross-compile --prefix=/home/liqinghan/workspace/ffmpeg-3.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() 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 = ; #pragma pack(push)
#pragma pack(1)
//共享内存区!
typedef struct{
int writeable;
int memsize;
int bufsize;
int64_t pts;
char buf[]; //定义一个不占为位置的符号,数据的起始地址
}AVshareMemBuf; #pragma pack(pop) static AVshareMemBuf* outMemBuf;
static AVshareMemBuf* userBuf; static void* shmembuf; static pthread_t pid; static int getframectrl = ; 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**;
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, , 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 = ;
frame->pkt_pos = -;
frame->pkt_size = -;
frame->key_frame = ;
frame->sample_aspect_ratio = (AVRational){ , };
frame->format = -; /* 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 = ;
} static void audio_decoder_vb_destroy(void){ shmdt(shmembuf);
vb_initialized = ;
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 | ); //第二个参数shmaddr为NULL,内核会自动选择地址映射
shmembuf = shmat(shmid, NULL, ); userBuf = (AVshareMemBuf*)shmembuf;
userBuf->writeable = ;
userBuf ->size = frmSize;
av_init_packet(&avPkt);
vb_initialized = ;
} 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 -;
}
//给解码器申请上下文,就是处理空间
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 < )
{
avcodec_free_context(&codecContext); _AV_AUDIO_DECODER_DEBUG_("can not open codec\n"); return -;
}
audioSize = decoderAttr.num_point_per_pack; outMemBuf =(AVshareMemBuf*)malloc(sizeof(AVshareMemBuf) + audioSize);
outMemBuf->size = audioSize;
outMemBuf->writeable =; pthread_mutex_init (&mutex,NULL);
//创建VB
audio_decoder_vb_create(decoderAttr.frmsize); return ; } 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, ) == -)
{
_AV_AUDIO_DECODER_DEBUG_("shmctl(IPC_RMID) failed\n");
//exit(EXIT_FAILURE);
} return ;
} 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 -;} if(collision < ){ while(userBuf->writeable == ){ } }
else if(collision ==){ if(userBuf->writeable == ) { _AV_AUDIO_DECODER_DEBUG_("decoder buffer is full\n");
return -;
}
}
else{ uint64_t time = get_cur_time(); while(userBuf->writeable == ){ if((get_cur_time() - time) > collision) { _AV_AUDIO_DECODER_DEBUG_("decoder buffer is full\n"); return -;
}
} } if(userBuf->size < size){ _AV_AUDIO_DECODER_DEBUG_("userBuf->size:%d,size:%d,frame size is too larger\n",userBuf->size,size); return -;
} memcpy(userBuf->buf,packet,size); userBuf->writeable = ;
userBuf->pts = pts;
userBuf->size = size; return ; } int audio_send_packet_stop(void){ audio_decoder_vb_destroy(); } void audio_decode_start(void){ if(getframectrl) return; getframectrl =; pthread_create(&pid,NULL,audio_decode_start_thread,NULL); } void audio_decode_stop(void){ if(getframectrl ==) return; getframectrl =; pthread_join(pid,NULL); } void* audio_decode_start_thread(void* param){ int got_frame = ; AVshareMemBuf* membuf = NULL; membuf = (AVshareMemBuf*)malloc(sizeof(AVshareMemBuf) + userBuf->size); while(getframectrl){ if(userBuf->writeable == ){ membuf->pts = userBuf->pts;
membuf->size = userBuf->size;
memcpy(membuf->buf,userBuf->buf,membuf->size);
userBuf->writeable = ; 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 ;
}
} else{
audio_get_frame_defaults(decodedFrame);
} got_frame = ; int len = avcodec_decode_audio4(codecContext, decodedFrame, &got_frame, &avPkt); if (len < )
{
// 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, ); 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[],data_size); outMemBuf->writeable = ;
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 =-;
pthread_mutex_lock(&mutex);
if(outMemBuf->writeable == ){ memcpy(buf,outMemBuf->buf,outMemBuf->size);
*pts = outMemBuf->pts;
*size = outMemBuf->size;
outMemBuf->writeable = ;
ret = ;
}
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
FFmpeg 裁剪——音频解码的更多相关文章
- FFMPEG视音频解码【一】
多媒体的时代,得多了解点编解码的技术才行,而ffmpeg为我们提供了一系列多媒体编解码的接口,如何用好这些接口达到自己所需要的目的,这也是一门重要的学问. 要是了解得不够,总是会遇到一堆又一堆问题:网 ...
- [总结]FFMPEG视音频编解码零基础学习方法--转
ffmpeg编解码学习 目录(?)[-] ffmpeg程序的使用ffmpegexeffplayexeffprobeexe 1 ffmpegexe 2 ffplayexe 3 ffprobeexe ...
- FFMPEG视音频编解码零基础学习方法
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...
- FFMPEG视音频编解码零基础学习方法-b
感谢大神分享,虽然现在还看不懂,留着大家一起看啦 PS:有不少人不清楚“FFmpeg”应该怎么读.它读作“ef ef em peg” 0. 背景知识 本章主要介绍一下FFMPEG都用在了哪里(在这里仅 ...
- [总结]FFMPEG视音频编解码零基础学习方法
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...
- 【转】[总结]FFMPEG视音频编解码零基础学习方法
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...
- FFMPEG视音频编解码零基础学习方法 【荐】
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频 编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在 ...
- [转载] FFMPEG视音频编解码零基础学习方法
在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者.在和大家探讨的过程中,我忽然发现了一个问题:在“ ...
- EasyDarwin开源音频解码项目EasyAudioDecoder:基于ffmpeg的安卓音频(AAC、G726)解码库(第一部分,ffmpeg-android的编译)
ffmpeg是一套开源的,完整的流媒体解决方案.基于它可以很轻松构建一些强大的应用程序.对于流媒体这个行业,ffmpeg就像圣经一样的存在.为了表达敬意,在这里把ffmpeg官网的一段简介搬过来,ff ...
随机推荐
- 缓存Memcached 与 Redis 相同点差异点分析
memcach简介 Memcache时一个内存对象缓存系统,用于加速动态web应用程序,减轻数据库负载.它可以应对任意多个连接,使用非阻塞的网络I/O,工作机制:在内存中开辟一块空间,然后建立一个ha ...
- 向json中添加新的熟悉或对象 Add new attribute (element) to JSON object using JavaScript
How do I add new attribute (element) to JSON object using JavaScript? JSON stands for JavaScript Obj ...
- linux dns 工具包 -- bind-utils
https://www.cnblogs.com/274914765qq/p/4817941.html
- git合并分支上指定的commit
merge 能够胜任平常大部分的合并需求.但也会遇到某些特殊的情况,例如正在开发一个新的功能,线上说有一个紧急的bug要修复.bug修好了但并不像把仍在开发的新功能代码也提交到线上去.这时候也许想要一 ...
- kubernetes-PetSet
什么是Pet?Pet是一个有状态应用程序,本质上它是一个具有确定性名称以及唯一身份的Pod,身份内容包括: DNS中可以识别的固定hostname 顺序化索引(Pet名称组成:PetSetName-O ...
- [ASP.NET MVC]视图是如何呈现的 (续)
在上一篇文章中,我们知道了通过Controller执行ActionResult的Execute可以找到对应Controler对应的ViewEngine,然后在View中把Action的结果显示出来.那 ...
- 180714、JRebel插件安装配置与破解激活(多方案)详细教程
JRebel 介绍 IDEA上原生是不支持热部署的,一般更新了 Java 文件后要手动重启 Tomcat 服务器,才能生效,浪费不少生命啊.目前对于idea热部署最好的解决方案就是安装JRebel插件 ...
- [实战]MVC5+EF6+MySql企业网盘实战(4)——上传头像
写在前面 最近又开始忙了,工期紧比较赶,另外明天又要去驾校,只能一个功能一个功能的添加了,也许每次完成的功能确实不算什么,等将功能都实现了,然后在找一个好点的ui对前端重构一下. 系列文章 [EF]v ...
- hdu2243 考研路茫茫——单词情结【AC自动机】【矩阵快速幂】
考研路茫茫——单词情结 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- ESP8266 的几个代码 加深对LUA的理解
--some functions dofile("functions.lua") lighton1= lighton2= lighton3= lighton4= pin1 = pi ...