ZLMediaKit/player/YuvDisplayer.h

201 lines
6.3 KiB
C++
Raw Normal View History

 /*
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){
{
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){
2019-09-20 17:58:50 +08:00
case REFRESH_EVENT:{
{
std::lock_guard<std::mutex> lck(_mtxTask);
if (_taskList.empty()) {
2019-09-20 17:58:50 +08:00
//not reachable
continue;
}
task = _taskList.front();
_taskList.pop_front();
}
flag = task();
break;
case SDL_QUIT:
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
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"){
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);
SDL_LogSetOutputFunction([](void *userdata, int category, SDL_LogPriority priority, const char *message) {
2018-04-17 21:38:13 +08:00
DebugL << category << " " << priority << message;
}, 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) {
#if (SDL_PATCHLEVEL >= 16 || SDL_MINOR_VERSION > 0)
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]);
} else
#endif
{
2021-09-08 20:06:28 +08:00
SDL_UpdateYUVTexture(
_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:
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_ */