Tiny4412移植ffmpeg實現視頻解碼
?FFmpeg是一套可以用來記錄、轉換數字音頻、視頻,并能將其轉化為流的開源計算機程序。采用LGPL或GPL許可證。它提供了錄制、轉換以及流化音視頻的完整解決方案。它包含了非常先進的音頻/視頻編解碼庫libavcodec,為了保證高可移植性和編解碼質量,libavcodec里很多code都是從頭開發的。
1.硬件平臺
硬件平臺:Tiny4412(Cortex-A9)
交叉編譯器:arm-linux-gcc(Ver4.5.1)
開發板系統: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
若編譯出現報錯: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
?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可變形參結構體*/
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)
4.相關函數介紹
4.1 打開輸入流并讀取頭數據avformat_open_input
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
4.2 查找流信息avformat_find_stream_info
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
函數功能:查找流信息
形參: AVFormatContext *ic 輸入的流信息
???AVDictionary **options 附加的一些選項,一般填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 用戶請求的流編號,-1用于自動選擇,
????related_stream 嘗試查找與此相關的流(例如,在同一程序中),如果沒有,則為-1
????decoder_ret 如果非空,則返回所選流的解碼器,可以填NULL,
???? flags 標志,當前未定義任何
返回值: 成功情況下的非負流編號
4.4 初始化音視頻編解碼器avcodec_open2
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
函數功能:該函數用于 初始化 一個視音頻編解碼器的AVCodecContext。
形參:avctx 編解碼器上下文
???codec 要打開的編解碼器
???options 一個包含AVcodeContext和編解碼器專用選項的存儲工具。
返回值: 成功返回0,失敗返回負數
4.5 分配一個重采樣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);
函數功能:分配一個重采樣,設置/重置公共參數
形參: s 現有的Swr上下文(如果可用),或NULL(如果不可用)
????out_ch_layout 輸出聲道格式
????out_sample_fmt 輸出采樣頻率
????in_ch_layout 輸入的聲道布局
????in_sample_fmt 輸入采樣格式
????log_offse、log_ctx 日志信息,填0和NULL即可
返回值: 錯誤時為NULL,否則為已分配上下文
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
開源
+關注
關注
3文章
3348瀏覽量
42498 -
視頻解碼
+關注
關注
1文章
49瀏覽量
18158 -
ffmpeg
+關注
關注
0文章
46瀏覽量
7403
發布評論請先 登錄
相關推薦
Linux下基于ffmpeg音視頻解碼
FFmpeg是一套可以用來記錄、轉換數字音頻、視頻,并能將其轉化為流的開源計算機程序。采用LGPL或GPL許可證。它提供了錄制、轉換以及流化音視頻的完整解決方案。它包含了非常先進的音頻/視頻
如何移植FFmpeg
?FFmpeg是一款專門用于處理數字音頻和視頻,支持錄制、轉換,并能將這些媒體內容轉化為實時流數據的開源計算機程序。它遵循LGPL或GPL許可協議,為用戶提供了涵蓋音視頻錄制、格式轉換及流媒體分發
【OK210申請】基于OK210的WIFI無線視頻監控小車的設計與實現
申請理由:1.有著對ARM的渴求度,對LINUX有一定的掌握2.本著自己為畢業一年的硬件開發工程師,希望能夠接觸到軟硬結合的ARM系統3.資金有限,只能獲得免費申請4.手里有一塊TINY4412板子
發表于 08-04 16:34
免費試用“Tiny4412開發板——友善之臂Cortex-A9”
本帖最后由 L490351555 于 2015-8-19 08:38 編輯
大家好,這兩天咱們的論壇搞了一個開發板投票試用活動。現在有一個投票項就是“Tiny4412開發板——友善之臂
發表于 08-18 19:09
請問在4412的USB驅動程序里該如何修改?
用tiny4412遇到一個問題,4412作為USB設備與作為主機的PC連接,物理連接是USB線,在4412上需要把USB上的特殊數據解析出來,當做并口數據處理。請問在4412的USB驅
發表于 05-17 00:12
Tiny4412-Uboot啟動后無法加載uImage
好吧。。在這里先祈求,有哪位大大,或者老師,能關注下。個人一度試圖移植tiny4412的uboot和kernel還有根文件系統。。。。。然后順帶學習一下設備樹的用法這個是uboot配置ls/dev
發表于 08-30 05:45
TINY4412 UART程序設計得相關資料分享
嵌入式實驗: TINY4412 UART 程序設計一、實驗目的熟悉UART通信相關的寄存器的功能和設置方法,設置引腳復用,選擇UART接收和發送對應的引腳用于UART通信,數據流格式設置,設置
發表于 11-09 06:11
如何實現Tiny4412通過NRF24L01 2.4G無線模塊發送數據呢
Linux下SPI設備驅動該怎樣去編寫呢?如何實現Tiny4412通過NRF24L01 2.4G無線模塊發送數據呢?
發表于 12-17 06:36
iny4412嵌入式Linux操作系統啟動流程是怎樣的
本次介紹一下友善之臂tiny4412嵌入式Linux操作系統分析首先,可以從官方提供的用戶手冊中得到這樣一張圖,它簡單表達了裸機燒寫啟動系統的流程,不過這張圖中缺少對BL2的描述,所以我就自己手繪了
發表于 12-20 07:50
基于FFmpeg + SDL2實現視頻播放功能資料分享
1、使用FFmpeg+SDL2在ART-Pi Smart平臺上實現視頻播放功能簡介X264 是由 VideoLAN 開發的一個免費開源軟件庫和命令行實用程序,用于將視頻流編碼為 H.2
發表于 08-05 11:40
FFMPEG視頻編解碼流程 H.264硬件編解碼實現
本文闡述了基于FFMpeg的 H.264視頻 硬件編解碼在 S3C6410 處理器上的實現方法,為數字娛樂、視頻監控和
發表于 04-03 11:28
?1.9w次閱讀
嵌入式實驗: TINY4412 UART 程序設計
嵌入式實驗: TINY4412 UART 程序設計一、實驗目的熟悉UART通信相關的寄存器的功能和設置方法,設置引腳復用,選擇UART接收和發送對應的引腳用于UART通信,數據流格式設置,設置
發表于 11-03 20:06
?13次下載
評論