【米尔王牌产品MYD-Y6ULX-V2开发板试用体验】视频工具ffmpeg的移植与测试开发 大信(QQ:8125036)
电子发烧友网推出了一款米尔的产品:MYD-Y6ULX-V2开发板,该开发板被米尔称之为经典王牌产品。也是是一款嵌入式linux入门级的开发板。本次测试目标是在此开发板上进行视频工具ffmpeg的移植与测试开发,测试ffmpeg在此开发板上进行视频应用测试。
一、FFmpeg简介 FFmpeg是一套开源的音视频代库,具有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等
FFmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以RTP方式将视频流传送给支持RTSP/RTMP 的流媒体服务器,支持直播应用。 采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,具有高可移植性和编解码质量。它几乎实现了所有当下常见的数据封装格式、多媒体传输协议以及音视频编解码器。
很多Linux桌面环境中的开源播放器VLC、MPlayer,Windows下的KMPlayer、暴风影音以及Android下几乎全部第三方播放器都是基于FFMPEG的,可见它的应用非常广泛,也是嵌入式系统中音视频使用最多的代码库。
Ffmpeg工程的几个主要目录:
libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构
和读取音视频帧等功能;
libavcodec:用于各种类型声音/图像编解码;
libswscale:用于视频场景比例缩放、色彩映射转换;
libpostproc:用于后期效果处理;
ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
ffsever:一个 HTTP 多媒体即时广播串流服务器;
ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示
二、Ffmpeg 移植编译1. 首先切换为交叉编译环境
2.从github 上拉取ffmpeg源码,考虑ffmpeg版本比较多,最新的版本增加了许多的扩展功能,同时也增加了对硬件资源的需求。考虑该开发板为
ARMv7的初级开发版,因此这里不使用最新的版本,而是使用一个两年前的版本。使用 ffmpeg-4.1.3版本。
3. 写配置执行脚本
Ffmpeg代码编译配置有非常多的选项,为了更好的进行配置,这里写一个脚本用来进行配置执行。
脚本内容如下:
脚本文件名:
config_for_mx6ull.sh
放到ffmpeg工程根目录下
这里特别注意,因为项目放到是主机的虚拟机外挂的共享目录里,共享目录的文件系统是fat32,它不支持软链接,因此需要设置链接命令为硬复制,即如下:
--ln_s="cp-R"
4. 执行配置执行脚本
编写好文配置脚本后,然后可以直接执行,执行完毕,输出结果如下:
4.开始多线程编译
配置脚本执行完毕后,会产生makefile文件,然后就可以进行编译,执行
make–j4
编译需要大概30分钟左右,整体编译顺利,最后编译出结果:
5.检查编译的库文件
使用命令 file 检查编译输出的动态库文件和ffmpeg文件,可见是armv7执行文件。
经过检查,目标文件已经编译成功。
6. 编译ffmpeg附带的测试例子程序
编译完ffmpeg库后,就可以编译附带的例子程序,可以更好的定制开发ffmpeg.先编译例子程序。例子带的makefile文件是x86平台的,需要修改一下才能编译开发板上的版本,进入目录 /mnt/hgfs/MYD-Y6ULX/Proj/ffmpeg.4.1.3/ffmpeg/doc/examples下,修改Makefile.example
修改如下:
修改完,就可以执行编译,命令如下:
make-f Makefile.example
编译很顺利,一次通过。
7. 瘦身动态库文件和ffmpeg执行文件
编译完的库文件体积都比较大,像| libavcodecs.so 文件达40M+,所有文件一起传到开发板上,将非常占用开发板文件空间,因此可以对动态库和ffmepg执行文件进行瘦身一下。所谓瘦身,就是把执行文件带的gdb符号信息全部去掉,即可大大减少文件的体积。
8.把编译瘦身后的文件传送到开发板
然后就可以把编译好的库文件和执行文件全部传送到开发板上,执行命令:
三、测试FFMPEG程序因此把ffmpeg的动态库和主程序都复制到板上的/home/root目录下了,因此执行ffmpeg时,会提示找不到依赖的运行库,因此在开发板环境下首先设置一个动态连接库的路径
export LD_LIBRARY_PATH=/home/root
1.查看fmpeg运行输出信息
然后执行ffmpeg –version ,看一下版本信息;
可见输出了ffmpeg版本库正确的信息。
1. 使用ffmpeg采集视频
执行命令:
./ffmpeg-f v4l2 -s 320*240 -r 10 -i /dev/video2 output.yuv
把从摄像头采集到的yuv数据,使用yuvview播放器上播放,播放如图:
显示采集视频成功。
2. 使用ffmpeg采集编码视频
板上执行命令
./ffmpeg -f v4l2 -s 640*360 -r 10 -i /dev/video2output1.mp4
传输到主机上,查看采集编码的视频内容
可见,能够正确的采集并编码出视频文件了。
3. 使用ffmpeg采集编码并进行推送rtsp视频流
因为在编译ffmpeg时,没用加入X264编码库,因此这里只能使用mpeg4编码器,因此执行命令如下:
./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推流测试,需要一个rtsp服务,推流软件先使用rtsp协议把流推送到rtsp服务上,然后播放器通过连接rtsp服务器进行拉流播放。Rtsp服务这里使用了 RtspServer 开源rtsp服务器,地址为:
https://github.com/PHZ76/RtspServer.git
在ubuntu主机上编译成rtsp服务程序,添加接收上行的流,再进行进入队列,并进行分发即可。操作为启动rtsp服务后,等待ffmpeg推流,在ffmpeg推流后,即可通过VLC 进行播放测试。
四、测试ffmpeg例子程序再测试一下基于ffmpeg库的例子程序,这里测试一下examle下的几个例程,把例程copy到板子上:
然后进入开发板执行一个视频合成例程 muxing,这个例程是调用ffmpeg库,来生成一段机器合成视频文件。
看一下输出的视频文件
五、开发ffmpeg应用程序也可以基于ffmpeg库进行视频应用的开发,这里从网上下载一段ffmpeg的应用程序内容,来测试一下基于上面编译的ffmpeg库,来开发应用程序。
代码如下:
- 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_sizen"
- "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_filen."
- "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 abbreviationn",
- dst_size);
- exit(1);
- }
- dst_file = fopen(dst_filename, "wb");
- if (!dst_file) {
- fprintf(stderr, "Could not open destination file %sn", 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%dn",
- 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 imagen");
- 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 imagen");
- 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 %sn",
- 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;
- }
编译后,板上运行
成功的输出 rgb 格式的原始视频文件,传输到PC上,使用yuvplayer 播放,可以看到生成的内容:
六、Y6ULL板上ffmpeg移植测试开发总结 通过从这次在MYD-Y6ULL开发板上进行ffmpeg的移植编译与应用开发测试过程看,ffmpeg在该开发板上移植非常容易,而且基本上代码不做任何改动,能够一次编译通过。也说明了该开发板的c/c++的开发工具与库支持比较完善,对这样复杂的工程也有很好的支持。
这也大大方便了试用该方案进行音视频开发的可能性,能够利用开源社区大量的音视频应用资源,开发出多种嵌入式的音视频应用。