2021-10-11 17:16:26 +08:00
|
|
|
|
/*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
2017-05-08 18:03:43 +08:00
|
|
|
|
*
|
2021-06-29 17:44:35 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit).
|
2017-09-27 16:20:30 +08:00
|
|
|
|
*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Use of this source code is governed by MIT license that can be found in the
|
|
|
|
|
* LICENSE file in the root of the source tree. All contributing project authors
|
|
|
|
|
* may be found in the AUTHORS file in the root of the source tree.
|
2017-05-08 18:03:43 +08:00
|
|
|
|
*/
|
2020-04-04 20:30:09 +08:00
|
|
|
|
|
2017-05-08 18:03:43 +08:00
|
|
|
|
#ifndef YUVDISPLAYER_H_
|
|
|
|
|
#define YUVDISPLAYER_H_
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
#include "Util/onceToken.h"
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
2018-04-17 21:38:13 +08:00
|
|
|
|
#include "SDL2/SDL.h"
|
|
|
|
|
#include "libavcodec/avcodec.h"
|
2017-05-08 18:03:43 +08:00
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-04-17 21:38:13 +08:00
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
#pragma comment(lib,"SDL2.lib")
|
|
|
|
|
#endif //defined(_WIN32)
|
|
|
|
|
|
|
|
|
|
#define REFRESH_EVENT (SDL_USEREVENT + 1)
|
|
|
|
|
|
|
|
|
|
class SDLDisplayerHelper
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static SDLDisplayerHelper &Instance(){
|
|
|
|
|
static SDLDisplayerHelper *instance(new SDLDisplayerHelper);
|
|
|
|
|
return *instance;
|
|
|
|
|
}
|
|
|
|
|
static void Destory(){
|
|
|
|
|
delete &Instance();
|
|
|
|
|
}
|
|
|
|
|
template<typename FUN>
|
|
|
|
|
void doTask(FUN &&f){
|
|
|
|
|
{
|
2022-02-02 20:34:50 +08:00
|
|
|
|
std::lock_guard<std::mutex> lck(_mtxTask);
|
2018-04-17 21:38:13 +08:00
|
|
|
|
_taskList.emplace_back(f);
|
|
|
|
|
}
|
|
|
|
|
SDL_Event event;
|
|
|
|
|
event.type = REFRESH_EVENT;
|
|
|
|
|
SDL_PushEvent(&event);
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
void runLoop(){
|
|
|
|
|
bool flag = true;
|
|
|
|
|
std::function<bool ()> task;
|
|
|
|
|
SDL_Event event;
|
|
|
|
|
while(flag){
|
|
|
|
|
SDL_WaitEvent(&event);
|
|
|
|
|
switch (event.type){
|
2022-07-18 22:30:28 +08:00
|
|
|
|
case REFRESH_EVENT: {
|
2019-09-20 17:58:50 +08:00
|
|
|
|
{
|
2022-02-02 20:34:50 +08:00
|
|
|
|
std::lock_guard<std::mutex> lck(_mtxTask);
|
|
|
|
|
if (_taskList.empty()) {
|
2022-07-18 22:30:28 +08:00
|
|
|
|
// not reachable
|
2019-09-20 17:58:50 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
task = _taskList.front();
|
|
|
|
|
_taskList.pop_front();
|
|
|
|
|
}
|
|
|
|
|
flag = task();
|
|
|
|
|
break;
|
2022-07-18 22:30:28 +08:00
|
|
|
|
}
|
|
|
|
|
case SDL_QUIT:{
|
2019-09-20 17:58:50 +08:00
|
|
|
|
InfoL << event.type;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-17 21:38:13 +08:00
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
void shutdown(){
|
|
|
|
|
doTask([](){return false;});
|
|
|
|
|
}
|
2018-04-17 21:38:13 +08:00
|
|
|
|
private:
|
|
|
|
|
SDLDisplayerHelper(){
|
|
|
|
|
};
|
|
|
|
|
~SDLDisplayerHelper(){
|
2020-03-20 11:51:24 +08:00
|
|
|
|
shutdown();
|
2018-04-17 21:38:13 +08:00
|
|
|
|
};
|
2018-10-29 13:56:10 +08:00
|
|
|
|
private:
|
2018-04-17 21:38:13 +08:00
|
|
|
|
std::deque<std::function<bool ()> > _taskList;
|
|
|
|
|
std::mutex _mtxTask;
|
|
|
|
|
|
|
|
|
|
};
|
2017-05-08 18:03:43 +08:00
|
|
|
|
|
2018-06-30 23:02:16 +08:00
|
|
|
|
|
2017-05-08 18:03:43 +08:00
|
|
|
|
class YuvDisplayer {
|
|
|
|
|
public:
|
2021-06-29 17:44:35 +08:00
|
|
|
|
using Ptr = std::shared_ptr<YuvDisplayer>;
|
2018-04-17 21:38:13 +08:00
|
|
|
|
|
2021-06-29 17:44:35 +08:00
|
|
|
|
YuvDisplayer(void *hwnd = nullptr,const char *title = "untitled"){
|
2022-02-02 20:34:50 +08:00
|
|
|
|
static toolkit::onceToken token([]() {
|
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) == -1) {
|
|
|
|
|
std::string err = "初始化SDL失败:";
|
2018-04-17 21:38:13 +08:00
|
|
|
|
err+= SDL_GetError();
|
|
|
|
|
ErrorL << err;
|
|
|
|
|
throw std::runtime_error(err);
|
|
|
|
|
}
|
|
|
|
|
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_CRITICAL);
|
2022-02-02 20:34:50 +08:00
|
|
|
|
SDL_LogSetOutputFunction([](void *userdata, int category, SDL_LogPriority priority, const char *message) {
|
2018-04-17 21:38:13 +08:00
|
|
|
|
DebugL << category << " " << priority << message;
|
2022-02-02 20:34:50 +08:00
|
|
|
|
}, nullptr);
|
2018-04-17 21:38:13 +08:00
|
|
|
|
InfoL << "SDL_Init";
|
|
|
|
|
}, []() {
|
|
|
|
|
SDLDisplayerHelper::Destory();
|
|
|
|
|
SDL_Quit();
|
|
|
|
|
});
|
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
_title = title;
|
|
|
|
|
_hwnd = hwnd;
|
|
|
|
|
}
|
|
|
|
|
virtual ~YuvDisplayer(){
|
|
|
|
|
if (_texture) {
|
|
|
|
|
SDL_DestroyTexture(_texture);
|
|
|
|
|
_texture = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (_render) {
|
|
|
|
|
SDL_DestroyRenderer(_render);
|
|
|
|
|
_render = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if (_win) {
|
|
|
|
|
SDL_DestroyWindow(_win);
|
|
|
|
|
_win = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool displayYUV(AVFrame *pFrame){
|
|
|
|
|
if (!_win) {
|
|
|
|
|
if (_hwnd) {
|
|
|
|
|
_win = SDL_CreateWindowFrom(_hwnd);
|
|
|
|
|
}else {
|
|
|
|
|
_win = SDL_CreateWindow(_title.data(),
|
|
|
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
|
|
|
SDL_WINDOWPOS_UNDEFINED,
|
|
|
|
|
pFrame->width,
|
|
|
|
|
pFrame->height,
|
|
|
|
|
SDL_WINDOW_OPENGL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (_win && ! _render){
|
2018-04-17 21:38:13 +08:00
|
|
|
|
#if 0
|
2020-03-20 11:51:24 +08:00
|
|
|
|
SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */
|
2018-04-17 21:38:13 +08:00
|
|
|
|
SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware
|
|
|
|
|
acceleration */
|
|
|
|
|
SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized
|
|
|
|
|
with the refresh rate */
|
|
|
|
|
SDL_RENDERER_TARGETTEXTURE = 0x00000008 /**< The renderer supports
|
|
|
|
|
rendering to texture */
|
|
|
|
|
#endif
|
2018-04-17 21:47:31 +08:00
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
_render = SDL_CreateRenderer(_win, -1, SDL_RENDERER_ACCELERATED);
|
|
|
|
|
}
|
|
|
|
|
if (_render && !_texture) {
|
2021-09-08 20:06:28 +08:00
|
|
|
|
if (pFrame->format == AV_PIX_FMT_NV12) {
|
|
|
|
|
_texture = SDL_CreateTexture(
|
|
|
|
|
_render, SDL_PIXELFORMAT_NV12, SDL_TEXTUREACCESS_STREAMING, pFrame->width, pFrame->height);
|
|
|
|
|
} else {
|
|
|
|
|
_texture = SDL_CreateTexture(
|
|
|
|
|
_render, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pFrame->width, pFrame->height);
|
|
|
|
|
}
|
2020-03-20 11:51:24 +08:00
|
|
|
|
}
|
|
|
|
|
if (_texture) {
|
2022-07-18 22:30:28 +08:00
|
|
|
|
#if SDL_VERSION_ATLEAST(2,0,16)
|
2021-09-08 20:06:28 +08:00
|
|
|
|
//需要更新sdl到最新(>=2.0.16)
|
|
|
|
|
if (pFrame->format == AV_PIX_FMT_NV12) {
|
|
|
|
|
SDL_UpdateNVTexture(
|
|
|
|
|
_texture, nullptr, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1]);
|
2021-09-13 10:38:32 +08:00
|
|
|
|
} else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
2021-09-08 20:06:28 +08:00
|
|
|
|
SDL_UpdateYUVTexture(
|
2021-09-13 10:38:32 +08:00
|
|
|
|
_texture, nullptr, pFrame->data[0], pFrame->linesize[0], pFrame->data[1], pFrame->linesize[1],
|
|
|
|
|
pFrame->data[2], pFrame->linesize[2]);
|
2021-09-08 20:06:28 +08:00
|
|
|
|
}
|
2018-04-17 21:38:13 +08:00
|
|
|
|
|
2020-03-20 11:51:24 +08:00
|
|
|
|
//SDL_UpdateTexture(_texture, nullptr, pFrame->data[0], pFrame->linesize[0]);
|
|
|
|
|
SDL_RenderClear(_render);
|
|
|
|
|
SDL_RenderCopy(_render, _texture, nullptr, nullptr);
|
|
|
|
|
SDL_RenderPresent(_render);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-05-08 18:03:43 +08:00
|
|
|
|
private:
|
2022-02-02 20:34:50 +08:00
|
|
|
|
std::string _title;
|
2020-03-20 11:51:24 +08:00
|
|
|
|
SDL_Window *_win = nullptr;
|
|
|
|
|
SDL_Renderer *_render = nullptr;
|
|
|
|
|
SDL_Texture *_texture = nullptr;
|
|
|
|
|
void *_hwnd = nullptr;
|
2017-05-08 18:03:43 +08:00
|
|
|
|
};
|
|
|
|
|
|
2021-09-08 20:06:28 +08:00
|
|
|
|
#endif /* YUVDISPLAYER_H_ */
|