FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。
硬件平台:Tiny4412(Cortex-A9)
交叉编译器:arm-linux-gcc(Ver4.5.1)
开发板系统:linux3.5
ffmpeg版本:ffmpeg-4.2.5
安装ffmpeg库之前需要先安装x264库。
x264下载地址:https://www.videolan.org/developers/x264.html
安装x264
#解压
tar xvf /mnt/hgfs/ubuntu/software_pack/x264-master.tar.bz2
#配置信息,生成Makefile
./configure --prefix=$PWD/_install --enable-shared --disable-asm --host=arm-linux
#修改config.mak
gedit config.mak
编译 make
若编译出现报错:undefined reference to `clock_gettime’,则添加动态链接: -lrt
重新编译 make
/*编译*/
make && make install
/*生成文件*/
[wbyq@wbyq x264-master]$ tree _install/
_install/
├── bin
│ └── x264
├── include
│ ├── x264_config.h
│ └── x264.h
└── lib
├── libx264.so -> libx264.so.164
├── libx264.so.164
└── pkgconfig
└── x264.pc
4 directories, 6 files
下载地址:http://www.ffmpeg.org/download.html
编译安装ffmpeg
/*解压*/
tar xvf /mnt/hgfs/ubuntu/software_pack/ffmpeg-4.2.5.tar.bz2
/*配置信息,生成makefile文件*/
./configure --enable-shared --enable-static --prefix=$PWD/_install --cross-prefix=arm-linux- --arch=arm --target-os=linux --enable-gpl --extra-cflags=-I/home/wbyq/tiny4412_pack/x264-master/_install/include --extra-ldflags=-L/home/wbyq/tiny4412_pack/x264-master/_install/lib --enable-ffmpeg --enable-libx264
/*编译源码*/
make && make install
#include
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FILE_NAME "1.mp4"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
extern const unsigned char ascii_32_16[][32*16/8];
static struct fb_var_screeninfo vinfo;/*lcd可变形参结构体*/
static struct fb_fix_screeninfo finfo;/*lcd固定参数结构体*/
static unsigned char *lcd_p;/*lcd缓冲区首地址*/
u32 lcd_widht;/*LCD屏宽度*/
u32 lcd_hight;/*LCD屏高度*/
static unsigned char *lcd_p2;/*图像数据*/
u32 map_w;
u32 map_h;
/*画点函数*/
void LCD_DrawPoint(int x,int y,int c)
{
unsigned int *p=(unsigned int *)(y*finfo.line_length+x*vinfo.bits_per_pixel/8+lcd_p);
*p=c;
}
/*画点函数*/
void LCD_DrawPoint2(int x,int y,int c)
{
unsigned int *p=(unsigned int *)(y*map_w*3+x*3+lcd_p2);
*p=c;
}
/*显示数据*/
void LCD_DisplayData(int x,int y,int w,int h,const unsigned char *data)
{
int i,j;
int x0=x;
unsigned char temp;
for(i=0;i0x80)
{
str+=2;
}
else
{
LCD_DisplayData(x,y,size/2,size,ascii_32_16[*str-' ']);
str++;
x+=size/2;
}
}
}
/*显示图片函数(居中显示)*/
void LCD_Image(int map_w,int map_h,u8 *map_rgb)
{
u32 w=map_w;//图片宽度
u32 h=map_h;//图片高度
//printf("w=%d,h=%dn",w,h);
// u16 x=(lcd_widht-w)/2;
// u16 y=(lcd_hight-h)/2;
u16 x=0;
u16 y=0;
int i,j;
int cnt=0;
u32 rgb=0xff0000;
u8 *image_rgb=map_rgb;
u32 *p=(unsigned int *)(y*finfo.line_length+x*vinfo.bits_per_pixel/8+lcd_p);//获取到坐标地址
for(i=0;istreams[videostream];
AVCodec *vcodec=avcodec_find_decoder(stream->codecpar->codec_id);
if(!vcodec)
{
printf("未找到解码器n");
return -1;
}
/*申请视频AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。*/
res=avcodec_open2(stream->codec,vcodec,NULL);
if(res)
{
printf("打开解码器失败n");
return -1;
}
/*寻找音频解码器*/
AVStream *audstream = ps->streams[audiostream];
AVCodec *audcodec=avcodec_find_decoder(audstream->codecpar->codec_id);
if(!audcodec)
{
printf("audcodec failedn");
return -1;
}
/*申请音频AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。*/
res=avcodec_open2(audstream->codec,audcodec,NULL);
if(res)
{
printf("open audio failedn");
return -1;
}
printf("sucessn");
int sample_rate=audstream->codec->sample_rate;/*采样率*/
int channel=audstream->codec->channels;/*通道数*/
printf("sample_rate:%dn",sample_rate);
printf("channel:%dn",channel);
int sample_fmt;
switch(audstream->codec->sample_fmt)
{
case AV_SAMPLE_FMT_U8:/*8位*/
sample_fmt=AV_SAMPLE_FMT_U8;
break;
case AV_SAMPLE_FMT_FLTP:/*浮点型*/
sample_fmt=AV_SAMPLE_FMT_FLTP;
break;
}
int go_audio;
AVPacket *packet=av_malloc(sizeof(AVPacket));/*分配包*/
AVFrame *frame=av_frame_alloc();/*分配视频帧*/
AVFrame *audioframe=av_frame_alloc();/*分配音频帧*/
int audiosize=2*1024*2;
char *out_buffer = (char*)av_malloc(audiosize);
/*对解码数据进行重采样*/
SwrContext *swrCtx = swr_alloc();
enum AVSampleFormat in_sample_fmt=audstream->codec->sample_fmt;/*输入采样格式*/
enum AVSampleFormat out_sample_fmt=AV_SAMPLE_FMT_S16;/*输出采样格式:16bit PCM*/
int in_sample_rate=audstream->codec->sample_rate;/*输入采样率*/
int out_sample_rate=44100;/*输出采样率*/
uint64_t in_ch_layout=audstream->codecpar->channel_layout;//输入的声道布局
uint64_t out_ch_layout=audstream->codecpar->channel_layout;/*立体声*/
swr_alloc_set_opts(swrCtx,out_ch_layout,out_sample_fmt,out_sample_rate,/*输入音频格式*/
in_ch_layout,in_sample_fmt,in_sample_rate,/*输出音频格式*/
0,NULL);
swr_init(swrCtx);
//视频解码
AVFrame *frameRGB=av_frame_alloc();/*申请yuv空间*/
/*分配空间,进行图像转换*/
int width=ps->streams[videostream]->codecpar->width;
int height=ps->streams[videostream]->codecpar->height;
int fmt=ps->streams[videostream]->codecpar->format;/*流格式*/
map_w=800;
map_h=480;
int size=avpicture_get_size(AV_PIX_FMT_BGR24, map_w,map_h);
unsigned char *buff=NULL;
printf("w=%d,h=%d,size=%dn",width,height,size);
buff=av_malloc(size);
/*计算一帧空间大小*/
avpicture_fill((AVPicture *)frameRGB,buff,AV_PIX_FMT_BGR24,map_w,map_h);
/*转换上下文*/
struct SwsContext *swsctx=sws_getContext(width,height, fmt,map_w,map_h, AV_PIX_FMT_BGR24,SWS_BICUBIC,NULL,NULL,NULL);
/*读帧*/
int go=0;
int Framecount=0;
printf("read fream buffn");
int audio_count=0;
time_t sec=0,sec2=0;
char buff_time[200]={0};
struct tm result;
while((av_read_frame(ps,packet)>=0))
{
sec=time(NULL);
if(sec!=sec2)
{
sec2=sec;
localtime_r(&sec2,&result);//将秒单位时间转换为时间结构体
strftime(buff_time,sizeof(buff_time),"%H:%M:%S",&result);//时间格式化打印
}
if(packet->stream_index == AVMEDIA_TYPE_VIDEO)/*判断是否为视频*/
{
res=avcodec_decode_video2(ps->streams[videostream]->codec,frame,&go,packet);
if(res<0)
{
printf("avcodec_decode_video2 failedn");
return -1;
}
if(go)
{
sws_scale(swsctx,(const uint8_t **)frame->data,frame->linesize,0,map_h,(const uint8_t **)frameRGB->data,frameRGB->linesize);
lcd_p2=buff;
NT35310_DisplayStr(lcd_widht/2-strlen(buff_time)/2*16,50,32,buff_time);
LCD_Image(map_w,map_h,buff);
Framecount++;
//printf("frame index:%dn",Framecount);
}
}
else if(packet->stream_index==AVMEDIA_TYPE_AUDIO)/*音频流*/
{
res=avcodec_decode_audio4(audstream->codec,audioframe,&go_audio,packet);
if(res<0)
{
printf("decode_audio4 failedn");
return -1;
}
if(go_audio)//音频数据处理
{
}
}
}
av_free_packet(packet);
sws_freeContext(swsctx);
av_frame_free(&frame);
av_frame_free(&frameRGB);
avformat_free_context(ps);
return 0;
}
*3;j+=3)>*w>
makefile文件
CFLAGS=-I/home/wbyq/tiny4412_pack/ffmpeg-4.2.5/_install/include -L/home/wbyq/tiny4412_pack/ffmpeg-4.2.5/_install/lib
CFLAGS+=-I/home/wbyq/tiny4412_pack/x264-master/_install/include -L/home/wbyq/tiny4412_pack/x264-master/_install/lib
CFLAGS+= -lpthread -lm -ldl -lavcodec -lavfilter -lavutil -lswresample -lavdevice -lavformat -lpostproc -lswscale -lpthread -lstdc++ -lm -lasound -lx264
OBJ=main.c ascii.c
app:
arm-linux-gcc -o app $(OBJ) $(CFLAGS)
int avformat_open_input(AVFormatContext **ps, const char *filename, ff_const59 AVInputFormat *fmt, AVDictionary **options);
函数功能:打开一个输入流并读取头部信息,但编解码器不会打开
1.分配一个AVFormatContext的实例。
2.调用init_input函数初始化输入流的信息。这里会初始化AVInputFormat。
3.根据上一步初始化好的AVInputFormat的类型,调用它的read_header方法,读取文件头。
形 参: AVFormatContext **ps 媒体文件或媒体流的构成和基本信息
filename 输入文件名
AVInputFormat *fmt 输入文件格式,一般填NULL即可。
如果fmt参数非空,也就是人为的指定了一个AVInputFormat的实例,那么这个函数就不会再检测输入文件的格式了;如果fmt为空,那么这个函数就会自动探测输入文件的格式等信息。
AVDictionary **options 附加的一些选项,一般填NULL即可;
返回值: 成功返回0
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
函数功能:查找流信息
形参: AVFormatContext *ic 输入的流信息
AVDictionary **options 附加的一些选项,一般填NULL即可;
返回值: 成功返回0
int av_find_best_stream(AVFormatContext *ic,
enum AVMediaType type,
int wanted_stream_nb,
int related_stream,
AVCodec **decoder_ret,
int flags);
形参: AVFormatContext *ic 输入的流信息
type 查找类型AVMEDIA_TYPE_VIDEO视频、AVMEDIA_TYPE_AUDIO音频
wanted_stream_nb 用户请求的流编号,-1用于自动选择,
related_stream 尝试查找与此相关的流(例如,在同一程序中),如果没有,则为-1
decoder_ret 如果非空,则返回所选流的解码器,可以填NULL,
flags 标志,当前未定义任何
返回值: 成功情况下的非负流编号
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
函数功能:该函数用于 初始化 一个视音频编解码器的AVCodecContext。
形参:avctx 编解码器上下文
codec 要打开的编解码器
options 一个包含AVcodeContext和编解码器专用选项的存储工具。
返回值: 成功返回0,失败返回负数
struct SwrContext *swr_alloc_set_opts(struct SwrContext *s,
int64_t out_ch_layout,
enum AVSampleFormat out_sample_fmt,
int out_sample_rate,
int64_t in_ch_layout,
enum AVSampleFormat in_sample_fmt,
int in_sample_rate,
int log_offset,
void *log_ctx);
函数功能:分配一个重采样,设置/重置公共参数
形参: s 现有的Swr上下文(如果可用),或NULL(如果不可用)
out_ch_layout 输出声道格式
out_sample_fmt 输出采样频率
in_ch_layout 输入的声道布局
in_sample_fmt 输入采样格式
log_offse、log_ctx 日志信息,填0和NULL即可
返回值: 错误时为NULL,否则为已分配上下文
全部0条评论
快来发表一下你的评论吧 !