sync.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:13k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  *              Bill May        wmay@cisco.com
  20.  */
  21. /*
  22.  * sync.cpp - provide sync thread implementations of CPlayerSession
  23.  */
  24. #include <stdlib.h>
  25. #include "player_session.h"
  26. #include "player_media.h"
  27. #include <SDL.h>
  28. #include <SDL_thread.h>
  29. #include "player_util.h"
  30. #include "audio.h"
  31. #include "video.h"
  32. //#define DEBUG_SYNC_STATE 1
  33. //#define DEBUG_SYNC_MSGS 1
  34. //#define DEBUG_SYNC_SDL_EVENTS 1
  35. #ifdef _WIN32
  36. DEFINE_MESSAGE_MACRO(sync_message, "avsync")
  37. #else
  38. #define sync_message(loglevel, fmt...) message(loglevel, "avsync", fmt)
  39. #endif
  40. /*
  41.  * Sync thread states.  General state machine looks like:
  42.  * INIT -> WAIT_SYNC -> WAIT_AUDIO -> PLAYING -> DONE -> EXIT
  43.  * PAUSE is entered when a PAUSE command is sent.  PAUSE exits into
  44.  * WAIT_SYNC.  EXIT is entered when a QUIT command is received.
  45.  */
  46. enum {
  47.   SYNC_STATE_INIT = 0,
  48.   SYNC_STATE_WAIT_SYNC = 1,
  49.   SYNC_STATE_WAIT_AUDIO = 2,
  50.   SYNC_STATE_PLAYING = 3,
  51.   SYNC_STATE_PAUSED = 4,
  52.   SYNC_STATE_DONE = 5,
  53.   SYNC_STATE_EXIT = 6,
  54. };
  55. #ifdef DEBUG_SYNC_STATE
  56. const char *sync_state[] = {
  57.   "Init",
  58.   "Wait Sync",
  59.   "Wait Audio",
  60.   "Playing",
  61.   "Paused",
  62.   "Done",
  63.   "Exit"
  64. };
  65. #endif
  66. /*
  67.  * process_sdl_events - process the sdl event queue.  This will allow the
  68.  * video window to capture things like close, key strokes.
  69.  */
  70. void CPlayerSession::process_sdl_events (void)
  71. {
  72.   SDL_Event event;
  73.   while (SDL_PollEvent(&event) == 1) {
  74.     switch (event.type) {
  75.     case SDL_QUIT:
  76.       m_master_msg_queue->send_message(MSG_RECEIVED_QUIT,
  77.        NULL, 
  78.        0,
  79.        m_master_msg_queue_sem);
  80. #ifdef DEBUG_SYNC_SDL_EVENTS
  81.       sync_message(LOG_DEBUG, "Quit event detected");
  82. #endif
  83.       break;
  84.     case SDL_KEYDOWN:
  85. #ifdef DEBUG_SYNC_SDL_EVENTS
  86.       sync_message(LOG_DEBUG, "Pressed %x %s", 
  87.    event.key.keysym.mod, SDL_GetKeyName(event.key.keysym.sym));
  88. #endif
  89.       switch (event.key.keysym.sym) {
  90.       case SDLK_ESCAPE:
  91. if (m_video_sync &&
  92.     m_video_sync->get_fullscreen() != 0) {
  93.   m_video_sync->set_fullscreen(0);
  94.   m_video_sync->do_video_resize();
  95. }
  96. break;
  97.       case SDLK_RETURN:
  98. if ((event.key.keysym.mod & (KMOD_LALT | KMOD_RALT)) != 0) {
  99.   // alt-enter - full screen
  100.   if (m_video_sync &&
  101.       m_video_sync->get_fullscreen() == 0) {
  102.     m_video_sync->set_fullscreen(1);
  103.     m_video_sync->do_video_resize();
  104.   }
  105. }
  106. break;
  107.       default:
  108. break;
  109.       }
  110.       sdl_event_msg_t msg;
  111.       msg.mod = event.key.keysym.mod;
  112.       msg.sym = event.key.keysym.sym;
  113.       m_master_msg_queue->send_message(MSG_SDL_KEY_EVENT,
  114.        (unsigned char *)&msg,
  115.        sizeof(msg),
  116.        m_master_msg_queue_sem);
  117.       break;
  118.     default:
  119.       break;
  120.     }
  121.   }
  122. }
  123. /*
  124.  * process_msg_queue - receive messages for the sync task.  Most are
  125.  * state changes.
  126.  */
  127. int CPlayerSession::process_msg_queue (int state) 
  128. {
  129.   CMsg *newmsg;
  130.   while ((newmsg = m_sync_thread_msg_queue.get_message()) != NULL) {
  131. #ifdef DEBUG_SYNC_MSGS
  132.     sync_message(LOG_DEBUG, "Sync thread msg %d", newmsg->get_value());
  133. #endif
  134.     switch (newmsg->get_value()) {
  135.     case MSG_PAUSE_SESSION:
  136.       state = SYNC_STATE_PAUSED;
  137.       break;
  138.     case MSG_START_SESSION:
  139.       state = SYNC_STATE_WAIT_SYNC;
  140.       break;
  141.     case MSG_STOP_THREAD:
  142.       state = SYNC_STATE_EXIT;
  143.       break;
  144.     case MSG_SYNC_RESIZE_SCREEN:
  145.       if (m_video_sync) {
  146. m_video_sync->do_video_resize();
  147.       }
  148.       break;
  149.     default:
  150.       sync_message(LOG_ERR, "Sync thread received message %d", 
  151.    newmsg->get_value());
  152.       break;
  153.     }
  154.     delete newmsg;
  155.     newmsg = NULL;
  156.   }
  157.   return (state);
  158. }
  159. /***************************************************************************
  160.  * Sync thread state handlers
  161.  ***************************************************************************/
  162. /*
  163.  * sync_thread_init - wait until all the sync routines are initialized.
  164.  */
  165. int CPlayerSession::sync_thread_init (void)
  166. {
  167.   int ret = 1;
  168.   for (CPlayerMedia *mptr = m_my_media;
  169.        mptr != NULL && ret == 1;
  170.        mptr = mptr->get_next()) {
  171.     if (mptr->is_video()) {
  172.       ret = m_video_sync->initialize_video(m_session_name,
  173.    m_screen_pos_x,
  174.    m_screen_pos_y);
  175.     } else {
  176.       ret = m_audio_sync->initialize_audio(m_video_sync != NULL);
  177.     }
  178.   }
  179.   if (ret == -1) {
  180.     sync_message(LOG_CRIT, "Fatal error while initializing hardware");
  181.     if (m_video_sync != NULL) {
  182.       m_video_sync->flush_sync_buffers();
  183.     }
  184.     if (m_audio_sync != NULL) {
  185.       m_audio_sync->flush_sync_buffers();
  186.     }
  187.     m_master_msg_queue->send_message(MSG_RECEIVED_QUIT, 
  188.      NULL, 
  189.      0, 
  190.      m_master_msg_queue_sem);
  191.     m_hardware_error = 1;
  192.     return (SYNC_STATE_DONE);
  193.   }
  194.   if (ret == 1) {
  195.     return (SYNC_STATE_WAIT_SYNC); 
  196.   } 
  197.   CMsg *newmsg;
  198.   newmsg = m_sync_thread_msg_queue.get_message();
  199.   if (newmsg && newmsg->get_value() == MSG_STOP_THREAD) {
  200.     return (SYNC_STATE_EXIT);
  201.   }
  202.   if (newmsg && newmsg->get_value() == MSG_PAUSE_SESSION) {
  203.     m_sync_pause_done = 1;
  204.   }
  205.   SDL_Delay(100);
  206.   return (SYNC_STATE_INIT);
  207. }
  208. /*
  209.  * sync_thread_wait_sync - wait until all decoding threads have put
  210.  * data into the sync classes.
  211.  */
  212. int CPlayerSession::sync_thread_wait_sync (void)
  213. {
  214.   int state;
  215.   state = process_msg_queue(SYNC_STATE_WAIT_SYNC);
  216.   if (state == SYNC_STATE_WAIT_SYNC) {
  217.       
  218.       // We're not synced.  See if the video is ready, and if the audio
  219.       // is ready.  Then start them going...
  220.       int vsynced = 1, asynced = 1;
  221.       uint64_t astart, vstart;
  222.       if (m_video_sync) {
  223. vsynced = m_video_sync->is_video_ready(vstart);
  224.       } 
  225.       if (m_audio_sync) {
  226. asynced = m_audio_sync->is_audio_ready(astart); 
  227.       }
  228.       if (vsynced == 1 && asynced == 1) {
  229. /*
  230.  * Audio and video are synced. 
  231.  */
  232. if (m_audio_sync) {
  233.   /* 
  234.    * If we have audio, we use that for syncing.  Start it up
  235.    */
  236.   m_first_time_played = astart;
  237.   m_current_time = astart;
  238.   sync_message(LOG_DEBUG, "Astart is %llu", astart);
  239.   m_waiting_for_audio = 1;
  240.   state = SYNC_STATE_WAIT_AUDIO;
  241.   m_audio_sync->play_audio();
  242. } else  if (m_video_sync) {
  243.   /*
  244.    * Video only - set up the start time based on the video time
  245.    * returned
  246.    */
  247.   m_first_time_played = vstart;
  248.   m_current_time = vstart;
  249.   m_waiting_for_audio = 0;
  250.   m_start = get_time_of_day();
  251.   m_start -= m_current_time;
  252.   state = SYNC_STATE_PLAYING;
  253. }
  254. sync_message(LOG_DEBUG, 
  255.      "Resynced at time "LLU " "LLU, m_current_time, vstart);
  256.       } else {
  257. SDL_Delay(10);
  258.       }
  259.     }
  260.   return (state);
  261. }
  262. /*
  263.  * sync_thread_wait_audio - wait until the audio thread starts and signals
  264.  * us.
  265.  */
  266. int CPlayerSession::sync_thread_wait_audio (void)
  267. {
  268.   int state;
  269.   state = process_msg_queue(SYNC_STATE_WAIT_AUDIO);
  270.   if (state == SYNC_STATE_WAIT_AUDIO) {
  271.     if (m_waiting_for_audio != 0) {
  272.       SDL_SemWaitTimeout(m_sync_sem, 10);
  273.     } else {
  274.       // make sure we set the current time
  275.       get_current_time();
  276.       sync_message(LOG_DEBUG, "Current time is %llu", m_current_time);
  277.       return (SYNC_STATE_PLAYING);
  278.     }
  279.   }
  280.   return (state);
  281. }
  282. /*
  283.  * sync_thread_playing - do the work of displaying the video and making
  284.  * sure we're in sync.
  285.  */
  286. int CPlayerSession::sync_thread_playing (void) 
  287. {
  288.   int state;
  289.   uint64_t audio_resync_time = 0;
  290.   int64_t video_status = 0;
  291.   int have_audio_eof = 0, have_video_eof = 0;
  292.   state = process_msg_queue(SYNC_STATE_PLAYING);
  293.   if (state == SYNC_STATE_PLAYING) {
  294.     get_current_time();
  295.     if (m_audio_sync) {
  296.       audio_resync_time = m_audio_sync->check_audio_sync(m_current_time, 
  297.  have_audio_eof);
  298.     }
  299.     if (m_video_sync) {
  300.       video_status = m_video_sync->play_video_at(m_current_time, 
  301.  have_video_eof);
  302.     }
  303.     int delay = 9;
  304.     int wait_for_signal = 0;
  305.     if (m_video_sync && m_audio_sync) {
  306.       if (have_video_eof && have_audio_eof) {
  307. return (SYNC_STATE_DONE);
  308.       }
  309.       if (video_status > 0 || audio_resync_time != 0) {
  310. if (audio_resync_time != 0) {
  311.   int64_t diff = audio_resync_time - m_current_time;
  312.   delay = (int)min(diff, video_status);
  313. }
  314. if (delay < 9) {
  315.   wait_for_signal = 0;
  316. } else {
  317.   wait_for_signal = 1;
  318. }
  319.       } else {
  320. wait_for_signal = 0;
  321.       }
  322.     } else if (m_video_sync) {
  323.       if (have_video_eof == 1) {
  324. return (SYNC_STATE_DONE);
  325.       } 
  326.       if (video_status >= 9) {
  327. wait_for_signal = 1;
  328. delay = (int)video_status;
  329.       } else {
  330. wait_for_signal = 0;
  331.       }
  332.     } else {
  333.       // audio only
  334.       if (have_audio_eof == 1) {
  335. return (SYNC_STATE_DONE);
  336.       }
  337.       if (audio_resync_time != 0) {
  338. if (audio_resync_time - m_current_time > 10) {
  339.   wait_for_signal = 1;
  340.   delay = (int)(audio_resync_time - m_current_time);
  341. } else {
  342.   wait_for_signal = 0;
  343. }
  344.       } else {
  345. wait_for_signal = 1;
  346.       }
  347.     }
  348.     //player_debug_message("w %d d %d", wait_for_signal, delay);
  349.     if (wait_for_signal) {
  350.       if (delay > 9) {
  351. delay = 9;
  352.       }
  353.       //player_debug_message("sw %d", delay);
  354.       SDL_SemWaitTimeout(m_sync_sem, delay);
  355.     }
  356.   }
  357.   return (state);
  358. }
  359. /*
  360.  * sync_thread_pause - wait for messages to continue or finish
  361.  */
  362. int CPlayerSession::sync_thread_paused (void)
  363. {
  364.   int state;
  365.   state = process_msg_queue(SYNC_STATE_PAUSED);
  366.   if (state == SYNC_STATE_PAUSED) {
  367.     SDL_SemWaitTimeout(m_sync_sem, 10);
  368.   }
  369.   return (state);
  370. }
  371. /*
  372.  * sync_thread_pause - wait for messages to exit, pretty much.
  373.  */
  374. int CPlayerSession::sync_thread_done (void)
  375. {
  376.   int state;
  377.   state = process_msg_queue(SYNC_STATE_DONE);
  378.   if (state == SYNC_STATE_DONE) {
  379.     SDL_SemWaitTimeout(m_sync_sem, 10);
  380.   } 
  381.   return (state);
  382. }
  383. /*
  384.  * sync_thread - call the correct handler, and wait for the state changes.
  385.  * Each handler should only return the new state...
  386.  */  
  387. int CPlayerSession::sync_thread (int state)
  388. {
  389.   int newstate = 0;
  390.   process_sdl_events();
  391.   switch (state) {
  392.   case SYNC_STATE_INIT:
  393.     m_session_state = SESSION_BUFFERING;
  394.     newstate = sync_thread_init();
  395.     break;
  396.   case SYNC_STATE_WAIT_SYNC:
  397.     newstate = sync_thread_wait_sync();
  398.     break;
  399.   case SYNC_STATE_WAIT_AUDIO:
  400.     newstate = sync_thread_wait_audio();
  401.     break;
  402.   case SYNC_STATE_PLAYING:
  403.     newstate = sync_thread_playing();
  404.     break;
  405.   case SYNC_STATE_PAUSED:
  406.     newstate = sync_thread_paused();
  407.     break;
  408.   case SYNC_STATE_DONE:
  409.     newstate = sync_thread_done();
  410.     break;
  411.   }
  412. #ifdef DEBUG_SYNC_STATE
  413.   if (state != newstate)
  414.     sync_message(LOG_INFO, "sync changed state %s to %s", 
  415.  sync_state[state], sync_state[newstate]);
  416. #endif
  417.   if (state != newstate) {
  418.     state = newstate;
  419.     switch (state) {
  420.     case SYNC_STATE_WAIT_SYNC:
  421.       m_session_state = SESSION_BUFFERING;
  422.       break;
  423.     case SYNC_STATE_WAIT_AUDIO:
  424.       break;
  425.     case SYNC_STATE_PLAYING:
  426.       m_session_state = SESSION_PLAYING;
  427.       break;
  428.     case SYNC_STATE_PAUSED:
  429.       if (m_video_sync != NULL) 
  430. m_video_sync->flush_sync_buffers();
  431.       if (m_audio_sync != NULL) 
  432. m_audio_sync->flush_sync_buffers();
  433.       m_session_state = SESSION_PAUSED;
  434.       m_sync_pause_done = 1;
  435.       break;
  436.     case SYNC_STATE_DONE:
  437.       if (m_video_sync && m_video_sync->get_fullscreen() != 0) {
  438. m_video_sync->set_fullscreen(0);
  439. m_video_sync->do_video_resize();
  440.       }
  441.       m_master_msg_queue->send_message(MSG_SESSION_FINISHED, 
  442.        NULL, 
  443.        0, 
  444.        m_master_msg_queue_sem);
  445.       m_session_state = SESSION_DONE;
  446.       break;
  447.     case SYNC_STATE_EXIT:
  448.       if (m_video_sync != NULL) 
  449. m_video_sync->flush_sync_buffers();
  450.       if (m_audio_sync != NULL) 
  451. m_audio_sync->flush_sync_buffers();
  452.       break;
  453.     }
  454.   }
  455.   return (state);
  456. }
  457. int c_sync_thread (void *data)
  458. {
  459.   CPlayerSession *p;
  460.   int state = SYNC_STATE_INIT;
  461.   p = (CPlayerSession *)data;
  462.   do {
  463.    state = p->sync_thread(state);
  464.   } while (state != SYNC_STATE_EXIT);
  465.   return (0);
  466. }
  467. /* end sync.cpp */