本篇測評由電子發(fā)燒友的優(yōu)秀測評者“ALSET”提供。
電子發(fā)燒友網(wǎng)發(fā)布了一款產(chǎn)品:米爾 MYD-Y6ULX-V2 開發(fā)板,基于 NXP i.MX6UL/i.MX6ULL處理器,該開發(fā)板被米爾稱之為經(jīng)典王牌產(chǎn)品。也是是一款嵌入式Linux入門級的開發(fā)板。本次測試目標(biāo)是在此開發(fā)板上進(jìn)行視頻工具FFmpeg的移植與測試開發(fā),測試FFmpeg在此開發(fā)板上的視頻應(yīng)用效果。
01.
FFmpeg是什么
FFmpeg是一套開源的音視頻代庫,具有非常強(qiáng)大的功能包括視頻采集功能、視頻格式轉(zhuǎn)換、視頻抓圖、給視頻加水印等。
FFmpeg視頻采集功能非常強(qiáng)大,不僅可以采集視頻采集卡或USB攝像頭的圖像,還可以進(jìn)行屏幕錄制,同時(shí)還支持以RTP方式將視頻流傳送給支持RTSP/RTMP 的流媒體服務(wù)器,支持直播應(yīng)用。采用LGPL或GPL許可證。它提供了錄制、轉(zhuǎn)換以及流化音視頻的完整解決方案。它包含了非常先進(jìn)的音頻/視頻編解碼庫libavcodec,具有高可移植性和編解碼質(zhì)量。它幾乎實(shí)現(xiàn)了所有當(dāng)下常見的數(shù)據(jù)封裝格式、多媒體傳輸協(xié)議以及音視頻編解碼器。
很多Linux桌面環(huán)境中的開源播放器VLC、MPlayer,Windows下的KMPlayer、暴風(fēng)影音以及Android下幾乎全部第三方播放器都是基于FFmpeg的,可見它的應(yīng)用非常廣泛,也是嵌入式系統(tǒng)中音視頻使用最多的代碼庫。
FFmpeg工程的幾個(gè)主要目錄:libavformat:用于各種音視頻封裝格式的生成和解析,包括獲取解碼所需信息以生成解碼上下文結(jié)構(gòu)和讀取音視頻幀等功能;libavcodec:用于各種類型聲音/圖像編解碼;libavutil:包含一些公共的工具函數(shù);libswscale:用于視頻場景比例縮放、色彩映射轉(zhuǎn)換;libpostproc:用于后期效果處理;ffmpeg:該項(xiàng)目提供的一個(gè)工具,可用于格式轉(zhuǎn)換、解碼或電視卡即時(shí)編碼等;ffsever:一個(gè) HTTP 多媒體即時(shí)廣播串流服務(wù)器;ffplay:是一個(gè)簡單的播放器,使用ffmpeg 庫解析和解碼,通過SDL顯示。
02.
FFmpeg移植編譯
1. 首先切換為交叉編譯環(huán)境
2.從github 上拉取ffmpeg源碼,考慮ffmpeg版本比較多,最新的版本增加了許多的擴(kuò)展功能,同時(shí)也增加了對硬件資源的需求??紤]該開發(fā)板為ARMv7的初級開發(fā)版,因此這里不使用最新的版本,而是使用一個(gè)兩年前的版本。使用 ffmpeg-4.1.3版本。
3. 寫配置執(zhí)行腳本
FFmpeg代碼編譯配置有非常多的選項(xiàng),為了更好的進(jìn)行配置,這里寫一個(gè)腳本用來進(jìn)行配置執(zhí)行。
腳本內(nèi)容如下:
腳本文件名:config_for_mx6ull.sh放到ffmpeg工程根目錄下這里特別注意,因?yàn)轫?xiàng)目放到是主機(jī)的虛擬機(jī)外掛的共享目錄里,共享目錄的文件系統(tǒng)是fat32,它不支持軟鏈接,因此需要設(shè)置鏈接命令為硬復(fù)制,即如下:--ln_s="cp-R"4. 執(zhí)行配置執(zhí)行腳本編寫好文配置腳本后,然后可以直接執(zhí)行,執(zhí)行完畢,輸出結(jié)果如下:
5.開始多線程編譯配置腳本執(zhí)行完畢后,會(huì)產(chǎn)生makefile文件,然后就可以進(jìn)行編譯,執(zhí)行make–j4
編譯需要大概30分鐘左右,整體編譯順利,最后編譯出結(jié)果:
6.檢查編譯的庫文件使用命令 file檢查編譯輸出的動(dòng)態(tài)庫文件和ffmpeg文件,可見是armv7執(zhí)行文件。
經(jīng)過檢查,目標(biāo)文件已經(jīng)編譯成功。7. 編譯FFmpeg附帶的測試?yán)映绦蚓幾g完ffmpeg 庫后,就可以編譯附帶的例子程序,可以更好的定制開發(fā)ffmpeg. 先編譯例子程序。例子帶的makefile 文件是x86 平臺的,需要修改一下才能編譯開發(fā)板上的版本,進(jìn)入目錄 /mnt/hgfs/MYD-Y6ULX/Proj/ffmpeg.4.1.3/ffmpeg/doc/examples下,修改Makefile.example修改如下:
修改完,就可以執(zhí)行編譯,命令如下:make-f Makefile.example
編譯很順利,一次通過。8. 瘦身動(dòng)態(tài)庫文件和ffmpeg執(zhí)行文件編譯完的庫文件體積都比較大,像| libavcodecs.so 文件達(dá)40M+,所有文件一起傳到開發(fā)板上,將非常占用開發(fā)板文件空間,因此可以對動(dòng)態(tài)庫和ffmepg執(zhí)行文件進(jìn)行瘦身一下。所謂瘦身,就是把執(zhí)行文件帶的gdb符號信息全部去掉,即可大大減少文件的體積。
9.把編譯瘦身后的文件傳送到開發(fā)板然后就可以把編譯好的庫文件和執(zhí)行文件全部傳送到開發(fā)板上,執(zhí)行命令:scplibavcodec/libavcodec.so.58root@192.168.50.150:/home/rootscplibavformat/libavformat.so.58 root@192.168.50.150:/home/rootscplibavdevice/libavdevice.so.58root@192.168.50.150:/home/rootscplibavfilter/libavfilter.so.7 root@192.168.50.150:/home/rootscplibavutil/libavutil.so.56 root@192.168.50.150:/home/rootscplibswresample/libswresample.so.3root@192.168.50.150:/home/rootscplibswscale/libswscale.so.5 root@192.168.50.150:/home/root
03.
測試FFmpeg程序
因此把FFmpeg的動(dòng)態(tài)庫和主程序都復(fù)制到板上的/home/root目錄下了,因此執(zhí)行FFmpeg時(shí),會(huì)提示找不到依賴的運(yùn)行庫,因此在開發(fā)板環(huán)境下首先設(shè)置一個(gè)動(dòng)態(tài)連接庫的路徑。
export LD_LIBRARY_PATH=/home/root
1.查看FFmpeg運(yùn)行輸出信息
然后執(zhí)行ffmpeg –version ,看一下版本信息;
可見輸出了FFmpeg版本庫正確的信息。
2. 使用FFmpeg采集視頻
執(zhí)行命令:
./ffmpeg-f v4l2 -s 320*240 -r 10 -i /dev/video2 output.yuv
把從攝像頭采集到的yuv數(shù)據(jù),使用yuvview播放器上播放,播放如圖:
顯示采集視頻成功。
3. 使用FFmpeg采集編碼視頻
板上執(zhí)行命令:
./ffmpeg -f v4l2 -s 640*360 -r 10 -i /dev/video2output1.mp4
傳輸?shù)街鳈C(jī)上,查看采集編碼的視頻內(nèi)容。
可見,能夠正確的采集并編碼出視頻文件了。
3. 使用FFmpeg采集編碼并進(jìn)行推送rtsp視頻流
因?yàn)樵诰幾gffmpeg時(shí),沒加入X264編碼庫,因此這里只能使用mpeg4編碼器,因此執(zhí)行命令如下:
./ffmpeg -t 10 -f video4linux2 -s176*144 -r 8 -i /dev/video2 -vcodec mpeg4 -f rtp rtp://192.168.50.171:554 >/ffmpeg.sdp
Rtsp推流測試,需要一個(gè)rtsp服務(wù),推流軟件先使用rtsp協(xié)議把流推送到rtsp服務(wù)上,然后播放器通過連接rtsp服務(wù)器進(jìn)行拉流播放。Rtsp服務(wù)這里使用了 RtspServer 開源rtsp服務(wù)器,地址為:
https://github.com/PHZ76/RtspServer.git
在ubuntu主機(jī)上編譯成rtsp服務(wù)程序,添加接收上行的流,再進(jìn)行進(jìn)入隊(duì)列,并進(jìn)行分發(fā)即可。操作為啟動(dòng)rtsp服務(wù)后,等待ffmpeg推流,在ffmpeg推流后,即可通過VLC 進(jìn)行播放測試。
04.
測試FFmpeg例子程序
再測試一下基于FFmpeg庫的例子程序,這里測試一下example下的幾個(gè)例程,把例程copy到板子上:
然后進(jìn)入開發(fā)板執(zhí)行一個(gè)視頻合成例程 muxing,這個(gè)例程是調(diào)用ffmpeg庫,來生成一段機(jī)器合成視頻文件。
看一下輸出的視頻文件:
05.
開發(fā)FFmpeg應(yīng)用程序
也可以基于FFmpeg庫進(jìn)行視頻應(yīng)用的開發(fā),這里從網(wǎng)上下載一段FFmpeg的應(yīng)用程序內(nèi)容,來測試一下基于上面編譯的FFmpeg庫,來開發(fā)應(yīng)用程序。
代碼如下:
int main(int argc, char **argv){ uint8_t *src_data[4], *dst_data[4]; int src_linesize[4], dst_linesize[4]; int src_w = 320, src_h = 240, dst_w, dst_h; enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P, dst_pix_fmt = AV_PIX_FMT_RGB24; const char *dst_size = NULL; const char *dst_filename = NULL; FILE *dst_file; int dst_bufsize; struct SwsContext *sws_ctx; int i, ret;
if (argc != 3) { fprintf(stderr, "Usage: %s output_file output_size\n" "API example program to show how to scale an image with libswscale.\n" "This program generates a series of pictures, rescales them to the given " "output_size and saves them to an output file named output_file\n." "\n", argv[0]); exit(1); } dst_filename = argv[1]; dst_size = argv[2];
if (av_parse_video_size(&dst_w, &dst_h, dst_size) < 0) { fprintf(stderr, "Invalid size '%s', must be in the form WxH or a valid size abbreviation\n", dst_size); exit(1); }
dst_file = fopen(dst_filename, "wb"); if (!dst_file) { fprintf(stderr, "Could not open destination file %s\n", dst_filename); exit(1); }
/* create scaling context */ sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt, dst_w, dst_h, dst_pix_fmt, SWS_BILINEAR, NULL, NULL, NULL); if (!sws_ctx) { fprintf(stderr, "Impossible to create scale context for the conversion " "fmt:%s s:%dx%d -> fmt:%s s:%dx%d\n", av_get_pix_fmt_name(src_pix_fmt), src_w, src_h, av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h); ret = AVERROR(EINVAL); goto end; }
/* allocate source and destination image buffers */ if ((ret = av_image_alloc(src_data, src_linesize, src_w, src_h, src_pix_fmt, 16)) < 0) { fprintf(stderr, "Could not allocate source image\n"); goto end; }
/* buffer is going to be written to rawvideo file, no alignment */ if ((ret = av_image_alloc(dst_data, dst_linesize, dst_w, dst_h, dst_pix_fmt, 1)) < 0) { fprintf(stderr, "Could not allocate destination image\n"); goto end; } dst_bufsize = ret;
for (i = 0; i < 100; i++) { /* generate synthetic video */ fill_yuv_image(src_data, src_linesize, src_w, src_h, i);
/* convert to destination format */ sws_scale(sws_ctx, (const uint8_t * const*)src_data, src_linesize, 0, src_h, dst_data, dst_linesize);
/* write scaled image to file */ fwrite(dst_data[0], 1, dst_bufsize, dst_file); }
fprintf(stderr, "Scaling succeeded. Play the output file with the command:\n" "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s\n", av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);
end: fclose(dst_file); av_freep(&src_data[0]); av_freep(&dst_data[0]); sws_freeContext(sws_ctx); return ret < 0;}
編譯后,板上運(yùn)行:
成功地輸出 rgb 格式的原始視頻文件,傳輸?shù)絇C上,使用yuvplayer 播放,可以看到生成的內(nèi)容:
06.
Y6ULX板上FFmpeg移植測試開發(fā)總結(jié)
通過從這次在MYD-Y6ULL開發(fā)板上進(jìn)行FFmpeg的移植編譯與應(yīng)用開發(fā)測試過程看,F(xiàn)Fmpeg在該開發(fā)板上移植非常容易,而且基本上代碼不做任何改動(dòng),能夠一次編譯通過。也說明了該開發(fā)板的C/C++的開發(fā)工具與庫支持比較完善,對這樣復(fù)雜的工程也有很好的支持。 這也大大方便了試用該方案進(jìn)行音視頻開發(fā)的可能性,能夠利用開源社區(qū)大量的音視頻應(yīng)用資源,開發(fā)出多種嵌入式的音視頻應(yīng)用。
-
嵌入式
+關(guān)注
關(guān)注
5059文章
18975瀏覽量
302072 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
4898瀏覽量
97064 -
米爾
+關(guān)注
關(guān)注
0文章
47瀏覽量
7903
發(fā)布評論請先 登錄
相關(guān)推薦
評論