⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video_sdl.cpp

📁 jpeg and mpeg 编解码技术源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 * 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.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 _WIN32
DEFINE_MESSAGE_MACRO(video_message, "videosync")
#else
#define video_message(loglevel, fmt...) message(loglevel, "videosync", fmt)
#endif

CSDLVideoSync::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;
}

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;
      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
#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 {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -