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

📄 sync.cpp

📁 网络MPEG4IP流媒体开发源代码
💻 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 *//* * sync.cpp - provide sync thread implementations of CPlayerSession */#include <stdlib.h>#include "player_session.h"#include "player_media.h"#include <SDL.h>#include <SDL_thread.h>#include "player_util.h"#include "audio.h"#include "video.h"#include "our_config_file.h"//#define DEBUG_SYNC_STATE 1//#define DEBUG_SYNC_MSGS 1//#define DEBUG_SYNC_SDL_EVENTS 1#ifdef _WIN32DEFINE_MESSAGE_MACRO(sync_message, "avsync")#else#define sync_message(loglevel, fmt...) message(loglevel, "avsync", fmt)#endif/* * Sync thread states.  General state machine looks like: * INIT -> WAIT_SYNC -> WAIT_AUDIO -> PLAYING -> DONE -> EXIT * PAUSE is entered when a PAUSE command is sent.  PAUSE exits into * WAIT_SYNC.  EXIT is entered when a QUIT command is received. */enum {  SYNC_STATE_INIT = 0,  SYNC_STATE_WAIT_SYNC = 1,  SYNC_STATE_WAIT_AUDIO = 2,  SYNC_STATE_PLAYING = 3,  SYNC_STATE_PAUSED = 4,  SYNC_STATE_DONE = 5,  SYNC_STATE_EXIT = 6,};#ifdef DEBUG_SYNC_STATEconst char *sync_state[] = {  "Init",  "Wait Sync",  "Wait Audio",  "Playing",  "Paused",  "Done",  "Exit"};#endif/* * process_sdl_events - process the sdl event queue.  This will allow the * video window to capture things like close, key strokes. */void CPlayerSession::process_sdl_events (void){  SDL_Event event;  while (SDL_PollEvent(&event) == 1) {    switch (event.type) {    case SDL_QUIT:      m_master_msg_queue->send_message(MSG_RECEIVED_QUIT,				       NULL, 				       0,				       m_master_msg_queue_sem);#ifdef DEBUG_SYNC_SDL_EVENTS      sync_message(LOG_DEBUG, "Quit event detected");#endif      break;    case SDL_KEYDOWN:#ifdef DEBUG_SYNC_SDL_EVENTS      sync_message(LOG_DEBUG, "Pressed %x %s", 		   event.key.keysym.mod, SDL_GetKeyName(event.key.keysym.sym));#endif      switch (event.key.keysym.sym) {      case SDLK_ESCAPE:	if (m_video_sync &&	    m_video_sync->get_fullscreen() != 0) {	  m_video_sync->set_fullscreen(0);	  m_video_sync->do_video_resize();	}	break;      case SDLK_RETURN:	if ((event.key.keysym.mod & (KMOD_LALT | KMOD_RALT)) != 0) {	  // alt-enter - full screen	  if (m_video_sync &&	      m_video_sync->get_fullscreen() == 0) {	    m_video_sync->set_fullscreen(1);	    m_video_sync->do_video_resize();	  }	}	break;      default:	break;      }      sdl_event_msg_t msg;      msg.mod = event.key.keysym.mod;      msg.sym = event.key.keysym.sym;      m_master_msg_queue->send_message(MSG_SDL_KEY_EVENT,				       (unsigned char *)&msg,				       sizeof(msg),				       m_master_msg_queue_sem);      break;    default:      break;    }  }}/* * process_msg_queue - receive messages for the sync task.  Most are * state changes. */int CPlayerSession::process_msg_queue (int state) {  CMsg *newmsg;  while ((newmsg = m_sync_thread_msg_queue.get_message()) != NULL) {#ifdef DEBUG_SYNC_MSGS    sync_message(LOG_DEBUG, "Sync thread msg %d", newmsg->get_value());#endif    switch (newmsg->get_value()) {    case MSG_PAUSE_SESSION:      state = SYNC_STATE_PAUSED;      break;    case MSG_START_SESSION:      state = SYNC_STATE_WAIT_SYNC;      break;    case MSG_STOP_THREAD:      state = SYNC_STATE_EXIT;      break;    case MSG_SYNC_RESIZE_SCREEN:      if (m_video_sync) {	m_video_sync->do_video_resize();      }      break;    default:      sync_message(LOG_ERR, "Sync thread received message %d", 		   newmsg->get_value());      break;    }    delete newmsg;    newmsg = NULL;  }  return (state);}/*************************************************************************** * Sync thread state handlers ***************************************************************************//* * sync_thread_init - wait until all the sync routines are initialized. */int CPlayerSession::sync_thread_init (void){  int ret = 1;  for (CPlayerMedia *mptr = m_my_media;       mptr != NULL && ret == 1;       mptr = mptr->get_next()) {    if (mptr->is_video()) {      ret = m_video_sync->initialize_video(m_session_name,					   m_screen_pos_x,					   m_screen_pos_y);    } else {      ret = m_audio_sync->initialize_audio(m_video_sync != NULL);    }  }  if (ret == -1) {    sync_message(LOG_CRIT, "Fatal error while initializing hardware");    if (m_video_sync != NULL) {      m_video_sync->flush_sync_buffers();    }    if (m_audio_sync != NULL) {      m_audio_sync->flush_sync_buffers();    }    m_master_msg_queue->send_message(MSG_RECEIVED_QUIT, 				     NULL, 				     0, 				     m_master_msg_queue_sem);    m_hardware_error = 1;    return (SYNC_STATE_DONE);  }	  if (ret == 1) {    return (SYNC_STATE_WAIT_SYNC);   }   CMsg *newmsg;  newmsg = m_sync_thread_msg_queue.get_message();  if (newmsg != NULL) {    int value = newmsg->get_value();    delete newmsg;    if (value == MSG_STOP_THREAD) {      return (SYNC_STATE_EXIT);    }    if (value == MSG_PAUSE_SESSION) {      m_sync_pause_done = 1;    }  }  SDL_Delay(100);	  return (SYNC_STATE_INIT);}/* * sync_thread_wait_sync - wait until all decoding threads have put * data into the sync classes. */int CPlayerSession::sync_thread_wait_sync (void){  int state;  state = process_msg_queue(SYNC_STATE_WAIT_SYNC);  if (state == SYNC_STATE_WAIT_SYNC) {            // We're not synced.  See if the video is ready, and if the audio      // is ready.  Then start them going...      int vsynced = 1, asynced = 1;      uint64_t astart, vstart;      if (m_video_sync) {	vsynced = m_video_sync->is_video_ready(vstart);      }       if (m_audio_sync) {	asynced = m_audio_sync->is_audio_ready(astart);       }      if (vsynced == 1 && asynced == 1) {	/*	 * Audio and video are synced. 	 */	if (m_audio_sync) {	  /* 	   * If we have audio, we use that for syncing.  Start it up	   */	  m_first_time_played = astart;	  m_current_time = astart;	  sync_message(LOG_DEBUG, "Astart is %llu", astart);	  m_waiting_for_audio = 1;	  state = SYNC_STATE_WAIT_AUDIO;	  m_audio_sync->play_audio();	} else 	if (m_video_sync) {	  /*	   * Video only - set up the start time based on the video time	   * returned	   */	  m_first_time_played = vstart;	  m_current_time = vstart;	  m_waiting_for_audio = 0;	  m_start = get_time_of_day();	  m_start -= m_current_time;	  state = SYNC_STATE_PLAYING;	}	sync_message(LOG_DEBUG, 		     "Resynced at time "LLU " "LLU, m_current_time, vstart);      } else {	SDL_Delay(10);      }    }  return (state);}/* * sync_thread_wait_audio - wait until the audio thread starts and signals * us. */int CPlayerSession::sync_thread_wait_audio (void){  int state;  state = process_msg_queue(SYNC_STATE_WAIT_AUDIO);  if (state == SYNC_STATE_WAIT_AUDIO) {    if (m_waiting_for_audio != 0) {      SDL_SemWaitTimeout(m_sync_sem, 10);    } else {      // make sure we set the current time      get_current_time();      sync_message(LOG_DEBUG, "Current time is %llu", m_current_time);      return (SYNC_STATE_PLAYING);    }  }  return (state);}/* * sync_thread_playing - do the work of displaying the video and making * sure we're in sync. */int CPlayerSession::sync_thread_playing (void) {  int state;  uint64_t audio_resync_time = 0;  int64_t video_status = 0;  int have_audio_eof = 0, have_video_eof = 0;  state = process_msg_queue(SYNC_STATE_PLAYING);  if (state == SYNC_STATE_PLAYING) {    get_current_time();    if (m_audio_sync) {      audio_resync_time = m_audio_sync->check_audio_sync(m_current_time, 							 have_audio_eof);    }    if (m_video_sync) {      video_status = m_video_sync->play_video_at(m_current_time, 						 have_video_eof);    }    int delay = 9;    int wait_for_signal = 0;    if (m_video_sync && m_audio_sync) {      if (have_video_eof && have_audio_eof) {	return (SYNC_STATE_DONE);      }      if (video_status > 0 || audio_resync_time != 0) {	if (audio_resync_time != 0) {	  int64_t diff = audio_resync_time - m_current_time;	  delay = (int)min(diff, video_status);	} else {	  if (video_status < 9) {	    delay = 0;	  }	}	if (delay < 9) {	  wait_for_signal = 0;	} else {	  wait_for_signal = 1;	}      } else {	wait_for_signal = 0;      }    } else if (m_video_sync) {      if (have_video_eof == 1) {	return (SYNC_STATE_DONE);      }       if (video_status >= 9) {	wait_for_signal = 1;	delay = (int)video_status;      } else {	wait_for_signal = 0;      }    } else {      // audio only      if (have_audio_eof == 1) {	return (SYNC_STATE_DONE);      }      if (audio_resync_time != 0) {	if (audio_resync_time - m_current_time > 10) {	  wait_for_signal = 1;	  delay = (int)(audio_resync_time - m_current_time);	} else {	  wait_for_signal = 0;	}      } else {	wait_for_signal = 1;      }    }    //player_debug_message("w %d d %d", wait_for_signal, delay);    if (wait_for_signal) {      if (delay > 9) {	delay = 9;      }      //player_debug_message("sw %d", delay);      SDL_SemWaitTimeout(m_sync_sem, delay);    }  }  return (state);}/* * sync_thread_pause - wait for messages to continue or finish */int CPlayerSession::sync_thread_paused (void){  int state;  state = process_msg_queue(SYNC_STATE_PAUSED);  if (state == SYNC_STATE_PAUSED) {    SDL_SemWaitTimeout(m_sync_sem, 10);  }  return (state);}/* * sync_thread_pause - wait for messages to exit, pretty much. */int CPlayerSession::sync_thread_done (void){  int state;  state = process_msg_queue(SYNC_STATE_DONE);  if (state == SYNC_STATE_DONE) {    SDL_SemWaitTimeout(m_sync_sem, 10);  }   return (state);}/* * sync_thread - call the correct handler, and wait for the state changes. * Each handler should only return the new state... */  int CPlayerSession::sync_thread (int state){  int newstate = 0;  process_sdl_events();  switch (state) {  case SYNC_STATE_INIT:    m_session_state = SESSION_BUFFERING;    newstate = sync_thread_init();    break;  case SYNC_STATE_WAIT_SYNC:    newstate = sync_thread_wait_sync();    break;  case SYNC_STATE_WAIT_AUDIO:    newstate = sync_thread_wait_audio();    break;  case SYNC_STATE_PLAYING:    newstate = sync_thread_playing();    break;  case SYNC_STATE_PAUSED:    newstate = sync_thread_paused();    break;  case SYNC_STATE_DONE:    newstate = sync_thread_done();    break;  }#ifdef DEBUG_SYNC_STATE  if (state != newstate)    sync_message(LOG_INFO, "sync changed state %s to %s", 		 sync_state[state], sync_state[newstate]);#endif  if (state != newstate) {    state = newstate;    switch (state) {    case SYNC_STATE_WAIT_SYNC:      m_session_state = SESSION_BUFFERING;      break;    case SYNC_STATE_WAIT_AUDIO:      break;    case SYNC_STATE_PLAYING:      m_session_state = SESSION_PLAYING;      break;    case SYNC_STATE_PAUSED:      if (m_video_sync != NULL) 	m_video_sync->flush_sync_buffers();      if (m_audio_sync != NULL) 	m_audio_sync->flush_sync_buffers();      m_session_state = SESSION_PAUSED;      m_sync_pause_done = 1;      break;    case SYNC_STATE_DONE:      if (m_video_sync && m_video_sync->get_fullscreen() != 0) {	m_video_sync->set_fullscreen(0);	m_video_sync->do_video_resize();      }      m_master_msg_queue->send_message(MSG_SESSION_FINISHED, 				       NULL, 				       0, 				       m_master_msg_queue_sem);      m_session_state = SESSION_DONE;      break;    case SYNC_STATE_EXIT:      if (m_video_sync != NULL) 	m_video_sync->flush_sync_buffers();      if (m_audio_sync != NULL) 	m_audio_sync->flush_sync_buffers();      break;    }  }  return (state);}int c_sync_thread (void *data){  CPlayerSession *p;  int state = SYNC_STATE_INIT;  p = (CPlayerSession *)data;  do {   state = p->sync_thread(state);  } while (state != SYNC_STATE_EXIT);  return (0);}/* end sync.cpp */

⌨️ 快捷键说明

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