245 lines
5.3 KiB
C++
245 lines
5.3 KiB
C++
/***************************************************************************************
|
|
*
|
|
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
|
*
|
|
* By downloading, copying, installing or using the software you agree to this license.
|
|
* If you do not agree to this license, do not download, install,
|
|
* copy or use the software.
|
|
*
|
|
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
|
|
*
|
|
* Redistribution and use in binary forms, with or without modification, are permitted.
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software distributed
|
|
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
|
|
* language governing permissions and limitations under the License.
|
|
*
|
|
****************************************************************************************/
|
|
|
|
#include "sys_inc.h"
|
|
#include "video_render_sdl.h"
|
|
#include "lock.h"
|
|
extern "C"
|
|
{
|
|
#include <libavutil/imgutils.h>
|
|
}
|
|
|
|
|
|
/***************************************************************************************/
|
|
|
|
static void * g_sdl_mutex = sys_os_create_mutex();
|
|
|
|
/***************************************************************************************/
|
|
|
|
CSDLVideoRender::CSDLVideoRender()
|
|
: CVideoRender()
|
|
, m_pWindow(NULL)
|
|
, m_pRenderer(NULL)
|
|
, m_pTexture(NULL)
|
|
{
|
|
}
|
|
|
|
CSDLVideoRender::~CSDLVideoRender()
|
|
{
|
|
unInit();
|
|
}
|
|
|
|
BOOL CSDLVideoRender::init(WId hWnd, int w, int h, int videofmt)
|
|
{
|
|
CVideoRender::init(hWnd, w, h, videofmt);
|
|
|
|
CLock lock(g_sdl_mutex);
|
|
|
|
m_bInited = initTexture();
|
|
|
|
return m_bInited;
|
|
}
|
|
|
|
void CSDLVideoRender::unInit()
|
|
{
|
|
CLock lock(g_sdl_mutex);
|
|
|
|
if (m_pTexture)
|
|
{
|
|
SDL_DestroyTexture(m_pTexture);
|
|
m_pTexture = NULL;
|
|
}
|
|
|
|
if (m_pRenderer)
|
|
{
|
|
SDL_DestroyRenderer(m_pRenderer);
|
|
m_pRenderer = NULL;
|
|
}
|
|
|
|
if (m_pWindow)
|
|
{
|
|
SDL_DestroyWindow(m_pWindow);
|
|
m_pWindow = NULL;
|
|
}
|
|
|
|
m_bInited = FALSE;
|
|
}
|
|
|
|
BOOL CSDLVideoRender::reInit(WId hWnd, int w, int h, int videofmt)
|
|
{
|
|
BOOL ret;
|
|
#ifdef IOS
|
|
char title[512] = {'\0'};
|
|
|
|
if (m_pWindow)
|
|
{
|
|
const char * p_title = SDL_GetWindowTitle(m_pWindow);
|
|
if (p_title)
|
|
{
|
|
strncpy(title, p_title, sizeof(title)-1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
unInit();
|
|
|
|
ret = init(m_hWnd, w, h, m_nVideoFmt);
|
|
|
|
#ifdef IOS
|
|
if (ret && m_pWindow)
|
|
{
|
|
SDL_SetWindowTitle(m_pWindow, title);
|
|
}
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL CSDLVideoRender::render(AVFrame * frame, int mode)
|
|
{
|
|
if (!m_bInited || NULL == frame)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return renderTexture(frame, mode);
|
|
}
|
|
|
|
BOOL CSDLVideoRender::initTexture()
|
|
{
|
|
#ifdef IOS
|
|
// On Mac platform, SDL does not support rendering videos on child windows
|
|
// and must be presented on a separate top-level window
|
|
m_pWindow = SDL_CreateWindow("", 0, 0, 400, 300, SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE);
|
|
#else
|
|
m_pWindow = SDL_CreateWindowFrom((void *)m_hWnd);
|
|
#endif
|
|
if (NULL == m_pWindow)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);
|
|
if (NULL == m_pRenderer)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_pTexture = SDL_CreateTexture(m_pRenderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, m_nVideoWidth, m_nVideoHeight);
|
|
if (NULL == m_pTexture)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
SDL_ShowWindow(m_pWindow);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CSDLVideoRender::renderTexture(AVFrame * frame, int mode)
|
|
{
|
|
int pitch;
|
|
uint8 * ptr;
|
|
uint8 * pixels;
|
|
AVFrame dstFrame;
|
|
|
|
if (m_nVideoWidth != frame->width || m_nVideoHeight != frame->height)
|
|
{
|
|
if (!reInit(m_hWnd, frame->width, frame->height, m_nVideoFmt))
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
m_nVideoWidth = frame->width;
|
|
m_nVideoHeight = frame->height;
|
|
}
|
|
|
|
memset(&dstFrame, 0, sizeof(AVFrame));
|
|
|
|
SDL_LockTexture(m_pTexture, NULL, (void **)&pixels, &pitch);
|
|
|
|
av_image_fill_arrays(dstFrame.data, dstFrame.linesize, pixels, AV_PIX_FMT_YUV420P, m_nVideoWidth, m_nVideoHeight, 1);
|
|
|
|
// swap UV plane
|
|
ptr = dstFrame.data[1];
|
|
dstFrame.data[1] = dstFrame.data[2];
|
|
dstFrame.data[2] = ptr;
|
|
|
|
av_image_copy(dstFrame.data, dstFrame.linesize, (const uint8_t**)frame->data, frame->linesize, AV_PIX_FMT_YUV420P, m_nVideoWidth, m_nVideoHeight);
|
|
|
|
SDL_UnlockTexture(m_pTexture);
|
|
|
|
SDL_RenderClear(m_pRenderer);
|
|
|
|
int w, h;
|
|
SDL_Rect rect;
|
|
|
|
SDL_GetRendererOutputSize(m_pRenderer, &w, &h);
|
|
|
|
if (mode == RENDER_MODE_KEEP)
|
|
{
|
|
double dw = w / (double) m_nVideoWidth;
|
|
double dh = h / (double) m_nVideoHeight;
|
|
double rate = (dw > dh) ? dh : dw;
|
|
|
|
int rw = (int)(m_nVideoWidth * rate);
|
|
int rh = (int)(m_nVideoHeight * rate);
|
|
|
|
rect.x = (w - rw) / 2;
|
|
rect.y = (h - rh) / 2;
|
|
rect.w = rw;
|
|
rect.h = rh;
|
|
}
|
|
else
|
|
{
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
rect.w = w;
|
|
rect.h = h;
|
|
}
|
|
|
|
SDL_RenderCopy(m_pRenderer, m_pTexture, NULL, &rect);
|
|
|
|
SDL_RenderPresent(m_pRenderer);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CSDLVideoRender::setWindowSize(QSize size)
|
|
{
|
|
reInit(m_hWnd, m_nVideoWidth, m_nVideoHeight, m_nVideoFmt);
|
|
}
|
|
|
|
void CSDLVideoRender::setWindowTitle(const char * title)
|
|
{
|
|
if (m_pWindow)
|
|
{
|
|
if (title)
|
|
{
|
|
SDL_SetWindowTitle(m_pWindow, title);
|
|
}
|
|
else
|
|
{
|
|
SDL_SetWindowTitle(m_pWindow, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
|