📄 sync.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-2005. 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 "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_AUDIO_RESYNC = 5, SYNC_STATE_DONE = 6, SYNC_STATE_EXIT = 7, SYNC_STATE_WAIT_AUDIO_READY = 8, SYNC_STATE_WAIT_TIMED_INIT = 9};#ifdef DEBUG_SYNC_STATEconst char *sync_state[] = { "Init", "Wait Sync", "Wait Audio", "Playing", "Paused", "Audio Resync", "Done", "Exit", "Wait Audio Ready", "Wait Timed Init",};#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; CVideoSync *vs; while (SDL_PollEvent(&event) == 1) { switch (event.type) { case SDL_QUIT: m_master_msg_queue->send_message(MSG_RECEIVED_QUIT, 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: vs = m_video_list; while (vs != NULL) { if (vs->get_fullscreen() != 0) { vs->set_fullscreen(0); vs->do_video_resize(); } vs = vs->GetNextVideo(); } break; case SDLK_RETURN: if ((event.key.keysym.mod & (KMOD_ALT | KMOD_META)) != 0) { // alt-enter - full screen if (m_video_list && m_video_count == 1 && m_video_list->get_fullscreen() == 0) { m_video_list->set_fullscreen(1); m_video_list->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; case SDL_MOUSEBUTTONUP: if (event.button.which == 0 && m_mouse_click_callback != NULL) { (m_mouse_click_callback)(m_mouse_click_callback_ud, event.button.x, event.button.y); } else { sdl_mouse_msg_t mouse_msg; mouse_msg.button = event.button.which; mouse_msg.x = event.button.x; mouse_msg.y = event.button.y; m_master_msg_queue->send_message(MSG_SDL_MOUSE_EVENT, (uint8_t *)&mouse_msg, sizeof(mouse_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: switch (state) { case SYNC_STATE_INIT: case SYNC_STATE_WAIT_AUDIO_READY: case SYNC_STATE_WAIT_TIMED_INIT: break; default: state = SYNC_STATE_WAIT_SYNC; break; } break; case MSG_STOP_THREAD: state = SYNC_STATE_EXIT; break; case MSG_SYNC_RESIZE_SCREEN: { CVideoSync *vs = m_video_list; while (vs != NULL) { vs->set_screen_size(m_screen_scale); if (m_video_count == 1) { vs->set_fullscreen(m_fullscreen); } vs->do_video_resize(m_pixel_width, m_pixel_height, m_max_width, m_max_height); vs = vs->GetNextVideo(); } } 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 ***************************************************************************/bool CPlayerSession::initialize_timed_sync (uint &failed, bool &any_inited){ CTimedSync *ts; bool all_initialized = true; any_inited = false; int ret; for (ts = m_timed_sync_list; ts != NULL; ts = ts->GetNext()) { //sync_message(LOG_DEBUG, "sync %s %d", ts->GetName(), ts->is_initialized()); if (ts->is_initialized() == false) { if (ts->get_sync_type() == VIDEO_SYNC) { CVideoSync *vs = (CVideoSync *)ts; vs->set_screen_size(m_screen_scale); if (m_video_count == 1) { vs->set_fullscreen(m_fullscreen); } } ret = ts->initialize(m_session_name); //sync_message(LOG_DEBUG, "sync %s init %d", ts->GetName(), ret); if (ret <= 0) { all_initialized = false; if (ts->get_sync_type() == VIDEO_SYNC) { failed |= 2; } else { failed |= 4; } } else any_inited = true; } else any_inited = true; } return all_initialized;}/* * sync_thread_init - wait until all the sync routines are initialized. */int CPlayerSession::sync_thread_init (void){ int ret = 1; uint failed = 0; CTimedSync *ts; bool all_timed_inited, audio_inited = false, any_timed_inited; if (m_audio_sync != NULL) { ret = m_audio_sync->initialize_audio(m_timed_sync_list != NULL); if (ret <= 0) { //sync_message(LOG_DEBUG, "audio sync failed init"); audio_inited = false; failed |= 1; } else { audio_inited = true; //sync_message(LOG_DEBUG, "audio sync init"); if (config.GetBoolValue(CONFIG_SHORT_VIDEO_RENDER)) return (SYNC_STATE_WAIT_AUDIO_READY); } } all_timed_inited = initialize_timed_sync(failed, any_timed_inited); if ((m_audio_sync == NULL || audio_inited) && all_timed_inited) { return (SYNC_STATE_WAIT_SYNC); } if ((m_audio_sync != NULL && audio_inited) || any_timed_inited) { m_init_tries_made_with_media++; if (m_init_tries_made_with_media > 5 * 100) { sync_message(LOG_CRIT, "One media is not initializing; it might not be receiving correctly"); if ((failed & 0x2) != 0 ) { sync_message(LOG_INFO, "video failed"); } if ((failed & 0x4) != 0 ) { sync_message(LOG_INFO, "timed text failed"); } if ((failed & 0x1) != 0 ) { sync_message(LOG_INFO, "audio failed"); } ret = -1; } } else { uint64_t nowtime = get_time_of_day(); uint64_t difftime = nowtime - m_init_time; m_init_tries_made_with_no_media++; if ( difftime > TO_U64(30 * 1000)) { sync_message(LOG_CRIT, "No media has been initialized or received"); ret = -1; } } if (ret == -1) { sync_message(LOG_CRIT, "Fatal error while initializing hardware"); ts = m_timed_sync_list; while (ts != NULL) { ts->flush_sync_buffers(); ts = ts->GetNext(); } if (m_audio_sync != NULL) { m_audio_sync->flush_sync_buffers(); } m_master_msg_queue->send_message(MSG_RECEIVED_QUIT, m_master_msg_queue_sem); m_hardware_error = 1; return (SYNC_STATE_DONE); } 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_SemWaitTimeout(m_sync_sem, 10); 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... bool vsynced = true; int asynced = 1; uint64_t astart = 0, vstart = MAX_UINT64; for (CTimedSync *ts = m_timed_sync_list; ts != NULL; ts = ts->GetNext()) { uint64_t cmp; if (ts->active_at_start()) { if (ts->is_ready(cmp)) { vstart = MIN(cmp, vstart); } else { vsynced = false; } } } if (m_audio_sync) { asynced = m_audio_sync->is_audio_ready(astart); } if (vsynced && 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 "U64, astart); if (m_timed_sync_list) sync_message(LOG_DEBUG, "Vstart is "U64, vstart); m_waiting_for_audio = 1; state = SYNC_STATE_WAIT_AUDIO; m_audio_sync->play_audio(); } else if (m_timed_sync_list) { /* * 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 "U64 " "U64, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -