谷动谷力

 找回密码
 立即注册
查看: 2782|回复: 0
打印 上一主题 下一主题
收起左侧

RT-Thread Smart基于 FFmpeg + SDL2 在 ART-Pi Smart 平台上视频播放.

[复制链接]
跳转到指定楼层
楼主
发表于 2022-4-28 14:40:59 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 fannifu 于 2022-4-28 14:43 编辑

RT-Thread Smart基于 FFmpeg + SDL2  在 ART-Pi Smart 平台上实现视频播放


基于文档《使用 VS Code 开发 GUI 应用》,使用 FFmpeg+SDL2 在 ART-Pi Smart 平台上实现视频播放功能;由于 ART-Pi Smart 没有音频模块,所以没有实现音频的解码播放。

简介
X264 是由 VideoLAN 开发的一个免费开源软件库和命令行实用程序,用于将视频流编码为 H.264 / MPEG-4 AVC 格式,根据GNU通用公共许可证的条款发布的。
FFmpeg 是一个编解码库,功能丰富,其自带 H.264 解码功能,但是要实现 H.264 编码需要集成 X264 将其作为编码器。

下载
  1. git clone https://code.videolan.org/videolan/x264.git
复制代码




源码目录:

交叉编译

  • 在 x264 文件夹同级目录下创建 build_x264.sh 文件
  • build_x264.sh 文件内容如下,注意:RTT_EXEC_PATH 和 ROOTDIR 修改为自己本地路径:
    # Get initial variablesexport RTT_EXEC_PATH=/home/liukang/repo/ART-Pi-smart/tools/gnu_gcc/arm-linux-musleabi_for_x86_64-pc-linux-gnu/binexport PATH=$PATHRTT_EXEC_PATHRTT_EXEC_PATH/../arm-linux-musleabi/binexport CROSS_COMPILE="arm-linux-musleabi"if [ "$1" == "debug" ]; then    export CFLAGS="-march=armv7-a -marm -msoft-float -D__RTTHREAD__ -O0 -g -gdwarf-2 -Wall -n --static"else    export CFLAGS="-march=armv7-a -marm -msoft-float -D__RTTHREAD__ -O2 -Wall -n --static"fiexport AR=${CROSS_COMPILE}-arexport AS=${CROSS_COMPILE}-asexport LD=${CROSS_COMPILE}-ldexport RANLIB=${CROSS_COMPILE}-ranlibexport CC=${CROSS_COMPILE}-gccexport CXX=${CROSS_COMPILE}-g++export NM=${CROSS_COMPILE}-nmROOTDIR="/home/liukang/repo/ART-Pi-smart/userapps"APP_NAME="x264"APP_DIR=${APP_NAME}LIB_DIR=${ROOTDIR}/sdk/libINC_DIR=${ROOTDIR}/sdk/includeRT_DIR=${ROOTDIR}/sdk/rt-threadRT_INC=" -I. -Iinclude -I${ROOTDIR} -I${RT_DIR}/include -I${RT_DIR}/components/dfs -I${RT_DIR}/components/drivers -I${RT_DIR}/components/finsh -I${RT_DIR}/components/net -I${INC_DIR}/sdl -DHAVE_CCONFIG_H"RT_INC+=" -I${ROOTDIR}/../kernel/bsp/imx6ull-artpi-smart/drivers/"export CPPFLAGS=${RT_INC}export LDFLAGS="-L${LIB_DIR} "export LIBS="-T ${ROOTDIR}/linker_scripts/arm/cortex-a/link.lds -march=armv7-a -marm -msoft-float -L${RT_DIR}/lib -Wl,--whole-archive -lrtthread -Wl,--no-whole-archive -n -static -Wl,--start-group -lc -lgcc -lrtthread -Wl,--end-group"# default buildfunction builddef() {    cd ${APP_DIR}    ./configure \    --prefix=/home/liukang/repo/x264lib \    --host=${CROSS_COMPILE} \    --disable-asm \    --enable-static     make clean    if [ "$1" == "verbose" ]; then        make V=1    else        make    fi    make install}builddef $1复制[size=0.825em]错误[size=0.825em]复制成功
  • 运行 build_x264.sh 文件,生成静态库:
  • 上面步骤成功后,在 x264lib 文件夹下,会生成 x264 的静态库文件和头文件:
    静态库文件:
    头文件:

[color=var(--theme-color, #42b983)]FFmpeg[color=var(--theme-color, #42b983)]简介
FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用 LGP L或 GPL 许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库 libavcodec,为了保证高可移植性和编解码质量,libavcodec 里很多 code 都是从头开发的。
FFmpeg 在 Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括 Windows、Mac OS X 等。这个项目最早由 Fabrice Bellard 发起,2004 年至 2015 年间由 Michael Niedermayer 主要负责维护。下面介绍如何将 FFmpeg 移植到 ART-Pi Smart 平台上,实现视频的解码功能。
[color=var(--theme-color, #42b983)]下载
打开 FFmpeg 官网,下载源码:
[color=var(--theme-color, #42b983)]交叉编译
  • 解压 tar.bz2 文件:
    tar -jxvf ffmpeg-snapshot.tar.bz2复制[size=0.825em]错误[size=0.825em]复制成功
  • 在 ffmpeg 文件夹同级目录下创建 build_ffmpeg.sh 文件
    # Get initial variablesROOTDIR="/home/liukang/repo/ART-Pi-smart/userapps"APP_NAME="ffmpeg"APP_DIR=${APP_NAME}LIB_DIR=${ROOTDIR}/sdk/libINC_DIR=${ROOTDIR}/sdk/includeRT_DIR=${ROOTDIR}/sdk/rt-threadRT_INC=" -I. -Iinclude -I${ROOTDIR} -I${RT_DIR}/include -I${RT_DIR}/components/dfs -I${RT_DIR}/components/drivers -I${RT_DIR}/components/finsh -I${RT_DIR}/components/net -I${INC_DIR}/sdl -DHAVE_CCONFIG_H"RT_INC+=" -I${ROOTDIR}/../kernel/bsp/imx6ull-artpi-smart/drivers/"export CPPFLAGS=${RT_INC}export LDFLAGS="-L${LIB_DIR} "export LIBS="-T ${ROOTDIR}/linker_scripts/arm/cortex-a/link.lds -march=armv7-a -marm -msoft-float -L${RT_DIR}/lib -Wl,--whole-archive -lrtthread -Wl,--no-whole-archive -n -static -Wl,--start-group -lc -lgcc -lrtthread -Wl,--end-group"export RTT_EXEC_PATH=/home/liukang/repo/ART-Pi-smart/tools/gnu_gcc/arm-linux-musleabi_for_x86_64-pc-linux-gnu/binexport PATH=$PATHRTT_EXEC_PATHRTT_EXEC_PATH/../arm-linux-musleabi/binexport CROSS_COMPILE="arm-linux-musleabi"if [ "$1" == "debug" ]; then    export CFLAGS="-march=armv7-a -marm -msoft-float -D__RTTHREAD__ -O0 -g -gdwarf-2 -Wall -n --static"else    export CFLAGS="-march=armv7-a -marm -msoft-float -D__RTTHREAD__ -O2 -Wall -n --static"fi# default buildfunction builddef() {    cd ${APP_DIR}    ./configure \    --cross-prefix=${CROSS_COMPILE} --enable-cross-compile --target-os=linux \    --cc=${CROSS_COMPILE}-gcc \    --ar=${CROSS_COMPILE}-ar \    --ranlib=${CROSS_COMPILE}-ranlib \    --arch=arm --prefix=/home/liukang/repo/ffmpeg/ffmpeg_lib \    --pkg-config-flags="--static" \    --enable-gpl --enable-nonfree --disable-ffplay --enable-swscale --enable-pthreads --disable-armv5te --disable-armv6 --disable-armv6t2 --disable-x86asm  --disable-stripping \    --enable-libx264 --extra-cflags=-I/home/liukang/repo/x264lib/include --extra-ldflags=-L/home/liukang/repo/x264lib/lib --extra-libs=-ldl    make clean    if [ "$1" == "verbose" ]; then        make V=1    else        make    fi    make install}builddef $1复制[size=0.825em]错误[size=0.825em]复制成功
  • 运行 build_ffmpeg.sh 文件
  • 上面步骤成功后,在 ffmpeg_lib 文件夹下,会生成 ffmpeg 的静态库文件和头文件:
    Lib 库:
    头文件:

[color=var(--theme-color, #42b983)]视频播放 Demo
  • 使用 VS Code 生成 makefile 工程
  • 将上面生成的静态库文件放在 Smart SDK 目录下
  • 修改 makefile 文件,添加静态库
    #程序版本号VERSION = 1.0.0     CROSS_COMPILE = arm-linux-musleabi-CC = $(CROSS_COMPILE)gccCXX = $(CROSS_COMPILE)g++复制[size=0.825em]错误[size=0.825em]复制成功
[color=var(--theme-color, #42b983)]project 根路径
PROJECT_DIR := $(shell pwd)
[color=var(--theme-color, #42b983)]userapps 根路径
UROOT_DIR = $(PROJECT_DIR)/../..
[color=var(--theme-color, #42b983)]rt-thread 路径
RT_DIR = $(UROOT_DIR)/sdk/rt-thread INC_DIR =$(UROOT_DIR)/sdk/rt-thread/include LIB_DIR = ${UROOT_DIR}/sdk/rt-thread/lib
[color=var(--theme-color, #42b983)]sdl 路径
SDL_DIR = ${UROOT_DIR}/sdk/include/sdl
[color=var(--theme-color, #42b983)]ffmpeg
FFMPEG_DIR = ${UROOT_DIR}/sdk/include/ffmpeg
#x264 X264_DIR = ${UROOT_DIR}/sdk/include/x264
[color=var(--theme-color, #42b983)]配置编译参数
CFLAGS = -march=armv7-a -marm -msoft-float -D__RTTHREAD__ -Wall -O0 -g -gdwarf-2 -n --static
[color=var(--theme-color, #42b983)]加入头文件搜索路径
CFLAGS += -I. -I$(UROOT_DIR) -I$(PROJECT_DIR) -I$(RT_DIR)/components/dfs -I$(RT_DIR)/components/drivers -I$(RT_DIR)/components/finsh -I$(RT_DIR)/components/net
-I$(RT_DIR)/components/net/netdev -I$(RT_DIR)/components/net/arpa -I${INC_DIR} -I${INC_DIR}/libc -I${INC_DIR}/sys -I${SDL_DIR} -I${FFMPEG_DIR}
-I${FFMPEG_DIR}/libavcodec -I${FFMPEG_DIR}/libavdevice -I${FFMPEG_DIR}/libavfilter -I${FFMPEG_DIR}/libavformat
-I${FFMPEG_DIR}/libavutil -I${FFMPEG_DIR}/libpostproc -I${FFMPEG_DIR}/libswresample -I${FFMPEG_DIR}/libswscale -I${X264_DIR}
[color=var(--theme-color, #42b983)]加入链接文件
LDFLAGS = -march=armv7-a -marm -msoft-float -T ${UROOT_DIR}/linker_scripts/arm/cortex-a/link.lds
[color=var(--theme-color, #42b983)]加入库文件
LDFLAGS += -L$(LIB_DIR) -Wl,--whole-archive -Os -lrtthread -lSDL2 -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc -lswresample -lswscale -lx264 -Wl,--no-whole-archive -n --static -Wl,--start-group -lc -lgcc -lrtthread -lSDL2 -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc -lswresample -lswscale -lx264 -Wl,--end-group
default: $(CC) $(CFLAGS) -c main.c -o main.o $(CC) $(LDFLAGS) main.o -o hello.elf
clean: @rm *.o *.elf
.PHONY: default clean
4. 编译![Snipaste_2022-01-17_10-10-13.png](figures/10.png)5. 通过 SD Card 启动 elf 文件,将生成的 hello.elf 文件和视频文件放到 SD 卡中,插入到 ART-Pi Smart: ![Snipaste_2022-01-17_10-15-04.png](figures/11.png)
完整代码
  1. #include <stdio.h>
  2. #include <SDL.h>
  3. #include <libavcodec/avcodec.h>
  4. #include <libavformat/avformat.h>
  5. #include <libswscale/swscale.h>

  6. extern Uint32 rtt_screen_width;
  7. extern Uint32 rtt_screen_heigth;

  8. int main (int argc, char *argv[])
  9. {
  10. int ret = -1;
  11. AVFormatContext *pFormatCtx = NULL;
  12. int videoStream;
  13. AVCodecParameters *pCodecParameters = NULL;
  14. AVCodecContext *pCodecCtx = NULL;
  15. AVCodec *pCodec = NULL;
  16. AVFrame *pFrame = NULL;
  17. AVPacket packet;

  18. SDL_Rect rect;
  19. SDL_Window *win = NULL;
  20. SDL_Renderer *renderer = NULL;
  21. SDL_Texture *texture = NULL;

  22. if(( argc != 2 ))
  23. {
  24.      printf("error input arguments!\n");
  25.      return(1);
  26. }

  27. // 默认窗口大小
  28. int w_width  = rtt_screen_width;
  29. int w_height = rtt_screen_heigth;

  30. // use dummy video driver
  31. SDL_setenv("SDL_VIDEODRIVER","rtt",1);
  32. //Initialize SDL
  33. if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
  34. {
  35.      printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
  36.      return -1;
  37. }

  38. // 打开输入文件
  39. if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
  40. {
  41.      printf("Couldn't open video file!: %s\n", argv[1]);
  42.      goto __exit;
  43. }

  44. // 找到视频流
  45. videoStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
  46. if (videoStream == -1)
  47. {
  48.      printf("Din't find a video stream!\n");
  49.      goto __exit;// Didn't find a video stream
  50. }

  51. // 流参数
  52. pCodecParameters = pFormatCtx->streams[videoStream]->codecpar;

  53. // 获取解码器
  54. pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
  55. if (pCodec == NULL)
  56. {
  57.      printf("Unsupported codec!\n");
  58.      goto __exit; // Codec not found
  59. }

  60. // 初始化一个编解码上下文
  61. pCodecCtx = avcodec_alloc_context3(pCodec);
  62. if (avcodec_parameters_to_context(pCodecCtx, pCodecParameters) != 0)
  63. {
  64.      printf("Couldn't copy codec context\n");
  65.      goto __exit;// Error copying codec context
  66. }

  67. // 打开解码器
  68. if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
  69. {
  70.      printf("Failed to open decoder!\n");
  71.      goto __exit; // Could not open codec
  72. }

  73. // Allocate video frame
  74. pFrame = av_frame_alloc();

  75. w_width = pCodecCtx->width;
  76. w_height = pCodecCtx->height;

  77. // 创建窗口
  78. win = SDL_CreateWindow("Media Player",
  79.                         SDL_WINDOWPOS_UNDEFINED,
  80.                         SDL_WINDOWPOS_UNDEFINED,
  81.                         w_width, w_height,
  82.                         SDL_WINDOW_SHOWN );
  83. if (!win)
  84. {
  85.      printf("Failed to create window by SDL\n");
  86.      goto __exit;
  87. }

  88. // 创建渲染器
  89. renderer = SDL_CreateRenderer(win, -1, 0);
  90. if (!renderer)
  91. {
  92.      printf("Failed to create Renderer by SDL\n");
  93.      goto __exit;
  94. }

  95. // 创建纹理
  96. texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV,
  97.                              SDL_TEXTUREACCESS_STREAMING,
  98.                              w_width,
  99.                              w_height);


  100. // 读取数据
  101. while (av_read_frame(pFormatCtx, &packet) >= 0)
  102. {
  103.      if (packet.stream_index == videoStream)
  104.      {
  105.          // 解码
  106.          avcodec_send_packet(pCodecCtx, &packet);
  107.          while (avcodec_receive_frame(pCodecCtx, pFrame) == 0)
  108.          {
  109.              SDL_UpdateYUVTexture(texture, NULL,
  110.                                   pFrame->data[0], pFrame->linesize[0],
  111.                                   pFrame->data[1], pFrame->linesize[1],
  112.                                   pFrame->data[2], pFrame->linesize[2]);

  113.              // set size of Window
  114.              rect.x = 0;
  115.              rect.y = 0;
  116.              rect.w = pCodecCtx->width;
  117.              rect.h = pCodecCtx->height;

  118.              SDL_RenderClear(renderer);
  119.              SDL_RenderCopy(renderer, texture, NULL, &rect);
  120.              SDL_RenderPresent(renderer);
  121.          }
  122.      }

  123.      av_packet_unref(&packet);
  124. }

  125. __exit:

  126. if (pFrame)
  127. {
  128.      av_frame_free(&pFrame);
  129. }

  130. if (pCodecCtx)
  131. {
  132.      avcodec_close(pCodecCtx);
  133. }

  134. if (pCodecParameters)
  135. {
  136.      avcodec_parameters_free(&pCodecParameters);
  137. }

  138. if (pFormatCtx)
  139. {
  140.      avformat_close_input(&pFormatCtx);
  141. }

  142. if (win)
  143. {
  144.      SDL_DestroyWindow(win);
  145. }

  146. if (renderer)
  147. {
  148.      SDL_DestroyRenderer(renderer);
  149. }

  150. if (texture)
  151. {
  152.      SDL_DestroyTexture(texture);
  153. }

  154. SDL_Quit();

  155. return ret;
  156. }
复制代码

实机演示
该仓库放置了编译好的 FFmpeg 和 X264 库文件:https://github.com/liukangcc/ART-Pi-Smart
git直接获取
  1. git clone https://github.com/liukangcc/ART-Pi-Smart.git
复制代码



+10
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-5-18 05:12 , Processed in 0.081728 second(s), 37 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表