基础配置
头文件
include
库文件
lib lib/x86 x64
动态库文件
dll bin/x86 x64
调式执行和pdb路径
bin/x86 x64
源码项目路径
src/first_ffmpeg
ffmpeg源码
tools
将文件配置进入项目中
(以Visual Studio 2017为例)
YUV格式
YUV444
表示$4:4:4$的YUV取样。
每个像素都有独立的Y、U、V分量。
每一个像素Y占一个字节,U占一个字节,V占一个字节,因此每个像素占:
$$1 (Y)×8 bits+1 (U)×8 bits+1 (V)×8 bits=24 bits/pixel (bpp)$$
以$2\times 2$的图像为例
1 2 3 4
| 像素1:Y1, U1, V1 像素2:Y2, U2, V2 像素3:Y3, U3, V3 像素4:Y4, U4, V4
|
YUV422
表示$4:2:2$的YUV取样。
每相邻两个像素每个像素占一个Y,共享一个U和一个V,因此两个像素占:
$$2 (Y)×8 bits+1 (U)×8 bits+1 (V)×8 bits=32 bits$$
每个像素占:
$$\displaystyle\frac{32bits}{2 pixels}=16 bits/pixel (bpp)$$
以$2\times 2$的图像为例
1 2 3 4
| 像素1:Y1, U1, V1 像素2:Y2, U1, V1 像素3:Y3, U2, V2 像素4:Y4, U2, V2
|
YUV422 格式比 YUV444 格式节省了数据量,同时仍然保持较高的图像质量。这就是为什么 YUV422 格式广泛用于视频压缩和传输的原因。
YUV411
表示$4:1:1$的YUV取样。
每相邻四个像素每个像素占一个Y,共享一个U和一个V,因此四个像素占:
$$4 (Y)×8 bits+1 (U)×8 bits+1 (V)×8 bits=48 bits$$
每个像素占:
$$\displaystyle\frac{48bits}{4 pixels}=12 bits/pixel (bpp)$$
以$2\times 2$的图像为例
1 2 3 4
| 像素1:Y1, U1, V1 像素2:Y2, U1, V1 像素3:Y3, U1, V1 像素4:Y4, U1, V1
|
YUV420
表示$4:2:0$的YUV取样。
水平每两个像素与垂直每两个像素中Y取4个,U取1个,V取1个,因此两个像素占:
$$4 (Y)×8 bits+1 (U)×8 bits+1 (V)×8 bits=48 bits$$
每个像素占:
$$\displaystyle\frac{48bits}{4 pixels}=12 bits/pixel (bpp)$$
以$2\times 2$的图像为例
1 2 3 4
| 像素1:Y1, U1, V1 像素2:Y2, U1, V1 像素3:Y3, U1, V1 像素4:Y4, U1, V1
|
这里的$4:2:0$代表了$4:2:0$和$4:0:2$两种情况,它们在奇偶行交错出现。
常见的H.264、H.265、VP8、AV1等都是以它为基础进行编解码的。
SDL_QT渲染
SDL(Simple DirectMedia Layer)在 FFmpeg 中的作用主要集中在视频和音频的实时播放方面。SDL 是一个跨平台的多媒体库,用于访问底层的硬件(如音频、视频、输入设备)并提供图形用户界面功能。
代码展示
sdlqtrgb.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #include "sdlqtrgb.h" #include <sdl/SDL.h>
#pragma comment(lib, "SDL2.lib")
static SDL_Window* sdl_win = NULL; static SDL_Renderer* sdl_render = NULL; static SDL_Texture* sdl_texture = NULL; static int sdl_width = 0; static int sdl_height = 0; static unsigned char* rgb = nullptr; static int pix_size = 4;
void SDLQtRGB::timerEvent(QTimerEvent* ev) { static unsigned char tmp = 255; tmp--; for (int j = 0; j < sdl_height; j++) { int b = j * sdl_width * pix_size; for (int i = 0; i < sdl_width * pix_size; i += pix_size) { rgb[b + i] = 0; rgb[b + i + 1] = tmp; rgb[b + i + 2] = 0; rgb[b + i + 3] = 0; } } SDL_UpdateTexture(sdl_texture, NULL, rgb, sdl_width * pix_size); SDL_RenderClear(sdl_render); SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = sdl_width; rect.h = sdl_height; SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect); SDL_RenderPresent(sdl_render); }
SDLQtRGB::SDLQtRGB(QWidget *parent) : QWidget(parent) { ui.setupUi(this);
sdl_width = ui.label->width(); sdl_height = ui.label->height();
SDL_Init(SDL_INIT_VIDEO); sdl_win = SDL_CreateWindowFrom((void*)ui.label->winId()); sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
sdl_texture = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, sdl_width, sdl_height );
rgb = new unsigned char[sdl_width * sdl_height * pix_size];
startTimer(10); }
SDLQtRGB::~SDLQtRGB() {}
|
获取label的宽高
1 2
| sdl_width = ui.label->width(); sdl_height = ui.label->height();
|
初始化SDL
1 2 3 4 5
| SDL_Init(SDL_INIT_VIDEO);
extern DECLSPEC int SDLCALL SDL_Init(Uint32 flags);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| SDL_INIT_VIDEO
#define SDL_INIT_TIMER 0x00000001u #define SDL_INIT_AUDIO 0x00000010u #define SDL_INIT_VIDEO 0x00000020u #define SDL_INIT_JOYSTICK 0x00000200u #define SDL_INIT_HAPTIC 0x00001000u #define SDL_INIT_GAMECONTROLLER 0x00002000u #define SDL_INIT_EVENTS 0x00004000u #define SDL_INIT_SENSOR 0x00008000u #define SDL_INIT_NOPARACHUTE 0x00100000u #define SDL_INIT_EVERYTHING ( \ SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \ SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_SENSOR \ )
|
SDL_Init(SDL_INIT_VIDEO);
是用于初始化 SDL 的视频子系统的函数调用。通过这个调用,SDL 会设置视频驱动、显示模式等,使得后续的图形绘制操作可以顺利进行。在开发基于 SDL 的多媒体应用时,这通常是必不可少的初始化步骤。
创建窗口
1 2 3
| static SDL_Window* sdl_win = NULL;
sdl_win = SDL_CreateWindowFrom((void*)ui.label->winId());
|
SDL_Window
用于窗口的结构体,通常包含了有关窗口的各个消息,通常只为指针使用。
SDL_CreateWindowFrom
函数是 SDL 库中的一个函数,它允许 SDL 使用现有的窗口句柄创建一个 SDL 窗口。
1 2 3 4 5 6
| extern DECLSPEC SDL_Window * SDLCALL SDL_CreateWindowFrom(const void *data);
|
ui.label->winId()
是 Qt 提供的一个函数,返回一个表示窗口句柄的 WId
类型(通常是一个平台相关的窗口句柄,比如 HWND 在 Windows 上)。这里我们将其强制转换为 void*
以便 SDL 可以使用。
【总结】:使用Qt的label窗口句柄,创建SDL_Window。
创建渲染器
1 2 3
| static SDL_Renderer* sdl_render = NULL;
sdl_render = SDL_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED);
|
SDL_Renderer
是一个不透明的数据类型,通常只作为指针使用。它表示用于渲染的上下文,可以在其中绘制点、线、矩形、纹理等图形元素。
1 2
| extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
|
参数解释:
创建材质
1 2 3 4 5 6 7 8
| static SDL_Texture* sdl_texture = NULL;
sdl_texture = SDL_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, sdl_width, sdl_height );
|
SDL_Texture
是 SDL 库中的一个结构体类型,用于表示纹理。纹理是指可以被渲染器处理和显示的图像数据。
SDL_CreateTexture
函数原型:
1 2
| extern DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
|
参数解释:
renderer:SDL_Renderer*
类型,指向要在其上创建纹理的渲染器。
format:Uint32
类型,纹理的像素格式。常用的像素格式包括 SDL_PIXELFORMAT_ARGB8888
、SDL_PIXELFORMAT_RGBA8888
等。
access:int
类型,纹理的访问模式。可以是以下值之一:
SDL_TEXTUREACCESS_STATIC
:纹理的内容不会改变。
SDL_TEXTUREACCESS_STREAMING
:纹理的内容会经常改变,可以通过锁定纹理来访问像素数据。
SDL_TEXTUREACCESS_TARGET
:纹理可以作为渲染目标。
w:int
类型,纹理的宽度(以像素为单位)。
h:int
类型,纹理的高度(以像素为单位)。
表示RGB颜色
1 2 3 4 5
| static unsigned char* rgb = nullptr;
static int pix_size = 4;
rgb = new unsigned char[sdl_width * sdl_height * pix_size];
|
unsigned char*
是一个指向 unsigned char
类型的指针。unsigned char
是一种基本数据类型,表示一个无符号的 8 位整数(通常用于表示字节数据)。
在图像处理和低级别数据操作中,unsigned char
类型经常用于表示原始字节数据,比如 RGB 颜色值。
调用QT的timerEvent槽函数(重载了的)
函数原型:
1
| int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
|
参数解释:
interval (int):
- 表示计时器的时间间隔,单位为毫秒。计时器每经过这个时间间隔就会触发一次定时器事件。
- 例如,如果
interval
设置为 1000,那么计时器每隔 1 秒触发一次定时器事件。
timerType (Qt::TimerType):
-
指定计时器的类型。这个参数是可选的,默认值为
。Qt 提供了几种不同的计时器类型:
Qt::PreciseTimer
:精确的定时器,尽量确保定时器精确地按照指定的间隔时间触发。
Qt::CoarseTimer
:粗略的定时器,可能会稍微不精确,但消耗的资源较少,适合大多数普通应用。
Qt::VeryCoarseTimer
:非常粗略的定时器,间隔时间可能会有较大误差,消耗的资源最少,适用于对精度要求很低的场景。
填充RGBA的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
static unsigned char tmp = 255; tmp--; for (int j = 0; j < sdl_height; j++) { int b = j * sdl_width * pix_size; for (int i = 0; i < sdl_width * pix_size; i += pix_size) { rgb[b + i] = 0; rgb[b + i + 1] = tmp; rgb[b + i + 2] = 0; rgb[b + i + 3] = 0; } }
|
更新纹理内容
1
| SDL_UpdateTexture(sdl_texture, NULL, rgb, sdl_width * pix_size);
|
SDL_UpdateTexture
函数用于更新纹理的内容,即将新的像素数据上传到指定的纹理中。
源码:
1 2 3 4
| extern DECLSPEC int SDLCALL SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch);
|
参数说明:
texture (SDL_Texture)*
- 指向要更新的纹理对象。在你的代码中,这个纹理对象是
sdl_texture
。
rect (const SDL_Rect)*
- 指定要更新的纹理区域。传递
NULL
表示更新整个纹理。
- 在你的代码中,传递的是
NULL
,因此整个纹理将被更新。
pixels (const void)*
- 指向新像素数据的指针。在你的代码中,这个指针是
rgb
,指向包含新像素数据的内存。
pitch (int)
- 每行像素数据的字节数,通常是纹理的宽度乘以每像素的字节数(即像素格式的字节数)。
- 在你的代码中,这是
sdl_width * pix_size
,表示每行像素数据的字节数。
- 从上到下,从左到右进行纹理更新
进行渲染
1 2 3 4 5 6 7 8
| SDL_RenderClear(sdl_render); SDL_Rect rect; rect.x = 0; rect.y = 0; rect.w = sdl_width; rect.h = sdl_height; SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect); SDL_RenderPresent(sdl_render);
|
-
SDL_RenderClear(sdl_render)
:清除当前渲染目标。
-
SDL_Rect rect
:定义一个矩形区域,用于指定纹理在窗口中的位置和大小。
-
rect.x
和 rect.y
:设置矩形的左上角位置为 (0, 0)。
-
rect.w
和 rect.h
:设置矩形的宽度和高度为纹理的宽度和高度。
-
SDL_RenderCopy(sdl_render, sdl_texture, NULL, &rect)
:将纹理复制到渲染目标(窗口)。
-
SDL_RenderPresent(sdl_render)
:更新屏幕,显示当前渲染的内容。
SDL_RenderCopy
函数原型:
1 2 3 4
| extern DECLSPEC int SDLCALL SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect);
|
参数解释:
- renderer (SDL_Renderer)*
- 指向渲染器的指针,用于绘制操作。在你的代码中,这是
sdl_render
。
- 渲染器是一个用于管理所有的绘制操作的对象,它与特定的窗口相关联。
- texture (SDL_Texture)*
- 指向纹理的指针,这是要复制的图像数据。在你的代码中,这是
sdl_texture
。
- 纹理包含了要绘制的像素数据。
- srcrect const SDL_Rect)(源矩阵)*
- 指向
SDL_Rect
结构的指针,用于指定从纹理的哪一部分复制。如果为 NULL
,则表示从整个纹理复制。
- 在你的代码中,这个参数是
NULL
,因此整个纹理都会被复制。
- dstrect (const SDL_Rect)(目标矩阵)*
- 指向
SDL_Rect
结构的指针,用于指定纹理复制到渲染目标的哪一部分。如果为 NULL
,则表示纹理将被复制到整个渲染目标。
- 在你的代码中,这是
&rect
,表示纹理将被复制到渲染目标中由 rect
指定的区域。
SDL_Rect
结构体:
SDL_Rect
结构体用于定义一个矩形区域,包含以下成员:
int x
:矩形左上角的 x 坐标。
int y
:矩形左上角的 y 坐标。
int w
:矩形的宽度。
int h
:矩形的高度。
main.cpp
1 2 3 4 5 6 7 8 9 10 11
| #include "sdlqtrgb.h" #include <QtWidgets/QApplication>
int main(int argc, char *argv[]) { QApplication a(argc, argv); SDLQtRGB w; w.show(); return a.exec(); }
|
sdlqtrgb.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #pragma once
#include <QtWidgets/QWidget> #include "ui_sdlqtrgb.h"
class SDLQtRGB : public QWidget { Q_OBJECT
public: SDLQtRGB(QWidget *parent = nullptr); ~SDLQtRGB(); void timerEvent(QTimerEvent* ev) override;
private: Ui::SDLQtRGBClass ui; };
|
使用 override
关键字的主要目的包括:
- 编译时检查:确保函数签名与基类中的虚函数匹配,防止由于拼写错误或参数类型错误导致的意外行为。
- 提高可读性:明确表明哪些函数是重写基类中的虚函数,便于代码维护和理解。
xvideo_view
代码展示
xsdl.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
| #include "xsdl.h" #include <sdl/SDL.h> #include <iostream> #pragma comment(lib, "SDL2.lib")
static bool InitVideo() { static bool is_first = true; static std::mutex mux; std::unique_lock<std::mutex> sdl_lock(mux); if (!is_first) return true; is_first = false; if (SDL_Init(SDL_INIT_VIDEO)) { std::cout << SDL_GetError() << std::endl; return false; }
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
return true; }
bool XSDL::IsExit() { SDL_Event ev;
SDL_WaitEventTimeout(&ev, 1);
if (ev.type == SDL_QUIT) return true; return false; }
void XSDL::Close() {
std::unique_lock<std::mutex> sdl_lock(mtx_);
if (texture_) { SDL_DestroyTexture(texture_); texture_ = nullptr; }
if (render_) { SDL_DestroyRenderer(render_); render_ = nullptr; }
if (win_) { SDL_DestroyWindow(win_); win_ = nullptr; } }
bool XSDL::Init(int w, int h, Format fmt, void *win_id) { if (w <= 0 || h <= 0) return false;
InitVideo();
std::unique_lock<std::mutex> sdl_lock(mtx_); width_ = w; height_ = h; fmt_ = fmt;
if (texture_) SDL_DestroyTexture(texture_);
if (render_) SDL_DestroyRenderer(render_);
if (!win_) { if (win_id) { win_ = SDL_CreateWindowFrom(win_id); } else { win_ = SDL_CreateWindow("Video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); } }
if (!win_) { std::cerr << SDL_GetError() << std::endl; return false; }
render_ = SDL_CreateRenderer(win_, -1, SDL_RENDERER_ACCELERATED); if (!render_) { std::cerr << SDL_GetError() << std::endl; return false; }
unsigned int sdl_fmt = SDL_PIXELFORMAT_RGBA8888;
switch (fmt_) { case XVideoView::RGBA: break; case XVideoView::YUV420P: sdl_fmt = SDL_PIXELFORMAT_IYUV; break; case XVideoView::ARGB: sdl_fmt = SDL_PIXELFORMAT_ARGB32; break; default: break; }
texture_ = SDL_CreateTexture(render_, sdl_fmt, SDL_TEXTUREACCESS_STREAMING, w, h ); if (!texture_) { std::cerr << SDL_GetError() << std::endl; return false; }
return true; }
bool XSDL::Draw(const unsigned char* data, int linesize) { if (!data) return false;
std::unique_lock<std::mutex> sdl_lock(mtx_);
if (!texture_ || !render_ || !win_ || width_ <= 0 || height_ <= 0) return false;
if (linesize <= 0) { switch (fmt_) { case XVideoView::RGBA: break; case XVideoView::YUV420P: linesize = width_; break; case XVideoView::ARGB: linesize = width_ * 4; break; default: break; } } if (linesize <= 0) return false;
auto re = SDL_UpdateTexture(texture_, NULL, data, linesize);
if (re != 0) { std::cout << SDL_GetError() << std::endl; return false; }
SDL_RenderClear(render_);
if (scale_w_ <= 0) scale_w_ = width_; if (scale_h_ <= 0) scale_h_ = height_; SDL_Rect rect; SDL_Rect *prect = nullptr; if (scale_w_ > 0) { rect.x = 0; rect.y = 0; rect.h = scale_h_; rect.w = scale_w_; prect = ▭ } re = SDL_RenderCopy(render_, texture_, NULL, prect); if (re != 0) { std::cout << SDL_GetError() << std::endl; return false; }
SDL_RenderPresent(render_); return true; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static bool InitVideo() { static bool is_first = true; static std::mutex mux; std::unique_lock<std::mutex> sdl_lock(mux); if (!is_first) return true; is_first = false; if (SDL_Init(SDL_INIT_VIDEO)) { std::cout << SDL_GetError() << std::endl; return false; }
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
return true; }
|
xsdl.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #pragma once #include "xvideo_view.h"
struct SDL_Window; struct SDL_Renderer; struct SDL_Texture;
class XSDL :public XVideoView { public:
void Close() override;
bool Init(int w, int h, Format fmt = RGBA, void *win_id = nullptr) override;
bool Draw(const unsigned char* data, int linesize = 0) override;
bool IsExit() override;
private: SDL_Window *win_ = nullptr; SDL_Renderer *render_ = nullptr; SDL_Texture *texture_ = nullptr; };
|
xvideo_view.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include "xsdl.h"
XVideoView* XVideoView::Create(RenderType type) { switch (type) { case XVideoView::SDL: return new XSDL(); break; default: break; }
return nullptr; }
|
xvideo_view.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| #ifndef XVIDEO_VIEW_H #define XVIDEO_VIEW_H #include <mutex>
class XVideoView { public: enum Format { RGBA = 0, YUV420P, ARGB };
enum RenderType { SDL = 0 };
static XVideoView* Create(RenderType type=SDL);
virtual bool Init(int w, int h, Format fmt = RGBA, void *win_id = nullptr) = 0;
virtual bool Draw(const unsigned char* data, int linesize = 0) = 0;
virtual void Close() = 0;
virtual bool IsExit() = 0;
void Scale(int w, int h) { scale_w_ = w; scale_h_ = h; } protected: int width_ = 0; int height_ = 0; Format fmt_ = RGBA; std::mutex mtx_; int scale_w_ = 0; int scale_h_ = 0; };
#endif
|
sdlqtvideo.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| #include "sdlqtrgb.h" #include <fstream> #include <QMessageBox> #include "xvideo_view.h"
static int sdl_width = 0; static int sdl_height = 0; static unsigned char* yuv = nullptr; static int pix_size = 2; static std::ifstream yuv_file; static XVideoView *view = nullptr;
void SDLQtRGB::timerEvent(QTimerEvent* ev) { yuv_file.read((char*)yuv, sdl_width * sdl_height * 1.5); if (view->IsExit()) { view->Close(); exit(0); } view->Draw(yuv); }
SDLQtRGB::SDLQtRGB(QWidget *parent) : QWidget(parent) { yuv_file.open("400_300_25.yuv", std::ios::binary); if (!yuv_file) { QMessageBox::information(this, "", "open yuv failed!"); return; }
ui.setupUi(this);
sdl_width = 400; sdl_height = 300; this->resize(sdl_width, sdl_height); ui.label->resize(sdl_width, sdl_height); view = XVideoView::Create(); view->Init(sdl_width, sdl_height, XVideoView::YUV420P);
view->Close(); view->Init(sdl_width, sdl_height, XVideoView::YUV420P, (void*)ui.label->winId());
yuv = new unsigned char[sdl_width * sdl_height * pix_size];
startTimer(40); }
void SDLQtRGB::resizeEvent(QResizeEvent *ev) { ui.label->resize(size()); ui.label->move(0, 0); view->Scale(width(), height()); }
SDLQtRGB::~SDLQtRGB() {}
|
sdlqtvideo.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #pragma once
#include <QtWidgets/QWidget> #include "ui_sdlqtrgb.h"
class SDLQtRGB : public QWidget { Q_OBJECT
public: SDLQtRGB(QWidget *parent = nullptr); ~SDLQtRGB(); void timerEvent(QTimerEvent* ev) override; void resizeEvent(QResizeEvent *ev) override;
private: Ui::SDLQtRGBClass ui; };
|