Tiny4412移植ffmpeg實(shí)現(xiàn)視頻解碼
?FFmpeg是一套可以用來記錄、轉(zhuǎn)換數(shù)字音頻、視頻,并能將其轉(zhuǎn)化為流的開源計(jì)算機(jī)程序。采用LGPL或GPL許可證。它提供了錄制、轉(zhuǎn)換以及流化音視頻的完整解決方案。它包含了非常先進(jìn)的音頻/視頻編解碼庫libavcodec,為了保證高可移植性和編解碼質(zhì)量,libavcodec里很多code都是從頭開發(fā)的。
1.硬件平臺(tái)
硬件平臺(tái):Tiny4412(Cortex-A9)
交叉編譯器:arm-linux-gcc(Ver4.5.1)
開發(fā)板系統(tǒng):linux3.5
ffmpeg版本:ffmpeg-4.2.5
2.ffmpeg源碼編譯
??安裝ffmpeg庫之前需要先安裝x264庫。
?2.1 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

若編譯出現(xiàn)報(bào)錯(cuò):undefined reference to `clock_gettime’,則添加動(dòng)態(tài)鏈接: -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
?2.2 ffmpeg編譯安裝
??下載地址: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
3.視頻解碼
#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可變形參結(jié)構(gòu)體*/
static struct fb_fix_screeninfo finfo;/*lcd固定參數(shù)結(jié)構(gòu)體*/
static unsigned char *lcd_p;/*lcd緩沖區(qū)首地址*/
u32 lcd_widht;/*LCD屏寬度*/
u32 lcd_hight;/*LCD屏高度*/
static unsigned char *lcd_p2;/*圖像數(shù)據(jù)*/
u32 map_w;
u32 map_h;
/*畫點(diǎn)函數(shù)*/
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;
}
/*畫點(diǎn)函數(shù)*/
void LCD_DrawPoint2(int x,int y,int c)
{
unsigned int *p=(unsigned int *)(y*map_w*3+x*3+lcd_p2);
*p=c;
}
/*顯示數(shù)據(jù)*/
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;
}
}
}
/*顯示圖片函數(shù)(居中顯示)*/
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);//獲取到坐標(biāo)地址
for(i=0;istreams[videostream];
AVCodec *vcodec=avcodec_find_decoder(stream->codecpar->codec_id);
if(!vcodec)
{
printf("未找到解碼器n");
return -1;
}
/*申請(qǐng)視頻AVCodecContext空間。需要傳遞一個(gè)編碼器,也可以不傳,但不會(huì)包含編碼器。*/
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;
}
/*申請(qǐng)音頻AVCodecContext空間。需要傳遞一個(gè)編碼器,也可以不傳,但不會(huì)包含編碼器。*/
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;/*通道數(shù)*/
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:/*浮點(diǎn)型*/
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);
/*對(duì)解碼數(shù)據(jù)進(jìn)行重采樣*/
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();/*申請(qǐng)yuv空間*/
/*分配空間,進(jìn)行圖像轉(zhuǎn)換*/
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);
/*計(jì)算一幀空間大小*/
avpicture_fill((AVPicture *)frameRGB,buff,AV_PIX_FMT_BGR24,map_w,map_h);
/*轉(zhuǎn)換上下文*/
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);//將秒單位時(shí)間轉(zhuǎn)換為時(shí)間結(jié)構(gòu)體
strftime(buff_time,sizeof(buff_time),"%H:%M:%S",&result);//時(shí)間格式化打印
}
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)//音頻數(shù)據(jù)處理
{
}
}
}
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)
4.相關(guān)函數(shù)介紹
4.1 打開輸入流并讀取頭數(shù)據(jù)avformat_open_input
int avformat_open_input(AVFormatContext **ps, const char *filename, ff_const59 AVInputFormat *fmt, AVDictionary **options);
函數(shù)功能:打開一個(gè)輸入流并讀取頭部信息,但編解碼器不會(huì)打開
???1.分配一個(gè)AVFormatContext的實(shí)例。
???2.調(diào)用init_input函數(shù)初始化輸入流的信息。這里會(huì)初始化AVInputFormat。
???3.根據(jù)上一步初始化好的AVInputFormat的類型,調(diào)用它的read_header方法,讀取文件頭。
形 參: AVFormatContext **ps 媒體文件或媒體流的構(gòu)成和基本信息
???filename 輸入文件名
???AVInputFormat *fmt 輸入文件格式,一般填NULL即可。
?????如果fmt參數(shù)非空,也就是人為的指定了一個(gè)AVInputFormat的實(shí)例,那么這個(gè)函數(shù)就不會(huì)再檢測(cè)輸入文件的格式了;如果fmt為空,那么這個(gè)函數(shù)就會(huì)自動(dòng)探測(cè)輸入文件的格式等信息。
?????AVDictionary **options 附加的一些選項(xiàng),一般填NULL即可;
返回值: 成功返回0
4.2 查找流信息avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
函數(shù)功能:查找流信息
形參: AVFormatContext *ic 輸入的流信息
???AVDictionary **options 附加的一些選項(xiàng),一般填NULL即可;
返回值: 成功返回0
4.3 查找輸入流中的音視頻信息av_find_best_stream
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 用戶請(qǐng)求的流編號(hào),-1用于自動(dòng)選擇,
????related_stream 嘗試查找與此相關(guān)的流(例如,在同一程序中),如果沒有,則為-1
????decoder_ret 如果非空,則返回所選流的解碼器,可以填NULL,
???? flags 標(biāo)志,當(dāng)前未定義任何
返回值: 成功情況下的非負(fù)流編號(hào)
4.4 初始化音視頻編解碼器avcodec_open2
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
函數(shù)功能:該函數(shù)用于 初始化 一個(gè)視音頻編解碼器的AVCodecContext。
形參:avctx 編解碼器上下文
???codec 要打開的編解碼器
???options 一個(gè)包含AVcodeContext和編解碼器專用選項(xiàng)的存儲(chǔ)工具。
返回值: 成功返回0,失敗返回負(fù)數(shù)
4.5 分配一個(gè)重采樣swr_alloc_set_opts
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);
函數(shù)功能:分配一個(gè)重采樣,設(shè)置/重置公共參數(shù)
形參: s 現(xiàn)有的Swr上下文(如果可用),或NULL(如果不可用)
????out_ch_layout 輸出聲道格式
????out_sample_fmt 輸出采樣頻率
????in_ch_layout 輸入的聲道布局
????in_sample_fmt 輸入采樣格式
????log_offse、log_ctx 日志信息,填0和NULL即可
返回值: 錯(cuò)誤時(shí)為NULL,否則為已分配上下文
-
開源
+關(guān)注
關(guān)注
3文章
3533瀏覽量
43292 -
視頻解碼
+關(guān)注
關(guān)注
1文章
51瀏覽量
18437 -
ffmpeg
+關(guān)注
關(guān)注
0文章
46瀏覽量
7558
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
Linux下基于ffmpeg音視頻解碼

如何移植FFmpeg

【OK210申請(qǐng)】基于OK210的WIFI無線視頻監(jiān)控小車的設(shè)計(jì)與實(shí)現(xiàn)
免費(fèi)試用“Tiny4412開發(fā)板——友善之臂Cortex-A9”
請(qǐng)問在4412的USB驅(qū)動(dòng)程序里該如何修改?
Tiny4412-Uboot啟動(dòng)后無法加載uImage
怎么實(shí)現(xiàn)ffmpeg解碼器到龍芯3B的移植?
TINY4412 UART程序設(shè)計(jì)得相關(guān)資料分享
如何實(shí)現(xiàn)Tiny4412通過NRF24L01 2.4G無線模塊發(fā)送數(shù)據(jù)呢
iny4412嵌入式Linux操作系統(tǒng)啟動(dòng)流程是怎樣的
ffmpeg支持的音視頻格式有哪些
FFMPEG視頻編解碼流程 H.264硬件編解碼實(shí)現(xiàn)

嵌入式實(shí)驗(yàn): TINY4412 UART 程序設(shè)計(jì)

在QT上構(gòu)建ffmpeg環(huán)境實(shí)現(xiàn)音頻的解碼

評(píng)論