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

Qt+SDL+ffmpeg视频播放演示

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

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

sudo apt install ffmpeg- W4 \$ k- o1 \6 {

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

bin   ffmpeg_sources    ffmpeg_build
( U+ c4 y9 S, ]0 O" I) `

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

txp@txp-virtual-machine:~/bin$ ls  w- x! Q% O& G; i0 Z; ]$ M
ffmpeg  ffplay  ffprobe  lame  nasm  
5 @; c2 S( z* p5 ^0 L4 _/ |  Nndisasm  x2644 K( G9 l5 j4 R

, K$ m0 U- I( M+ E

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

txp@txp-virtual-machine:~/ffmpeg_sources$ ls
( M+ }9 d5 u  y1 Z1 \fdk-aac                  lame-3.100.tar.gz     SDL2-2.0.14.tar.gz* c# b* n$ J; A2 D6 H: _7 L
ffmpeg                   libvpx                SVT-AV1
2 a6 ?' c/ i0 @3 ]% N$ uffmpeg-4.2.1             nasm-2.14.02          x264
2 g, h  a8 H; f2 O  }" tffmpeg-4.2.1.tar.bz2     nasm-2.14.02.tar.bz2  x265_git& M5 ]' N, s8 h9 V( `
ffmpeg-snapshot.tar.bz2  opus- ?) e' G; q8 Z4 R) {9 ~
lame-3.100               SDL2-2.0.149 o- h0 K5 o+ ?' ^) E! a- R
0 V. d3 I% u1 i- Y, @. u3 Y

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

txp@txp-virtual-machine:~/ffmpeg_build/lib$ ls
3 C; P+ Y  \( |4 m3 j. }7 wcmake          libmp3lame.a           libSDL2.la       libswscale.a
' K( G; O  g" h8 m1 ^( {* qlibavcodec.a   libmp3lame.la          libSDL2main.a    libvpx.a8 z, J# v; ]- Q: q
libavdevice.a  libopus.a              libSDL2main.la   libx264.a
( R" L+ ?, i) o! k* h5 ?: \1 Dlibavfilter.a  libopus.la             libSDL2.so       libx265.a1 @% ~$ s% {0 t
libavformat.a  libpostproc.a          libSDL2_test.a   pkgconfig. G# m8 y1 M6 ?& p
libavutil.a    libSDL2-2.0.so.0       libSDL2_test.la, }" L2 K! a' @! o- @, \9 ^
libfdk-aac.a   libSDL2-2.0.so.0.14.0  libSvtAv1Enc.a! ?6 a9 _6 V3 ~1 k: ^" S$ Y
libfdk-aac.la  libSDL2.a              libswresample.a
1 y0 M  U% b# g" [# ~
& F1 ]2 S( ^! H

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

二、 qt环境搭建

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

  • 首先我们要去qt的官网下载linux版本的源码安装包:% w) {4 i! e( ^
版本下载地址:
4 E4 T, f' F: T3 x6 a1 @https://download.qt.io/archive/qt/5.12/5.12.10/$ \, b7 k5 d# u+ b* R
微信图片_20210201125402.png
  • 开始安装qt:
    / N; U$ l3 y. u" [% x6 H, L1 h

这里我直接把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 ./qtcreator8 q; ~: z! h/ a5 ]& T5 c
& M# I  L( e8 ]  j5 U
Got keys from plugin meta data ("xcb")
! f5 t% m$ a- MQFactoryLoader:FactoryLoader() checking directory path "/home/txp/share/qt/Qt5.12.10/Tools/QtCreator/bin/platforms" ...( h- S5 \8 N$ G: M8 w. m
loaded library "/home/txp/share/qt/Qt5.12.10/Tools/QtCreator/lib/Qt/plugins/platforms/libqxcb.so"
& V% f) R( s6 Q9 sloaded library "Xcursor"
8 B# u. d( Z0 MSegmentation fault (core dumped)8 W- e, q/ H) j# P( B7 @
' q, `+ d. B3 B% R4 u
  • 解决qt运行失败的方法:3 U" f5 d* Z" Z$ S3 W$ M; S

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

微信图片_20210201125422.png

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

sudo apt install --reinstall libxcb-xinerama09 Q6 v9 r, Y8 a8 O/ }

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

微信图片_20210201125425.png

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

txp@txp-virtual-machine:~/share/qt/Qt5.12.10/Tools/QtCreator/bin$
6 W2 f* Y1 T5 F( {sudo ./qtcreator
0 |8 s9 O0 w* h8 K2 a& r# ~7 K% P. {

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

sudo chown -R txp:txp ~/.config/; e: Y/ m2 Q0 v1 s# k% v
, \  w: f( m; z1 b

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

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

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

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

最终一个工程项目就建立好了:
* z4 {1 \( Z+ Z

微信图片_20210201125441.png

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

  • 配置pro文件:pro文件里面默认是:
    ; @: C8 ?  A1 g( s9 v
TEMPLATE = app
! y( |, }2 h2 {) H/ s. K; d( M% HCONFIG += console) i5 _6 @) M: v) K+ N
CONFIG -= app_bundle  G1 y( f3 C+ O0 F3 h7 ~+ Q% i) X0 T
CONFIG -= qt
) F3 B2 P! q* ^9 \+ l0 B$ M$ I" Z2 u* e' \% @5 Q' ~9 g
SOURCES += \' X# Q; f' D  p  E
        main.c
2 n. t+ M+ j4 [+ |. v
6 R- R! ]' C7 l2 |9 _1 h

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

TEMPLATE = app
8 P3 W* w  e; A5 G6 h3 CCONFIG += console
3 X$ Z( G" [' h6 y  eCONFIG -= app_bundle1 M' ]7 N" Z! l9 k  P
CONFIG -= qt5 E+ Q% K7 u0 P
& e# o5 Q2 _" _* \
SOURCES += \$ M/ V. |0 I& |3 ~: ]5 `
        main.c2 \4 }: F7 t& \9 T
INCLUDEPATH += /home/txp/ffmpeg_build/include- V8 R/ c- m0 v( |& W
#LIBS += /home/txp/ffmpeg_build/lib/libSDL2.so. W& a* j1 a' h" ^  I

, ]3 M4 s2 j$ Z5 m' VLIBS += /home/txp/ffmpeg_build/lib/libavcodec.a \
6 v8 e5 M* N3 V, ], l! G        /home/txp/ffmpeg_build/lib/libavdevice.a \
; ]; k& `! S# W* o& S        /home/txp/ffmpeg_build/lib/libavfilter.a \9 O: W- t: t, }9 D- y7 P0 X9 }1 @
        /home/txp/ffmpeg_build/lib/libavformat.a \4 U. |8 q* S8 r1 J6 z6 p
        /home/txp/ffmpeg_build/lib/libavutil.a \
2 A3 n8 a* S6 n        /home/txp/ffmpeg_build/lib/libswresample.a \
7 I- L/ [! V0 S4 Y/ N! A        /home/txp/ffmpeg_build/lib/libswscale.a) @+ ~/ M1 s1 i/ C

2 k0 l/ D2 u% W; F: r7 J3 M; W- j; X! D/ U! c
  • main.c源码文件就可以修改成这样:2 }6 r. s8 |; E2 I* q: q* n9 L
#include <stdio.h>  J$ V  x9 M* N' O6 o3 r6 E
//包含ffmpeg头⽂件
; l& f8 D! Y2 K1 K- w5 T" o#include "libavutil/avutil.h"
- ]6 v: P3 h/ I- Pint main()+ U& o6 V$ V$ r1 `
{
1 U/ x. o* o& t: W5 l( {- L    printf("Hello FFMPEG, version is %s\n", av_version_info());
& a  J8 I0 h7 @) M6 M    return 0;
/ a- r1 b2 Y( G/ o. i2 I}8 Q& N, W; ]9 G* a3 W: K

8 n$ e1 i5 F% k

最终结果,显示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 ...
; w( w; W! k6 o+ W3 o2 VHello FFMPEG, version is 4.2.1
! H; s: f$ a8 S8 g- T; b20: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
. U- O$ H$ ^* L/ D" u" f, G& ^# S7 f+ l

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

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

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

https://blog.csdn.net/leixiaohua1020/article/details/119540390 R1 m+ g8 h+ T4 a: k: n  s  M5 E
微信图片_20210201125450.png

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

https://www.libsdl.org/download-2.0.php
6 i8 @. r# g1 a8 D9 K3 H, A
微信图片_20210201125454.png
  • 开始安装,先把这个源码包放到ffmpeg_sources目录下去,然后进行解压:7 X, B/ C5 z% a, s2 \
txp@txp-virtual-machine:~/ffmpeg_sources$ tar zxf SDL2-2.0.14.tar.gz
# M9 C( k: l  |$ y. ]* xtxp@txp-virtual-machine:~/ffmpeg_sources$ ls
( B% y2 F2 M. z% P4 _3 Z* E: [fdk-aac                  lame-3.100.tar.gz     SDL2-2.0.14.tar.gz4 q1 H/ j2 M% T- w; d# j1 ?
ffmpeg                   libvpx                SVT-AV1- z5 z; t" l9 j* N2 [  ~5 }
ffmpeg-4.2.1             nasm-2.14.02          x2647 P: u4 A7 z- M! V  |: ^2 @
ffmpeg-4.2.1.tar.bz2     nasm-2.14.02.tar.bz2  x265_git# S. m, Y% y2 l( B( R( A) C
ffmpeg-snapshot.tar.bz2  opus
9 h6 ?) m- [  }- C' d  `8 glame-3.100               SDL2-2.0.14
# c) T+ _% T$ r4 W' c
# O: E" z& b1 I

然后执行:

txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$ ./autogen.sh 1 z# S  p5 a1 _9 D- Z1 c9 H
Generating build information using autoconf( w5 ^; E; s, |" z
This may take a while ...% ^- l) @3 t2 V, Z  e7 r) }; q6 c
Now you are ready to run ./configure
) p1 I+ g9 y4 f+ d
2 m* ^' _" X5 b( u; U

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

./configure --prefix=/home/txp/ffmpeg_build --bindir=/home/txp/bin   c# E" \$ P9 y8 w5 ~, `  b

% x# `. ~( @$ k7 G* ?0 B
  • 然后进行编译:make -j4+ |* h0 C( a! \9 v
txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$ 6 E' M5 k4 m' f0 x1 o4 l% A
make -j4; Y  o" b$ S) V1 b+ k$ j9 Y  y. n

) E% T$ W' @3 ]; W2 g5 Z
  • 最后再执行sudo make install就行,SDL就安装成功了:
    + D! z8 J' F+ n) n) h% f
txp@txp-virtual-machine:~/ffmpeg_sources/SDL2-2.0.14$
* p: Y9 U3 Z5 h! p, F5 lsudo make install! y) m/ E/ L. A5 }
0 {3 h9 l( w5 I8 ~- P

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

#include <stdio.h>3 z) E; ]7 X4 {; }8 c) M
#include <string.h>
# ^" T5 Y* S0 [#include "SDL2/SDL.h"//包含SDL动态库文件" Q2 R+ b% B: O( T* U- C4 d: g

- e/ u1 J2 @* ~4 ]//自定义消息类型; p9 E4 o% g6 A
#define REFRESH_EVENT   (SDL_USEREVENT + 1)     // 请求画面刷新事件
: b: t+ p9 q  }3 n7 M9 `+ ]#define QUIT_EVENT      (SDL_USEREVENT + 2)     // 退出事件. z3 m4 i6 w9 @% |' k6 Z$ e
9 e6 w  z: T) o/ a
//定义分辨率  F0 ~5 O+ H, ?' M5 {8 |! E) A
// YUV像素分辨率8 S9 f% ~  r: m+ `3 u9 @
#define YUV_WIDTH   3204 ]1 y9 B& a8 t) R* g
#define YUV_HEIGHT  240/ v" H- [8 n6 R) G5 M6 u
//定义YUV格式
* L; g1 X3 I* V9 y- T#define YUV_FORMAT  SDL_PIXELFORMAT_IYUV* |- B$ F7 ^6 X$ h: I, M: J

9 O( ~( v( L/ T/ r$ ]3 I2 pint s_thread_exit = 0;  // 退出标志 = 1则退出
& w% V% x; y- a; e1 v. C# j7 T
& |) Q  q& c) m$ W+ H- j4 jint refresh_video_timer(void *data); v& d4 y0 W- s/ _4 z, b
{
, u0 {$ {" _2 u    while (!s_thread_exit)7 E4 B8 o! a2 l% j8 k
    {, o/ ]. {$ W5 s9 z
        SDL_Event event;
9 e' E- V. ^; [; _0 m& d        event.type = REFRESH_EVENT;, m' q; y& O2 }# N3 G% O$ }
        SDL_PushEvent(&event);" v0 E+ w; [+ C& b! a, t
        SDL_Delay(40);
1 _5 Q5 W8 `+ ?6 I+ D7 Q+ w7 n) `    }
3 j' H9 u3 r, `/ P3 f% A" g6 U) `: \9 D  w8 K, S
    s_thread_exit = 0;! S4 L9 ]% G* [( l1 t* y0 R

7 S' v" u9 R. }8 ]+ `    //push quit event
" B+ A9 i- l5 }. b2 n4 D1 |  ^    SDL_Event event;
$ X% {! J- }& Z0 O3 i) }2 |  ~    event.type = QUIT_EVENT;
- i* @+ N* \7 |' k3 q    SDL_PushEvent(&event);
& _5 I( B8 b7 b6 x
) ^$ r6 P0 n% s9 f; t    return 0;
2 I( H. p% k. H% ?9 a. ~) H: q: n}6 d* t! v+ N; a* F/ P9 }; o$ @
#undef main6 |+ h5 W2 ~2 w, p5 _. v
int main(int argc, char* argv[]): ]: P# E- y! Z& [# k; @
{6 i9 ~0 {, A% b. f5 u
    //初始化 SDL' H5 ^" H9 ~$ ]4 ?- [+ x7 k0 c
    if(SDL_Init(SDL_INIT_VIDEO))
. `5 x& B  Z/ ~8 V2 M7 ^% }    {
  ~+ q4 x  ?% `8 t! P; N        fprintf( stderr, "Could not initialize SDL - %s\n", SDL_GetError());
1 `  l$ I) S) s# C: {: l        return -1;
& ^$ P, ?  L! K. ^9 w    }
9 Q4 D' ]3 a6 M; W" q3 M4 h3 b8 R2 c( Z
    // SDL# P* g+ Z9 F) L. p$ K0 ~+ e
    SDL_Event event;                            // 事件
, [. D: o* ?' m3 x% [# L( T    SDL_Rect rect;                              // 矩形. v9 A. _, n! [, l4 V
    SDL_Window *window = NULL;                  // 窗口9 \9 M! H+ s; y+ U/ q+ H) U% h; U
    SDL_Renderer *renderer = NULL;              // 渲染
5 p: g( e9 H- U1 q: B, T    SDL_Texture *texture = NULL;                // 纹理- j0 l! o) ?) z
    SDL_Thread *timer_thread = NULL;            // 请求刷新线程
- a  Z" D/ I6 I( ]) A    uint32_t pixformat = YUV_FORMAT;            // YUV420P,即是SDL_PIXELFORMAT_IYUV% L1 B4 C8 e4 D% i" X

' L9 B5 y8 E- o7 q    // 分辨率+ n& m) m- W$ L. w4 K
    // 1. YUV的分辨率
3 a, N. h' a+ y    int video_width = YUV_WIDTH;
% _6 k: J1 c: g, G! a* \7 d    int video_height = YUV_HEIGHT;
" v: u1 k# i* u7 m    // 2.显示窗口的分辨率8 z# N! `3 g$ [  ], K
    int win_width = YUV_WIDTH;+ w" g+ y( w" Z: |1 f% P
    int win_height = YUV_WIDTH;
  q- f8 x+ i7 b/ h0 @! z# `* Z: z9 M# t* V0 a- V) Q
    // YUV文件句柄! `2 N  d, V. S4 h0 s5 p* T1 |9 j
    FILE *video_fd = NULL;
- d5 [$ G7 _' l5 a" k7 j9 s    const char *yuv_path = "yuv420p_320x240.yuv";  x5 j1 a! d; d: r# t3 N; w1 u
$ }1 ^4 b; T1 D% h8 q/ p+ h) ~
    size_t video_buff_len = 0;
% o, {9 G# H' V: i. @; l' m+ v2 g/ x  n
    uint8_t *video_buf = NULL; //读取数据后先把放到buffer里面
5 @, d4 R) ]2 D1 ]* k. \' B0 P8 h! {( a* v* m
    // 我们测试的文件是YUV420P格式0 m' i/ a& Z6 u5 q
    uint32_t y_frame_len = video_width * video_height;* s' |6 l* Q; ~+ a' x% O
    uint32_t u_frame_len = video_width * video_height / 4;
% p+ I, F9 U" O' e0 t7 K# Q    uint32_t v_frame_len = video_width * video_height / 4;) G0 m1 E# X7 p4 I! l
    uint32_t yuv_frame_len = y_frame_len + u_frame_len + v_frame_len;4 a) i' x1 g& h* E* ^: u
& g1 X+ m) x$ d% X, ]) Q) o
    //创建窗口
$ {: G# u0 Y  j# i4 v+ n1 j    window = SDL_CreateWindow("Simplest YUV Player",% ~, ~( ]8 }! a: Z  v, x7 g' L$ ~
                           SDL_WINDOWPOS_UNDEFINED," _7 J: Y' C8 s& [) N0 s% f: S' _
                           SDL_WINDOWPOS_UNDEFINED,
: b4 M" k  z0 j% C" k) x( C) t                           video_width, video_height,
3 b5 U1 g' D3 i8 E& Q; t                           SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);( s6 L& w& W/ h+ R
    if(!window)) n$ i' t# W6 O9 A3 B" _
    {
4 k# c& X6 p( z8 j4 m* u* |9 `        fprintf(stderr, "SDL: could not create window, err:%s\n",SDL_GetError());
! T' N; Q. C  W2 P4 P        goto _FAIL;
9 q+ W* B8 a& b; u+ \    }' u9 A; ]* H3 ^4 [! i8 Q/ H
    // 基于窗口创建渲染器
& h, N  x6 y  j4 a    renderer = SDL_CreateRenderer(window, -1, 0);% {0 M3 D! X1 l" @1 Q/ K) ^
    // 基于渲染器创建纹理
# {0 z0 ]9 z2 B5 X4 s; ?    texture = SDL_CreateTexture(renderer,
) M8 D2 x8 C. l4 u4 w8 H) H                                pixformat,
9 h, h; Z4 B; r+ c                                SDL_TEXTUREACCESS_STREAMING,/ b: W5 g/ R. z; t4 J
                                video_width,7 D* [( s2 }9 @4 p4 C
                                video_height);2 [" \! l; r; M; @; y" |2 ]& M/ a

+ ]6 h  V* n% B. F: x    // 分配空间5 V. {+ k% Q& i1 x
    video_buf = (uint8_t*)malloc(yuv_frame_len);! V9 J! c- w, C! E5 r* n+ n
    if(!video_buf)* n% \& P. o+ ]& u
    {
; u5 h. M* o+ L3 e        fprintf(stderr, "Failed to alloce yuv frame space!\n");
' t, @3 ^) ?$ l) i        goto _FAIL;
# X. V9 _  [. k3 o/ i4 P) O! g    }5 O' u) s; A, d3 ^7 B( e9 U* q
& D+ V' }+ Y" M' j
    // 打开YUV文件" d* K# z, ?9 q
    video_fd = fopen(yuv_path, "rb");
* v2 }5 l. \1 h5 f    if( !video_fd )
# T: x; `$ f& E    {
/ C( `; m: W4 [/ P* Q        fprintf(stderr, "Failed to open yuv file\n");
+ B$ {( J. N- j; W+ ?        goto _FAIL;
* }) Q" F2 q- [6 z' v  e$ [2 f; q    }
2 M- b7 T2 J% G4 H5 [    // 创建请求刷新线程& }* z) f! F; v1 L
    timer_thread = SDL_CreateThread(refresh_video_timer,8 p; l" E! f/ h, h* f# }; L
                                    NULL,
' |6 J# f- F/ |( l" \                                    NULL);
3 o4 }  G$ W' w% _6 O1 X
3 \% e9 ]9 E' x& s    while (1)4 u+ D9 i; J* G6 o( h
    {  [6 C# {5 _" b" b7 ^
        // 收取SDL系统里面的事件" |, ~2 _- [8 v3 C! Q
        SDL_WaitEvent(&event);. S# Q1 t2 H# s  Z0 G

, C! b2 j* X4 S+ R  d        if(event.type == REFRESH_EVENT) // 画面刷新事件% t3 [& \/ f. H" U0 L) e
        {- _3 }& L2 C: M+ v
            video_buff_len = fread(video_buf, 1, yuv_frame_len, video_fd);
6 H, c7 c2 D4 p, ~* Z            if(video_buff_len <= 0)8 m- _, u* Z9 ?0 ]- F% A6 |9 B
            {
, {  I$ i7 F' d9 o: e2 s                fprintf(stderr, "Failed to read data from yuv file!\n");. ~2 h1 a, N! I# }0 _: r# ?3 E
                goto _FAIL;/ w: ]3 R9 W( Q& \4 ~- L  I
            }
! w" e, \. t1 O$ J            // 设置纹理的数据 video_width = 320, plane9 o4 g  f# R, {% G6 r& U% x
            SDL_UpdateTexture(texture, NULL, video_buf, video_width);; Y6 Y. N2 o' V
  O! o/ F1 d( a9 R; n7 p
            // 显示区域,可以通过修改w和h进行缩放. s! U: C0 C/ A; `
            rect.x = 0;
6 {" u' l' `9 Y2 Y# h            rect.y = 0;  P1 `- j/ H# m( L/ Q0 S8 R/ r: i/ N
            float w_ratio = win_width * 1.0 /video_width;
2 p: X, F: y1 n  X1 D4 r2 x            float h_ratio = win_height * 1.0 /video_height;1 u! n5 K; Q) k; k6 F6 e; N3 g
            // 320x240 怎么保持原视频的宽高比例
# l1 Y7 p/ w) m2 L$ P& Y            rect.w = video_width * w_ratio;
  z: A. O8 F6 U* H            rect.h = video_height * h_ratio;
. O/ g2 Y: s3 U' N" n; o//            rect.w = video_width * 0.5;3 y0 O9 I& \, K' {, u, z2 d
//            rect.h = video_height * 0.5;9 R! A3 a3 M; }& M, C
8 D7 n' M; v4 f7 a
            // 清除当前显示# o. K+ N- F+ J- k5 I
            SDL_RenderClear(renderer);% k. c5 R% d; A. |4 S; N
            // 将纹理的数据拷贝给渲染器
4 F0 ]9 k" X9 P3 k+ Y$ j            SDL_RenderCopy(renderer, texture, NULL, &rect);
6 z- F# V7 i) H1 L8 R            // 显示
7 i% @+ S0 c3 B0 N+ m            SDL_RenderPresent(renderer);8 G2 R2 {0 H4 m
        }
$ U( q7 @0 m" x, J: n! l        else if(event.type == SDL_WINDOWEVENT)5 T! T8 c  b# g9 f& o
        {
" e, I3 P: U9 k9 t0 S            //If Resize
$ Y! n* P! l$ f) W+ H6 w            SDL_GetWindowSize(window, &win_width, &win_height);+ c6 d# C5 M2 L- A6 x5 ], @
            printf("SDL_WINDOWEVENT win_width:%d, win_height:%d\n",win_width,
& w% G# t, F  K/ S                   win_height );+ q, f& E6 g4 ?& F1 J
        }! l+ U7 W* I1 ~' z& f
        else if(event.type == SDL_QUIT) //退出事件( t3 A1 D3 |  F! D& d
        {
$ x% s5 \2 W( }* F6 @            s_thread_exit = 1;: y/ S1 d' T$ {0 `
        }' R7 o# ?9 t" J% g2 F- {
        else if(event.type == QUIT_EVENT)
: m2 Q; T& T; O; n2 [6 o        {% d: f  e8 v8 o  i$ }% P3 k" @
            break;$ U( Z+ b4 ^& K' M( K1 q8 m# @
        }
( S" c* @; Z; j    }
; \# B0 {# Y  {  c- T/ Z) S' o  M& W0 i/ c, F4 p
_FAIL:
4 m7 \  _% p3 b( [$ ^: a$ `    s_thread_exit = 1;      // 保证线程能够退出& o4 T% {5 }* L0 F9 C" Y. r* A
    // 释放资源
0 g- `) }/ B% _" @# y8 ^+ Z* d8 a    if(timer_thread)
5 y3 J* U& k& o% ^        SDL_WaitThread(timer_thread, NULL); // 等待线程退出
1 p! w9 c: Y" p4 ^3 J) _- h    if(video_buf)/ {6 y. D; w# y  g  i9 a
        free(video_buf);
. V8 a& I  [$ }3 T8 i, @' u" ?    if(video_fd)4 Q+ P  {% R( n
        fclose(video_fd);
( @- E5 G( u8 \3 P    if(texture)
5 H5 y  q0 {: O        SDL_DestroyTexture(texture);  M; O+ G: T9 ]3 {9 g
    if(renderer)8 S9 t7 V8 O# V3 U
        SDL_DestroyRenderer(renderer);
: l7 Z8 I4 H* i2 W' s4 N* _4 c    if(window)0 s  H2 V7 {; ^, c6 Z
        SDL_DestroyWindow(window);
& e7 W- [* X& r
) a, a4 ^- _3 u1 ~3 V( _! c    SDL_Quit();, k" ^. w$ I: l( c/ i
, ]- W! ~( _5 X" V; V" [
    return 0;
' g0 u3 N  Y2 a1 a' E; h9 I( z
9 o  X4 d: B- d) \4 R, ~}' K* S5 C7 I2 D! P
! v$ I. c" L7 |3 b9 q+ O

.pro文件配置成:

TEMPLATE = app7 @. f. r- l" `) z3 ?8 W4 _
CONFIG += console
3 V# e. _& J0 s4 pCONFIG -= app_bundle
# x- T. h" D. \5 r0 F4 Y+ C& a% YCONFIG -= qt/ ?' \, [0 A$ O+ }  Y1 M. a
4 t* d/ ~! O4 q. G# M
SOURCES += \$ V; m. ?1 ~  B7 j
        main.c0 o1 ^9 J, @2 {3 p4 [- f
INCLUDEPATH += /home/txp/ffmpeg_build/include
3 F% o- K0 B. h, \* e* Y! qLIBS += /home/txp/ffmpeg_build/lib/libSDL2.so
7 R/ F5 t. n6 [2 @, q6 x8 ^3 b! C3 ^% U9 v: I! ]& B

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

微信图片_20210201125458.png

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

微信图片_20210201125501.png

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

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

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


& _5 n0 ^7 I: X6 a
收藏 评论0 发布时间:2021-2-1 13:03

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版