XVideoView.cpp
bool XVideoView::drawAVFrame(AVFrame* frame)
{
bool ret = (frame != nullptr);
if (ret)
{
switch (frame->format)
{
case AV_PIX_FMT_ARGB:
case AV_PIX_FMT_RGBA:
ret = draw(frame->data[0], frame->linesize[0]);
break;
case AV_PIX_FMT_YUV420P:
ret = draw(frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2]);
break;
default:
ret = false;
break;
}
}
return ret;
}
XSDL.cpp
bool XSDL::draw(const unsigned char* Yplane, int Ypitch,
const unsigned char* Uplane, int Upitch,
const unsigned char* Vplane, int Vpitch)
{
bool ret = (Yplane && (Ypitch > 0) && Uplane && (Upitch > 0) && Vplane && (Vpitch > 0) && (m_width > 0) && (m_height > 0) && m_win && m_render && m_texture);
if (ret)
{
// 复制内存到显存中
ret = (SDL_UpdateYUVTexture(m_texture, nullptr, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) == 0);
if (ret)
{
SDL_Rect rect;
SDL_Rect* pr = nullptr;
rect.x = 0;
rect.y = 0;
rect.w = m_scaleWid; // rect.w, rect.h 为显示的尺寸大小
rect.h = m_scaleHgh;
/* 默认渲染尺寸为窗口大小,若用户设置了缩放尺寸,则使用用户设定的尺寸来渲染 */
if ((m_scaleWid > 0) && (m_scaleHgh > 0))
{
pr = ▭
}
// 清空屏幕
SDL_RenderClear(m_render);
// 将材质复制到渲染器
ret = (SDL_RenderCopy(m_render, m_texture, nullptr, pr) == 0);
if (ret)
{
SDL_RenderPresent(m_render);
}
else
{
cerr << SDL_GetError() << endl;
}
}
else
{
cerr << SDL_GetError() << endl;
}
}
return ret;
}
SdlQtRGB.cpp
#include "SdlQtRGB.h"
#include "XVideoView.h"
#include <iostream>
#include <fstream>
#include <QMessageBox>
extern "C"
{
#include "libavcodec/avcodec.h"
}
using namespace std;
static AVFrame* frame = nullptr;;
static int sdl_width = 0;
static int sdl_height = 0;
static int pixel_size = 2;
static ifstream yuv_file;
static XVideoView* view = nullptr;
SdlQtRGB::SdlQtRGB(QWidget *parent)
: QWidget(parent)
{
int r = 0;
yuv_file.open("400_300_25.yuv", ios::in | ios::binary);
if (!yuv_file)
{
QMessageBox::information(this, "information", "open 400_300_25.yuv failed!");
return;
}
ui.setupUi(this);
sdl_width = 400;
sdl_height = 300;
ui.label->resize(400, 300);
view = XVideoView::create();
if (view)
{
view->init(sdl_width, sdl_height, XVideoView::YUV420P);
view->init(sdl_width, sdl_height, XVideoView::YUV420P, (void*)ui.label->winId());
}
frame = av_frame_alloc();
frame->width = 400;
frame->height = 300;
frame->format = AV_PIX_FMT_YUV420P;
// Y Y
// UV
// Y Y
frame->linesize[0] = sdl_width; // Y
frame->linesize[1] = sdl_width / 2; // U
frame->linesize[2] = sdl_width / 2; // V
r = av_frame_get_buffer(frame, 0);
if (r != 0)
{
char buf[1024] = {0};
av_strerror(r, buf, sizeof(buf));
cerr << buf << endl;
}
startTimer(10); // 每过10ms就会调用一次 timerEvent,1s大约有100帧的图像
}
void SdlQtRGB::timerEvent(QTimerEvent* evt)
{
/* AVFrame 中 YUV 是单独存放的,所以需要分开进行读取 */
yuv_file.read((char*)frame->data[0], sdl_width * sdl_height); // Y
yuv_file.read((char*)frame->data[1], sdl_width * sdl_height / 4); // U
yuv_file.read((char*)frame->data[2], sdl_width * sdl_height / 4); // V
if (view)
{
view->drawAVFrame(frame);
if (view->isExit())
{
view->close();
delete view;
exit(0);
}
}
}
void SdlQtRGB::resizeEvent(QResizeEvent* evt)
{
ui.label->resize(size());
ui.label->move(0, 0);
// view->scale(width(), height());
}
SdlQtRGB::~SdlQtRGB()
{
av_frame_free(&frame);
}