米尔电子
直播中

ALSET

3年用户 269经验值
擅长:可编程逻辑,电源/新能源,嵌入式技术,处理器/DSP
私信 关注
[技术]

【米尔王牌产品MYD-Y6ULX-V2开发板试用体验】4.视频工具ffmpeg的移植与测试开发

FFmpeg采集输出视频

【米尔王牌产品MYD-Y6ULX-V2开发板试用体验】视频工具ffmpeg的移植与测试开发
大信(QQ:8125036)
      电子发烧友网推出了一款米尔的产品:MYD-Y6ULX-V2开发板,该开发板被米尔称之为经典王牌产品。也是是一款嵌入式linux入门级的开发板。本次测试目标是在此开发板上进行视频工具ffmpeg的移植与测试开发,测试ffmpeg在此开发板上进行视频应用测试。
1.jpg

一、FFmpeg简介
    FFmpeg是一套开源的音视频代库,具有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等
FFmpeg视频采集功能非常强大,不仅可以采集视频采集卡或USB摄像头的图像,还可以进行屏幕录制,同时还支持以RTP方式将视频流传送给支持RTSP/RTMP 的流媒体服务器,支持直播应用。 采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,具有高可移植性和编解码质量。它几乎实现了所有当下常见的数据封装格式、多媒体传输协议以及音视频编解码器。
很多Linux桌面环境中的开源播放器VLC、MPlayer,Windows下的KMPlayer、暴风影音以及Android下几乎全部第三方播放器都是基于FFMPEG的,可见它的应用非常广泛,也是嵌入式系统中音视频使用最多的代码库。
Ffmpeg工程的几个主要目录:
libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构
和读取音视频帧等功能;
libavcodec:用于各种类型声音/图像编解码;
libavutil:包含一些公共的工具函数;
libswscale:用于视频场景比例缩放、色彩映射转换;
libpostproc:用于后期效果处理;
ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
ffsever:一个 HTTP 多媒体即时广播串流服务器;
ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示
2.jpg

二、Ffmpeg 移植编译
1. 首先切换为交叉编译环境
3.jpg
2.从github 上拉取ffmpeg源码,考虑ffmpeg版本比较多,最新的版本增加了许多的扩展功能,同时也增加了对硬件资源的需求。考虑该开发板为ARMv7的初级开发版,因此这里不使用最新的版本,而是使用一个两年前的版本。使用 ffmpeg-4.1.3版本。
gitclone https://gitee.com/mirrors/ffmpeg.git -b release/4.1 --depth=1
4.jpg
5.jpg
3. 写配置执行脚本
Ffmpeg代码编译配置有非常多的选项,为了更好的进行配置,这里写一个脚本用来进行配置执行。
脚本内容如下:
6.jpg
脚本文件名:
config_for_mx6ull.sh
放到ffmpeg工程根目录下
这里特别注意,因为项目放到是主机的虚拟机外挂的共享目录里,共享目录的文件系统是fat32,它不支持软链接,因此需要设置链接命令为硬复制,即如下:
--ln_s="cp-R"
4. 执行配置执行脚本
编写好文配置脚本后,然后可以直接执行,执行完毕,输出结果如下:
7.jpg
4.开始多线程编译
配置脚本执行完毕后,会产生makefile文件,然后就可以进行编译,执行
make–j4
8.jpg
编译需要大概30分钟左右,整体编译顺利,最后编译出结果:
9.jpg
5.检查编译的库文件
使用命令 file 检查编译输出的动态库文件和ffmpeg文件,可见是armv7执行文件。
10.jpg
经过检查,目标文件已经编译成功。
6. 编译ffmpeg附带的测试例子程序
编译完ffmpeg库后,就可以编译附带的例子程序,可以更好的定制开发ffmpeg.先编译例子程序。例子带的makefile文件是x86平台的,需要修改一下才能编译开发板上的版本,进入目录 /mnt/hgfs/MYD-Y6ULX/Proj/ffmpeg.4.1.3/ffmpeg/doc/examples下,修改Makefile.example
修改如下:
11.jpg
修改完,就可以执行编译,命令如下:
make-f Makefile.example
12.jpg
13.jpg
编译很顺利,一次通过。
7. 瘦身动态库文件和ffmpeg执行文件
编译完的库文件体积都比较大,像| libavcodecs.so 文件达40M+,所有文件一起传到开发板上,将非常占用开发板文件空间,因此可以对动态库和ffmepg执行文件进行瘦身一下。所谓瘦身,就是把执行文件带的gdb符号信息全部去掉,即可大大减少文件的体积。
14.jpg
8.把编译瘦身后的文件传送到开发板
然后就可以把编译好的库文件和执行文件全部传送到开发板上,执行命令:
scplibavcodec/libavcodec.so.58    root@192.168.50.150:/home/root
scplibavformat/libavformat.so.58  root@192.168.50.150:/home/root
scplibavdevice/libavdevice.so.58  root@192.168.50.150:/home/root
scplibavfilter/libavfilter.so.7   root@192.168.50.150:/home/root
scplibavutil/libavutil.so.56      root@192.168.50.150:/home/root
scplibswresample/libswresample.so.3  root@192.168.50.150:/home/root
scplibswscale/libswscale.so.5     root@192.168.50.150:/home/root
15.jpg
三、测试FFMPEG程序因此把ffmpeg的动态库和主程序都复制到板上的/home/root目录下了,因此执行ffmpeg时,会提示找不到依赖的运行库,因此在开发板环境下首先设置一个动态连接库的路径
export LD_LIBRARY_PATH=/home/root
1.查看fmpeg运行输出信息
然后执行ffmpeg –version ,看一下版本信息;
16.jpg

可见输出了ffmpeg版本库正确的信息。
1. 使用ffmpeg采集视频
执行命令:
./ffmpeg-f v4l2 -s 320*240 -r 10 -i /dev/video2 output.yuv
17.jpg
把从摄像头采集到的yuv数据,使用yuvview播放器上播放,播放如图:
18.jpg
显示采集视频成功。
2. 使用ffmpeg采集编码视频
板上执行命令
./ffmpeg -f v4l2 -s 640*360 -r 10 -i /dev/video2output1.mp4
19.jpg
20.jpg
传输到主机上,查看采集编码的视频内容
21.jpg
可见,能够正确的采集并编码出视频文件了。
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 进行播放测试。
22.jpg
23.jpg

四、测试ffmpeg例子程序再测试一下基于ffmpeg库的例子程序,这里测试一下examle下的几个例程,把例程copy到板子上:
24.jpg
然后进入开发板执行一个视频合成例程 muxing,这个例程是调用ffmpeg库,来生成一段机器合成视频文件。
25.jpg
看一下输出的视频文件
26.jpg

五、开发ffmpeg应用程序
也可以基于ffmpeg库进行视频应用的开发,这里从网上下载一段ffmpeg的应用程序内容,来测试一下基于上面编译的ffmpeg库,来开发应用程序。
代码如下:

  1. int main(int argc, char **argv)
  2. {
  3.     uint8_t *src_data[4], *dst_data[4];
  4.     int src_linesize[4], dst_linesize[4];
  5.     int src_w = 320, src_h = 240, dst_w, dst_h;
  6.     enum AVPixelFormat src_pix_fmt = AV_PIX_FMT_YUV420P, dst_pix_fmt = AV_PIX_FMT_RGB24;
  7.     const char *dst_size = NULL;
  8.     const char *dst_filename = NULL;
  9.     FILE *dst_file;
  10.     int dst_bufsize;
  11.     struct SwsContext *sws_ctx;
  12.     int i, ret;

  13.     if (argc != 3) {
  14.         fprintf(stderr, "Usage: %s output_file output_sizen"
  15.                 "API example program to show how to scale an image with libswscale.n"
  16.                 "This program generates a series of pictures, rescales them to the given "
  17.                 "output_size and saves them to an output file named output_filen."
  18.                 "n", argv[0]);
  19.         exit(1);
  20.     }
  21.     dst_filename = argv[1];
  22.     dst_size     = argv[2];

  23.     if (av_parse_video_size(&dst_w, &dst_h, dst_size) < 0) {
  24.         fprintf(stderr,
  25.                 "Invalid size '%s', must be in the form WxH or a valid size abbreviationn",
  26.                 dst_size);
  27.         exit(1);
  28.     }

  29.     dst_file = fopen(dst_filename, "wb");
  30.     if (!dst_file) {
  31.         fprintf(stderr, "Could not open destination file %sn", dst_filename);
  32.         exit(1);
  33.     }

  34.     /* create scaling context */
  35.     sws_ctx = sws_getContext(src_w, src_h, src_pix_fmt,
  36.                              dst_w, dst_h, dst_pix_fmt,
  37.                              SWS_BILINEAR, NULL, NULL, NULL);
  38.     if (!sws_ctx) {
  39.         fprintf(stderr,
  40.                 "Impossible to create scale context for the conversion "
  41.                 "fmt:%s s:%dx%d -> fmt:%s s:%dx%dn",
  42.                 av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
  43.                 av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h);
  44.         ret = AVERROR(EINVAL);
  45.         goto end;
  46.     }

  47.     /* allocate source and destination image buffers */
  48.     if ((ret = av_image_alloc(src_data, src_linesize,
  49.                               src_w, src_h, src_pix_fmt, 16)) < 0) {
  50.         fprintf(stderr, "Could not allocate source imagen");
  51.         goto end;
  52.     }

  53.     /* buffer is going to be written to rawvideo file, no alignment */
  54.     if ((ret = av_image_alloc(dst_data, dst_linesize,
  55.                               dst_w, dst_h, dst_pix_fmt, 1)) < 0) {
  56.         fprintf(stderr, "Could not allocate destination imagen");
  57.         goto end;
  58.     }
  59.     dst_bufsize = ret;

  60.     for (i = 0; i < 100; i++) {
  61.         /* generate synthetic video */
  62.         fill_yuv_image(src_data, src_linesize, src_w, src_h, i);

  63.         /* convert to destination format */
  64.         sws_scale(sws_ctx, (const uint8_t * const*)src_data,
  65.                   src_linesize, 0, src_h, dst_data, dst_linesize);

  66.         /* write scaled image to file */
  67.         fwrite(dst_data[0], 1, dst_bufsize, dst_file);
  68.     }

  69.     fprintf(stderr, "Scaling succeeded. Play the output file with the command:n"
  70.            "ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %sn",
  71.            av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename);

  72. end:
  73.     fclose(dst_file);
  74.     av_freep(&src_data[0]);
  75.     av_freep(&dst_data[0]);
  76.     sws_freeContext(sws_ctx);
  77.     return ret < 0;
  78. }


编译后,板上运行
27.jpg
成功的输出 rgb 格式的原始视频文件,传输到PC上,使用yuvplayer 播放,可以看到生成的内容:
28.jpg

六、Y6ULL板上ffmpeg移植测试开发总结
    通过从这次在MYD-Y6ULL开发板上进行ffmpeg的移植编译与应用开发测试过程看,ffmpeg在该开发板上移植非常容易,而且基本上代码不做任何改动,能够一次编译通过。也说明了该开发板的c/c++的开发工具与库支持比较完善,对这样复杂的工程也有很好的支持。
    这也大大方便了试用该方案进行音视频开发的可能性,能够利用开源社区大量的音视频应用资源,开发出多种嵌入式的音视频应用。

生成视频内容

更多回帖

发帖
×
20
完善资料,
赚取积分