📄 video_sdl.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2000, 2001. All Rights Reserved. * * Contributor(s): * Bill May wmay@cisco.com * video aspect ratio by: * Peter Maersk-Moller peter@maersk-moller.net *//* * video.cpp - provides codec to video hardware class */#include <string.h>#include "player_session.h"#include "video_sdl.h"#include "player_util.h"#include <SDL_error.h>#include <SDL_syswm.h>//#define VIDEO_SYNC_PLAY 2//#define VIDEO_SYNC_FILL 1//#define SHORT_VIDEO 1//#define SWAP_UV 1#ifdef _WIN32// new hwsurface method doesn't work on windows.// If you have pre-directX 8.1 - you'll want to define OLD_SURFACE//#define OLD_SURFACE 1#endif#ifdef _WIN32DEFINE_MESSAGE_MACRO(video_message, "videosync")#else#define video_message(loglevel, fmt...) message(loglevel, "videosync", fmt)#endifCSDLVideoSync::CSDLVideoSync (CPlayerSession *psptr) : CVideoSync(psptr){ char buf[32]; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0 || !SDL_VideoDriverName(buf, 1)) { video_message(LOG_CRIT, "Could not init SDL video: %s", SDL_GetError()); } m_screen = NULL; m_image = NULL; m_video_initialized = 0; m_config_set = 0; m_have_data = 0; for (int ix = 0; ix < MAX_VIDEO_BUFFERS; ix++) { m_y_buffer[ix] = NULL; m_u_buffer[ix] = NULL; m_v_buffer[ix] = NULL; m_buffer_filled[ix] = 0; } m_play_index = m_fill_index = 0; m_decode_waiting = 0; m_dont_fill = 0; m_paused = 1; m_behind_frames = 0; m_total_frames = 0; m_behind_time = 0; m_behind_time_max = 0; m_skipped_render = 0; m_video_scale = 2; m_msec_per_frame = 0; m_consec_skipped = 0; m_fullscreen = 0; m_filled_frames = 0; m_double_width = 0; m_pixel_width = 0; m_pixel_height = 0; m_max_width = 0; m_max_height = 0;}CSDLVideoSync::~CSDLVideoSync (void){ if (m_fullscreen != 0) { m_fullscreen = 0; do_video_resize(); } if (m_image) { SDL_FreeYUVOverlay(m_image); m_image = NULL; } if (m_screen) { SDL_FreeSurface(m_screen); m_screen = NULL; } for (int ix = 0; ix < MAX_VIDEO_BUFFERS; ix++) { if (m_y_buffer[ix] != NULL) { free(m_y_buffer[ix]); m_y_buffer[ix] = NULL; } if (m_u_buffer[ix] != NULL) { free(m_u_buffer[ix]); m_u_buffer[ix] = NULL; } if (m_v_buffer[ix] != NULL) { free(m_v_buffer[ix]); m_v_buffer[ix] = NULL; } }}/* * CSDLVideoSync::config - routine for the codec to call to set up the * width, height and frame_rate of the video */void CSDLVideoSync::config (int w, int h){ m_width = w; m_height = h; for (int ix = 0; ix < MAX_VIDEO_BUFFERS; ix++) { m_y_buffer[ix] = (uint8_t *)malloc(w * h * sizeof(uint8_t)); m_u_buffer[ix] = (uint8_t *)malloc(w/2 * h/2 * sizeof(uint8_t)); m_v_buffer[ix] = (uint8_t *)malloc(w/2 * h/2 * sizeof(uint8_t)); m_buffer_filled[ix] = 0; } m_config_set = 1;}/* * CSDLVideoSync::initialize_video - Called from sync task to initialize * the video window */ int CSDLVideoSync::initialize_video (const char *name, int x, int y){ if (m_video_initialized == 0) { if (m_config_set) { const SDL_VideoInfo *video_info; video_info = SDL_GetVideoInfo(); switch (video_info->vfmt->BitsPerPixel) { case 16: case 32: m_video_bpp = video_info->vfmt->BitsPerPixel; break; default: m_video_bpp = 16; break; } SDL_ShowCursor(SDL_DISABLE); SDL_SysWMinfo info; SDL_VERSION(&info.version); int ret; ret = SDL_GetWMInfo(&info); // Oooh... fun... To scale the video, just pass the width and height // to this routine. (ie: m_width *2, m_height * 2).#ifdef OLD_SURFACE int mask = SDL_SWSURFACE | SDL_ASYNCBLIT | SDL_RESIZABLE;#else int mask = SDL_HWSURFACE | SDL_RESIZABLE;#endif int video_scale = m_video_scale; if (m_fullscreen != 0) { mask |= SDL_FULLSCREEN;#ifdef _WIN32 video_scale = 2;#endif } int w = m_width * video_scale / 2; if (m_double_width) w *= 2; int h = m_height * video_scale / 2; m_screen = SDL_SetVideoMode(w, h, m_video_bpp, mask); if (ret > 0) {#ifdef unix // player_debug_message("Trying"); if (info.subsystem == SDL_SYSWM_X11) { info.info.x11.lock_func(); XMoveWindow(info.info.x11.display, info.info.x11.wmwindow, x, y); info.info.x11.unlock_func(); }#endif } SDL_WM_SetCaption(name, NULL); m_dstrect.x = 0; m_dstrect.y = 0; m_dstrect.w = m_screen->w; m_dstrect.h = m_screen->h;#if 1 video_message(LOG_DEBUG, "Created mscreen %p hxw %d %d", m_screen, m_height, m_width);#endif do_video_resize();#ifdef OLD_SURFACE if (video_scale == 4) { m_image = SDL_CreateYUVOverlay(m_width << 1, m_height << 1, SDL_YV12_OVERLAY, m_screen); } else {#else {#endif m_image = SDL_CreateYUVOverlay(m_width, m_height, SDL_YV12_OVERLAY, m_screen); } m_video_initialized = 1; return (1); } else { return (0); } } return (1);}/* * CSDLVideoSync::is_video_ready - called from sync task to determine if * we have sufficient number of buffers stored up to start displaying */int CSDLVideoSync::is_video_ready (uint64_t &disptime){ disptime = m_play_this_at[m_play_index]; if (m_dont_fill) { return 0; }#ifdef SHORT_VIDEO return (m_buffer_filled[m_play_index] == 1);#else return (m_buffer_filled[(m_play_index + 2*MAX_VIDEO_BUFFERS/3) % MAX_VIDEO_BUFFERS] == 1);#endif}void CSDLVideoSync::play_video (void) {}/* * CSDLVideoSync::play_video_at - called from sync task to show the next * video frame (if the timing is right */int64_t CSDLVideoSync::play_video_at (uint64_t current_time, int &have_eof){ uint64_t play_this_at; unsigned int ix; uint8_t *to, *from; /* * If the next buffer is not filled, indicate that, as well */ if (m_buffer_filled[m_play_index] == 0) { /* * If we have end of file, indicate it */ if (m_eof_found != 0) { have_eof = 1; return (-1); } return 10; } /* * we have a buffer. If it is in the future, don't play it now */ play_this_at = m_play_this_at[m_play_index]; if (play_this_at > current_time) { return (play_this_at - current_time); }#if VIDEO_SYNC_PLAY video_message(LOG_DEBUG, "play "LLU" at "LLU " %d", play_this_at, current_time, m_play_index);#endif /* * If we're behind - see if we should just skip it */ if (play_this_at < current_time) { m_behind_frames++; uint64_t behind = current_time - play_this_at; m_behind_time += behind; if (behind > m_behind_time_max) m_behind_time_max = behind;#if 0 if ((m_behind_frames % 64) == 0) { video_message(LOG_DEBUG, "behind "LLU" avg "LLU" max "LLU, behind, m_behind_time / m_behind_frames, m_behind_time_max); }#endif } m_paused = 0; /* * If we're within 1/2 of the frame time, go ahead and display * this frame */#define CHECK_SYNC_TIME 1#ifdef CHECK_SYNC_TIME int showed = 0; if ((m_msec_per_frame == 0) || ((play_this_at + m_msec_per_frame) > current_time) || (m_consec_skipped > 10)) {#else {#endif showed = 1; m_consec_skipped = 0; if (SDL_LockYUVOverlay(m_image)) { video_message(LOG_ERR, "Failed to lock image"); } else { // Must always copy the buffer to memory. This creates 2 copies of this // data (probably a total of 6 - libsock -> rtp -> decoder -> our ring -> // sdl -> hardware)#ifdef OLD_SURFACE if (m_fullscreen == 0 && m_video_scale == 4) { // when scaling to 200%, don't use SDL stretch blit // use a smoothing (averaging) blit instead#ifdef USE_MMX FrameDoublerMmx(m_y_buffer[m_play_index], m_image->pixels[0], m_width, m_height); FrameDoublerMmx(m_v_buffer[m_play_index], m_image->pixels[1], m_width >> 1, m_height >> 1); FrameDoublerMmx(m_u_buffer[m_play_index], m_image->pixels[2], m_width >> 1, m_height >> 1);#else FrameDoubler(m_y_buffer[m_play_index], m_image->pixels[0], m_width, m_height, m_image->pitches[0]); FrameDoubler(m_v_buffer[m_play_index], m_image->pixels[1], m_width >> 1, m_height >> 1, m_image->pitches[1]); FrameDoubler(m_u_buffer[m_play_index], m_image->pixels[2], m_width >> 1, m_height >> 1, m_image->pitches[2]);#endif } else #endif { // let SDL blit, either 1:1 for 100% or decimating by 2:1 for 50% uint32_t bufsize = m_width * m_height * sizeof(uint8_t); unsigned int width = m_width, height = m_height; if (width != m_image->pitches[0]) { to = (uint8_t *)m_image->pixels[0]; from = m_y_buffer[m_play_index]; for (ix = 0; ix < height; ix++) { memcpy(to, from, width); to += m_image->pitches[0]; from += width; } } else { memcpy(m_image->pixels[0], m_y_buffer[m_play_index], bufsize); } bufsize /= 4; width /= 2; height /= 2;#ifdef SWAP_UV#define V 2#define U 1#else#define V 1#define U 2#endif if (width != m_image->pitches[V]) { to = (uint8_t *)m_image->pixels[V]; from = m_v_buffer[m_play_index]; for (ix = 0; ix < height; ix++) { memcpy(to, from, width); to += m_image->pitches[V]; from += width; } } else { memcpy(m_image->pixels[V], m_v_buffer[m_play_index], bufsize); } if (width != m_image->pitches[U]) { to = (uint8_t *)m_image->pixels[U]; from = m_u_buffer[m_play_index]; for (ix = 0; ix < height; ix++) { memcpy(to, from, width); to += m_image->pitches[U]; from += width; } } else { memcpy(m_image->pixels[U], m_u_buffer[m_play_index], bufsize); } } int rval = SDL_DisplayYUVOverlay(m_image, &m_dstrect); if (rval != 0) { video_message(LOG_ERR, "Return from display is %d", rval); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -