你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Qt+SDL+ffmpeg视频播放演示

[复制链接]
gaosmile 发布时间:2021-2-1 13:03
一、前言

在前几篇文章当中,有提到过用源码去搭建ffmpeg的命令环境开发,为啥要这样去搭建环境,为什么不用直接用下面这个命令在ubuntu下安装多快,简单又方便:

sudo apt install ffmpeg
. z1 w: ^6 b9 K: ~3 {

今天分享ffmepg第五弹:ffmpeg+qt+SDL的真正开发环境,就要用源码安装的方式去在qt里面调用ffmpeg相关的库;还记得之前源码搭建创建的三个文件夹不:

bin   ffmpeg_sources    ffmpeg_build& o8 ^9 k& Q9 T5 C

bin文件夹下是编译得到的二进制文件

txp@txp-virtual-machine:~/bin$ ls
( N5 Z2 |8 O. o8 pffmpeg  ffplay  ffprobe  lame  nasm  6 l4 ^; i$ S- B% {$ q
ndisasm  x264
  `# s& T4 f3 x" b- W) O$ Y5 C) A& s* K/ o  V  C& r

ffmpeg_sources文件下是下载的各种库的源码:

txp@txp-virtual-machine:~/ffmpeg_sources$ ls
5 ~' X; ]- T! U  V& F, [5 E  ^! Gfdk-aac                  lame-3.100.tar.gz     SDL2-2.0.14.tar.gz* E/ |9 O* ]: O
ffmpeg                   libvpx                SVT-AV1
+ c& q. A3 {/ @2 f9 x) Y" sffmpeg-4.2.1             nasm-2.14.02          x264
) w- z7 l9 r% a  _2 zffmpeg-4.2.1.tar.bz2     nasm-2.14.02.tar.bz2  x265_git
- W0 `( N! Z) \: {ffmpeg-snapshot.tar.bz2  opus
8 [) a5 M) \" X0 Olame-3.100               SDL2-2.0.142 ?0 n9 [* g% q9 ~% i
2 }8 \% U& K/ l5 n0 q

ffmpeg_build文件夹主要是ffmpeg的一些库文件,等下下面演示的模板就要调用ffmpeg相关的库:

txp@txp-virtual-machine:~/ffmpeg_build/lib$ ls7 s0 S% y) A5 T% r* e3 M
cmake          libmp3lame.a           libSDL2.la       libswscale.a2 z$ @/ v* y9 R5 B4 v9 f
libavcodec.a   libmp3lame.la          libSDL2main.a    libvpx.a
! l1 v+ Y% U1 ?' Z' a9 F) ilibavdevice.a  libopus.a              libSDL2main.la   libx264.a3 E1 n& }. a9 y/ T) R5 z
libavfilter.a  libopus.la             libSDL2.so       libx265.a
0 _  s, v7 V" n: I! ilibavformat.a  libpostproc.a          libSDL2_test.a   pkgconfig3 U- D0 P  l; w9 O
libavutil.a    libSDL2-2.0.so.0       libSDL2_test.la
* ~' E& [' Q. g3 V/ llibfdk-aac.a   libSDL2-2.0.so.0.14.0  libSvtAv1Enc.a
2 ^/ s; O9 a5 ilibfdk-aac.la  libSDL2.a              libswresample.a) ?  l) z! D2 M; g' @1 S

$ g! k5 |7 x8 i. I- U. O

因为我已经搭建好了开发环境,从现在来看的话,如果你直接用命令去安装ffmpeg的话,到时候我们在qt的环境中去调用ffmpeg的库,至少到目前为止我暂时不知道去如何配置相关路径来调用ffmpeg的库;所以我们明白了这点,那么就撸起袖子肝就是。

二、 qt环境搭建

玩过qt的朋友,对于这块应该比我熟悉多了;不过有可能有一些朋友可能没有接触过qt的话,为此我还是简单演示一下qt的安装步骤:

  • 首先我们要去qt的官网下载linux版本的源码安装包:, R4 i8 W' R- k$ F# J% {+ @
版本下载地址:
( ?7 t& t2 Z9 Y0 Hhttps://download.qt.io/archive/qt/5.12/5.12.10/: v' G+ V4 g+ N' q3 r# k$ S
微信图片_20210201125402.png
  • 开始安装qt:) z% e, F9 r6 N  b

这里我直接把qt的源码包下载到samba服务共享文件下,当然你也可以直接在ubuntu下载:

微信图片_20210201125406.png

然后我在share目录创建一个qt文件夹,用存放qt安装的地方,然后直接运行这个源码文件:

微信图片_20210201125409.png

接着就会出现qt的安装界面:

微信图片_20210201125412.png
微信图片_20210201125415.png
微信图片_20210201125419.png

最终qt就安装完成了,但是如果你运行qt执行失败的话(注意qtcreator的所放在的路线):

txp@txp-virtual-machine:~/share/qt/Qt5.12.10/Tools/QtCreator/bin$ sudo ./qtcreator
8 ]2 b" u& T6 z- B
1 v/ ]0 C" s, `7 V& ~5 c) U' o
Got keys from plugin meta data ("xcb")
" w$ x3 c$ f2 y- l( B# x/ iQFactoryLoader:FactoryLoader() checking directory path "/home/txp/share/qt/Qt5.12.10/Tools/QtCreator/bin/platforms" ...
( `$ l! X8 {0 C& Y" h/ j  u5 hloaded library "/home/txp/share/qt/Qt5.12.10/Tools/QtCreator/lib/Qt/plugins/platforms/libqxcb.so") L6 i/ f  b* D  x( ?3 d
loaded library "Xcursor"
6 x4 S+ v. p7 s! G" |$ jSegmentation fault (core dumped)9 X+ h% c; i1 k4 l% x# g' Q

8 R5 [  I& J6 {: J
  • 解决qt运行失败的方法:1 K& \' T0 [4 n6 e

在这个脚本里面添加一句话:

微信图片_20210201125422.png

然后接着再安装相关插件:

sudo apt install --reinstall libxcb-xinerama09 [! \1 l' P$ i1 Z1 ^% H6 V

然后我们执行一下,就可以成功打开qt了:

微信图片_20210201125425.png

还有一种方法直接打开qt,因为按照上面的这种方式打开的话,每次都要跑到这个目录去执行这条语句才行:

txp@txp-virtual-machine:~/share/qt/Qt5.12.10/Tools/QtCreator/bin$
* Y6 [4 {, l3 q$ bsudo ./qtcreator/ G8 `5 `8 n0 Z" b) d! @
5 R5 V. m" ~3 m7 x' y

现在我们只要执行下面这条语句就不用这么麻烦了:

sudo chown -R txp:txp ~/.config/
/ x% {2 n/ Q9 }1 G6 X* t2 d% t6 h! F- ~

然后你就可以像在windows环境下去直接打开这个软件就行:

微信图片_20210201125428.png
三、牛刀小试,调用ffmpeg库3.1 示例模板,显示打印ffmpeg的版本:

现在我们打开刚才安装好的qt软件,来创建一个工程:

微信图片_20210201125432.png
微信图片_20210201125435.png
微信图片_20210201125438.png

最终一个工程项目就建立好了:8 y/ }: }# C$ P8 ?

微信图片_20210201125441.png

我们可以看到两个文件,一个是以.pro结尾的qt工程管理配置文件,一个主源码文件,现在我们就简单使用ffmpeg库来打印ffmpeg的版本号:

  • 配置pro文件:pro文件里面默认是:
      ]* Y7 |: y. d. Y5 }
TEMPLATE = app
% d' ^  U! A4 K# |" ^# lCONFIG += console) K6 Q7 v' o: G
CONFIG -= app_bundle4 {( ~0 _  T  E- B- Y! r
CONFIG -= qt0 Q. \0 P$ L+ D

' w' O# ^6 v1 h; X( c. T# kSOURCES += \
, T0 @* y. M$ U* R1 b        main.c
8 ?6 P  X( u3 [! r
1 x' Q$ }9 v$ y( F% C4 C( l+ ]

现在我们要加入ffmpeg_build目录下的ffmpeg库文件:

TEMPLATE = app
. S; E3 Z  _5 x: a9 g( c2 xCONFIG += console3 h$ T0 @" e+ t& B& D
CONFIG -= app_bundle* \( H9 S) u0 p5 |/ _# l
CONFIG -= qt; L" Z* f0 P, F5 k) J1 S

8 M9 M, Z2 J- O) C, j" l0 uSOURCES += \
- N* A! B9 A9 `( s( l: Y  |        main.c
$ S( x5 p0 W1 }3 W4 i4 ^! n, S+ HINCLUDEPATH += /home/txp/ffmpeg_build/include
9 Z, H' |0 k( j8 e( f2 M: G: ~1 y#LIBS += /home/txp/ffmpeg_build/lib/libSDL2.so: [( I' Q# {1 Q+ c4 O* H
0 b- L  a) F  C5 O; ~7 q
LIBS += /home/txp/ffmpeg_build/lib/libavcodec.a \5 }. R, b- Z! M% O( y) L' y( i
        /home/txp/ffmpeg_build/lib/libavdevice.a \# y0 X# k+ {# Z" y: B& _: z; Z
        /home/txp/ffmpeg_build/lib/libavfilter.a \
  ]( D  A* e4 ]/ n1 n: [: M- a        /home/txp/ffmpeg_build/lib/libavformat.a \
' o( D7 [0 o! G$ c) V9 U        /home/txp/ffmpeg_build/lib/libavutil.a \2 h) [9 G. A0 g9 V& t* K( k7 g* e
        /home/txp/ffmpeg_build/lib/libswresample.a \
7 s. W9 c! q% \( Y3 `        /home/txp/ffmpeg_build/lib/libswscale.a1 c' N. J+ F# E9 D
3 j) V" |+ g2 y, }) G
  T; I. ]! H5 }& u% W. R
  • main.c源码文件就可以修改成这样:
    7 x) Z& K9 A* o
#include <stdio.h>
: \- i: B$ v& H# S& e% r- F//包含ffmpeg头⽂件
8 l8 y/ A& x, a9 i3 `#include "libavutil/avutil.h"
  H* R0 M. H0 ?. Jint main()
% ^2 T6 V- q: H* E{, X6 \7 s3 g" Z8 z& l5 v- j* W
    printf("Hello FFMPEG, version is %s\n", av_version_info());: P+ I! _5 H, Q" n& G: n( V
    return 0;
8 a" J1 d: E* [& \}
) o9 I/ `9 H- O! n/ L6 J( F  w3 i; d( }6 l( _  @, @- J& h! \: b  R

最终结果,显示ffmpeg的版本为 4.2.1:

20:01:19: Starting /home/txp/share/qt/workspace/build-linux_1-ffmpeg-Desktop_Qt_5_12_10_GCC_64bit-Debug/linux_1-ffmpeg ...$ _- C3 [8 G# M+ e9 ^5 K) l8 n
Hello FFMPEG, version is 4.2.1) V& k. ^4 L: A: Q* Q/ P
20:01:19: /home/txp/share/qt/workspace/build-linux_1-ffmpeg-Desktop_Qt_5_12_10_GCC_64bit-Debug/linux_1-ffmpeg exited with code 0
* @& k) C, E, u! _$ R9 y: z5 A, I) R7 ?( [

注意:我们的ubuntu运行环境一定要是64位的,不然安装不了这个版本的qt;还有一点,其实我们在.pro文件里面,按键盘上的ctrl键然后把鼠标放到库文件路径上,是可以打开里面的:

微信图片_20210201125445.png
3.2、搭建SDL,然后播放yuv格式的视频文件:

关于什么是SDL,这里我就不造轮子了,可以参考雷神的文章介绍:

https://blog.csdn.net/leixiaohua1020/article/details/11954039& |5 D6 A  d! v3 [8 m9 s; n
微信图片_20210201125450.png

下面我们去SDL的官网下源码包就行安装:

https://www.libsdl.org/download-2.0.php
5 A- I7 C5 g  I* U2 O1 T
微信图片_20210201125454.png
  • 开始安装,先把这个源码包放到ffmpeg_sources目录下去,然后进行解压:
    ' q$ a* u0 ]  S% B* ~
txp@txp-virtual-machine:~/ffmpeg_sources$ tar zxf SDL2-2.0.14.tar.gz 8 }; V+ [: p! b, K! Y6 l9 q" z3 }
txp@txp-virtual-machine:~/ffmpeg_sources$ ls( `: f, n2 `& l, o+ A, U# V+ d
fdk-aac                  lame-3.100.tar.gz     SDL2-2.0.14.tar.gz8 P5 S7 x9 y8 m$ k, b
ffmpeg                   libvpx                SVT-AV1
3 x! x  b5 ], d& ?0 f0 M/ cffmpeg-4.2.1             nasm-2.14.02          x264& C0 |5 g! ]+ ]; \3 `
ffmpeg-4.2.1.tar.bz2     nasm-2.14.02.tar.bz2  x265_git
/ K& ]7 t$ b  }+ u8 fffmpeg-snapshot.tar.bz2  opus
2 m  n+ [  O0 U, o' C1 i! B) mlame-3.100               SDL2-2.0.14
- N& R. e, \! w1 x
1 _& {) O( a# Z  g0 F( d/ y

然后执行:

txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$ ./autogen.sh . J! x) F0 ~/ T0 b! v. l
Generating build information using autoconf4 `4 ~( F+ I/ n" g
This may take a while ...- a0 s. L$ s- V' P& e
Now you are ready to run ./configure, a2 O( m3 h& b: W% |: R) T9 A" I
2 \4 U+ S' k/ h' A& P( A

这里提示了你直接运行 ./configure:

./configure --prefix=/home/txp/ffmpeg_build --bindir=/home/txp/bin
. e5 l3 E) f! B5 z6 M0 N, I- L+ Z6 h/ Y5 z* }" b& H( g
  • 然后进行编译:make -j4
    $ a1 I! L3 W! p" G7 o) d
txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$
! s1 C- S, Q. `7 L! xmake -j43 m, V3 f1 S1 x0 \) S3 s+ `4 n
: O% f7 A) s6 Y% b. Z
  • 最后再执行sudo make install就行,SDL就安装成功了:: G  P" a! a8 J! y! Y$ W
txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$ 7 Q2 i0 k3 `8 U
sudo make install
4 s, X: x7 E, t: }4 k: Z
* |( y$ [* a( A

下面我再创建一个工程,具体过程我就再写了,和第一个工程创建是一样的:这里我的main.c文件里面的源代码,大家先不用管代码具体啥意思:

#include <stdio.h>
, c& f7 @. ]. T7 }4 J" e#include <string.h>
$ S, N! [* H3 p/ r#include "SDL2/SDL.h"//包含SDL动态库文件
6 X; r/ o8 `; f, D$ f. h
, M( c+ [; Q' q! o8 X# w* b//自定义消息类型$ ]: E6 b+ W1 M
#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件
" }6 w/ f- K9 j, E7 ]$ d8 z  i8 W#define QUIT_EVENT      (SDL_USEREVENT + 2)     // 退出事件
. n* z0 b$ k5 [9 Q8 L
% g; X1 W& ?" o, P5 c% u/ k, v//定义分辨率
- T8 N9 R7 i5 W// YUV像素分辨率
6 l' w" n2 J/ j0 ~$ H& G#define YUV_WIDTH   320
3 x! W7 \+ E5 S+ q8 V7 \' F#define YUV_HEIGHT  2402 L, c) ~( e! y/ J6 h9 P# ~6 P: M
//定义YUV格式  \- B7 ~  c; M% N! ]9 @) @6 Y
#define YUV_FORMAT  SDL_PIXELFORMAT_IYUV3 u1 J; T) I1 D# o* l* U% E. z2 W
6 C  {, p1 G# v, `; V0 u
int s_thread_exit = 0;  // 退出标志 = 1则退出) v' \$ t) t6 h" t+ C

2 b: p. w: B7 @- Sint refresh_video_timer(void *data)
0 @, U4 K+ P! K+ ]6 o% l" W/ u{
. E# B1 Y0 D( D+ t3 ~    while (!s_thread_exit)4 S" z+ o  p, t5 [6 d4 J# n
    {
4 h. [. ^8 W6 n2 |7 T! j* `8 ~8 G0 Y        SDL_Event event;
$ L# W/ l: B$ s, A- h/ Y        event.type = REFRESH_EVENT;
4 A+ [+ ]+ o0 S: R: e8 K        SDL_PushEvent(&event);" B4 p& O4 j: `( F' L
        SDL_Delay(40);2 R& m/ }# r, U4 _5 O3 K/ S7 n
    }0 L1 W) H  g* p# |. a

4 f6 p% s" |* [9 s1 |( s/ Z- n    s_thread_exit = 0;
# I. h" ]4 l# H, b* w. [4 c& \) {4 t& D2 k; X1 b9 J4 Q. O  h
    //push quit event
4 }+ C9 [$ L8 f# d# n' I; U+ n5 `3 E% B    SDL_Event event;
6 Z4 E+ l7 w% v" h, V    event.type = QUIT_EVENT;3 u; b( [2 |0 i' K
    SDL_PushEvent(&event);
( u0 G' B, ^4 \( L! O* `
( D6 Z" T$ a7 |% j1 b    return 0;/ S# H) i/ w  G+ b/ _
}
. X2 l) |  c7 K  l3 G& O) F/ Z7 U#undef main
1 K1 T- @# I5 zint main(int argc, char* argv[])
( I1 k4 B) |4 k% F+ V) b  c{5 I) d0 V& k+ B
    //初始化 SDL
% @  v5 A% h) d    if(SDL_Init(SDL_INIT_VIDEO))) b0 N, U( L! c, r7 i6 P& ?$ o
    {
3 L# J4 [" g- M6 r; l5 `        fprintf( stderr, "Could not initialize SDL - %s\n", SDL_GetError());
. ]$ w$ e& {7 T4 y        return -1;
. W* {; ^' {9 F7 p: z# D    }
) H  ~" a) Y% E( m0 E9 e8 K/ P5 G+ l. D1 c
    // SDL
7 b5 Q  |! ^6 S& E0 c7 r    SDL_Event event;                            // 事件
/ R& Y3 F4 _9 G3 C$ w  U1 w8 L0 [    SDL_Rect rect;                              // 矩形
3 K4 D" l6 p! t2 m' i    SDL_Window *window = NULL;                  // 窗口
; j6 h. A% I- f' ^: l    SDL_Renderer *renderer = NULL;              // 渲染; m5 V+ l$ d( k- q) e  q, e
    SDL_Texture *texture = NULL;                // 纹理' X; J! W4 y% k8 \1 p5 w
    SDL_Thread *timer_thread = NULL;            // 请求刷新线程
' s1 B8 ?7 ?3 Z/ T% x4 C$ l    uint32_t pixformat = YUV_FORMAT;            // YUV420P,即是SDL_PIXELFORMAT_IYUV
/ X# B1 R/ u' s' ]% ?) b( O9 E, |; \9 E; z
    // 分辨率
! j' u7 P! [8 n4 A6 m" Y    // 1. YUV的分辨率) A) j# A# u2 X
    int video_width = YUV_WIDTH;
/ a- Q7 ]; {* _" ^3 T    int video_height = YUV_HEIGHT;
: f# W* h, \4 {, }: Z7 C; p2 }    // 2.显示窗口的分辨率
( t# e% g+ Z; g) w& [/ d3 @9 W) y0 n    int win_width = YUV_WIDTH;
- t: s0 d; \) U, N  J4 O% X    int win_height = YUV_WIDTH;1 h0 X/ ~4 ]4 z

; f6 M2 r  K5 C) g6 `. V: H1 @    // YUV文件句柄# v' @; `0 L1 k' }4 U& O  F
    FILE *video_fd = NULL;  k9 o) p# M' h8 g/ Z! N
    const char *yuv_path = "yuv420p_320x240.yuv";9 N6 i+ y' ?1 z* |" F
( B1 }  S+ f. K" _: Q5 S) C& ?
    size_t video_buff_len = 0;' m' _  L" }2 z; y* Q
* ~) M( ^# B# ^  v# e
    uint8_t *video_buf = NULL; //读取数据后先把放到buffer里面. a5 p: b# t/ U. H: H4 w4 r; @

5 m0 D4 |7 E/ ]( G  z    // 我们测试的文件是YUV420P格式5 V" B5 ~# G6 H& b
    uint32_t y_frame_len = video_width * video_height;  L( R8 b2 D3 T2 m( z* n! n
    uint32_t u_frame_len = video_width * video_height / 4;
, Y% d, [& m% R: J. [    uint32_t v_frame_len = video_width * video_height / 4;
/ U& ]( P6 v. U* T    uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;
6 r/ l$ M: L! K0 ?  f& f! C7 c+ i+ j+ d
    //创建窗口
6 q& j4 l1 [' J    window = SDL_CreateWindow("Simplest YUV Player",+ y/ o1 @) R( g* k) r: y" @
                           SDL_WINDOWPOS_UNDEFINED,) n% f" W* M8 [5 @1 s" Q/ b
                           SDL_WINDOWPOS_UNDEFINED,0 b0 s  X8 W% W( m
                           video_width, video_height,
1 ~, n( |: }9 n                           SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);; H5 t7 G) Z0 ^5 Y9 u
    if(!window): Y$ e' G& M% ^+ F" N/ L8 x
    {" k1 S8 r2 O: p9 ^- Y
        fprintf(stderr, "SDL: could not create window, err:%s\n",SDL_GetError());
! O3 G. }9 F' C- R        goto _FAIL;) w3 o) {  T/ \( U
    }$ @) f# r5 e  U$ S0 s
    // 基于窗口创建渲染器
7 C7 F/ ]5 c3 ~; w    renderer = SDL_CreateRenderer(window, -1, 0);
/ K0 R4 e' V; g4 x( |0 y( z4 _1 g/ V    // 基于渲染器创建纹理
8 i6 M" f1 g6 W5 n8 {$ q+ t8 ]: z    texture = SDL_CreateTexture(renderer,0 t2 ~7 u& X- ?: Z
                                pixformat,
  _5 @, {/ v" [8 J$ d5 e  O                                SDL_TEXTUREACCESS_STREAMING,
  @6 \) y6 w& g( k3 v                                video_width,5 h& P+ u* G- W# }" B- E
                                video_height);
0 g7 q% u8 a7 P  O6 U. g8 t: b5 |7 Q, c5 _8 U
    // 分配空间
' ~: P8 ^! x1 N; i* ?* I4 Q    video_buf = (uint8_t*)malloc(yuv_frame_len);6 L' V" x+ ^- Q% Q* H
    if(!video_buf)
7 E7 h- g& ^9 z$ l$ h( k    {
/ }3 X' j  U+ B' C- |        fprintf(stderr, "Failed to alloce yuv frame space!\n");& G7 D; Y  a1 }+ d: k" ]
        goto _FAIL;
, u1 p% X) n, L! M/ i    }1 P4 q1 `- c, }) e/ f- N3 X" u

% b3 |# A0 C6 ?0 b6 ]9 B    // 打开YUV文件. o, b3 |' J. Y! S/ W
    video_fd = fopen(yuv_path, "rb");
9 A6 x$ Z% m6 D! b    if( !video_fd )
- q' o; Z, l3 x. v) a9 ^    {
: g2 z6 h: J& @! e8 ^% i        fprintf(stderr, "Failed to open yuv file\n");7 e0 {: t2 @* a( `8 x
        goto _FAIL;4 ~+ _- m! d  O; x9 d( B
    }6 v; c# p: _5 F% B; F2 h
    // 创建请求刷新线程  s) _1 W2 v; |
    timer_thread = SDL_CreateThread(refresh_video_timer,- p6 i- y* U' k2 y/ q: R7 ~
                                    NULL,) g5 h: s2 K4 K. O$ y: u, i, S
                                    NULL);% z( U+ M: t' c, k: v

3 u2 L4 s7 s2 x9 Z. Q$ i" h    while (1)
$ L+ F) i/ L7 b3 i2 M" U: b    {9 \0 J0 M; V9 Y  t: S4 c
        // 收取SDL系统里面的事件
6 K$ i, l. F8 u- ~3 q$ l% x1 I& A        SDL_WaitEvent(&event);
4 F  t' H6 O/ F+ R2 j* V; G, I4 K. i2 j/ Y
        if(event.type == REFRESH_EVENT) // 画面刷新事件
" M& e) w2 H/ ?" R* c        {
2 |# }2 J1 V0 y: Z2 l            video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd);
4 L5 U# z& C1 R) k$ I- H4 p            if(video_buff_len <= 0)- V$ T. x' p* s9 U: H
            {
5 Q) o0 C7 P, f  B6 k' `  k4 B                fprintf(stderr, "Failed to read data from yuv file!\n");
) x+ p" x$ _' Q1 \# K                goto _FAIL;
$ _8 R9 m) V5 ^8 j7 S2 h            }
2 y2 z# {2 a8 \4 t$ r; r4 F- b# _            // 设置纹理的数据 video_width = 320, plane" f: t( N1 X7 ?" G
            SDL_UpdateTexture(texture, NULL, video_buf, video_width);
) `, D0 t' v! n% J% ]. X. E4 f3 I
. p9 m) X, p; a% z8 N            // 显示区域,可以通过修改w和h进行缩放
6 G  M( p0 R! ~            rect.x = 0;6 I. ~1 H! x- k- @9 C
            rect.y = 0;
/ y8 @  p3 o, V            float w_ratio = win_width * 1.0 /video_width;0 V( O% ~. _& c  n! U
            float h_ratio = win_height * 1.0 /video_height;
6 u, C6 R/ _* I. |            // 320x240 怎么保持原视频的宽高比例
0 B! p  R5 K- Z  s            rect.w = video_width * w_ratio;
4 {" V1 w3 R, N            rect.h = video_height * h_ratio;4 |" L8 {" W- d
//            rect.w = video_width * 0.5;. E" ^# ~+ r3 N4 l. |) ^9 |
//            rect.h = video_height * 0.5;0 U& P) ], s- q% ~" G1 d8 X+ \' H

! a) \; k, X5 u3 [0 e4 c" }$ F            // 清除当前显示
% J0 o1 c, X- q# q, P7 M1 b# t# k7 ?            SDL_RenderClear(renderer);! P  g9 u% _4 J" ~5 O3 L. s1 M$ k
            // 将纹理的数据拷贝给渲染器
$ ?( U5 S' L0 e& C9 r! e            SDL_RenderCopy(renderer, texture, NULL, &rect);  J& o7 C" r! P) ]9 P
            // 显示
  y& r' L  g9 D$ U2 S- s5 s. [6 y            SDL_RenderPresent(renderer);$ t# w$ d, U. m( N  N9 w
        }
% V* X, U" \4 w  J        else if(event.type == SDL_WINDOWEVENT)
6 a! N5 S$ N6 U9 b        {( K/ L) Y9 @* f+ c1 `6 [
            //If Resize
( [& l. j6 ]1 L) g            SDL_GetWindowSize(window, &win_width, &win_height);
$ @% \9 \3 S8 A/ |5 x            printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n",win_width,
+ k$ @) Z7 ?+ ^+ g                   win_height );) E/ N: T' t; K. C+ \  z$ J
        }  r! Q' R% ?' t; s+ I! {
        else if(event.type == SDL_QUIT) //退出事件
9 _# p4 N5 Y% w6 s  M1 y  n% o        {
8 s, f) ?, r7 W  V3 G* w8 x# n            s_thread_exit = 1;$ W& g$ d2 D+ q
        }9 J( v6 l+ |8 d$ \" ~7 G# j
        else if(event.type == QUIT_EVENT)0 {& E2 g' F  g) o- [1 d
        {
' a' f1 c7 P+ r, g# |            break;! |1 ]. N: ^" O$ ^7 G# D- [+ i
        }! m9 Z2 m) u7 w8 M# U. H* w
    }1 c4 a8 f; l. _6 J) d5 L4 F& b8 x
; W( B- b3 F) W2 Z0 \
_FAIL:
" A1 s5 L9 H" I& C1 d( L/ W2 ]    s_thread_exit = 1;      // 保证线程能够退出1 D- V2 N- b& v# m2 Y: P
    // 释放资源
5 B7 r. g. P; {8 {1 |( [    if(timer_thread)' h6 v, ^" r# Q( P1 f
        SDL_WaitThread(timer_thread, NULL); // 等待线程退出
  K: }' U0 `6 P8 H$ i0 s9 o3 K    if(video_buf)
+ [- b8 y( T* m        free(video_buf);; u0 X* N5 u( O- {5 O- G
    if(video_fd)
( Z. y  n" D! o        fclose(video_fd);
8 x- g  b1 w- C5 C. G% \    if(texture)0 k% [. g* H5 @+ ^
        SDL_DestroyTexture(texture);
) k" j7 F8 v. |. L    if(renderer)
% b5 w) I) z2 o% _; f6 d        SDL_DestroyRenderer(renderer);. f2 u7 y- D0 n+ n+ e2 x6 {! k
    if(window)  r8 c8 D/ o* O' Z
        SDL_DestroyWindow(window);
6 ^4 n2 a% ]! _, ?3 @2 N
/ Q( C* D$ X3 i5 }+ i+ a) D2 P    SDL_Quit();
) B+ V9 T/ v' s$ ]+ B5 X) n+ E& j- v
    return 0;: x/ q* d3 Z4 ^1 Q
" A* C, |3 R, F9 A& ?
}; a( E# z( P$ a

; K) {$ g4 Q! T4 }- z: a( A% D

.pro文件配置成:

TEMPLATE = app
6 Z5 e3 q- ~0 l2 `9 [; E1 ]7 wCONFIG += console
: e: b. u, ]! x# jCONFIG -= app_bundle4 A! U$ N8 y  e: K( k
CONFIG -= qt1 X+ ~, `# X. X; f8 [
3 a# z' t" F: j% _- X; ^1 d# t, y" R. T
SOURCES += \3 d/ \0 a  J& _' {) f
        main.c
9 V% a% N: ?8 m5 c  _+ sINCLUDEPATH += /home/txp/ffmpeg_build/include8 r% g4 |3 t% o( ^' h' E
LIBS += /home/txp/ffmpeg_build/lib/libSDL2.so
1 w" M# i. N. x: x" s! Q
; K9 K5 _! F/ c% G) v& I. n

最终运行结果就可以看到在播放一个yuv格式的视频文件了:

微信图片_20210201125458.png

注:这里的播放yuv格式的视频文件,我是事先已经准备好的:

微信图片_20210201125501.png

同时要注意我们要把播放的视频文件放到工程目录下,不然播放是不会成功的:

微信图片_20210201125505.png
四、总结:

现在ffmpeg真正的开发环境已经搭建完了,其实上面搭建环境蛮折腾人的,特别是源码安装ffmpeg。好了今天的文章就分享到这里了,如果你在看完文章后,有不懂的地方可以后台私聊我。

- `, Q* E5 s, q
赞 收藏 评论0 发布时间:2021-2-1 13:03

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版