Пример #1
0
/*
 * rtp_check_payload - this is called after receiving packets, but before a
 * m_rtp_byte_stream is selected.
 */
void CPlayerMedia::rtp_check_payload (void)
{
  // note wmay - 3/16/2005 - need to push in text here.
  // we'll only every allow 1 type to be read, so we'll be able to
  // set up the interface directly.
  bool try_bytestream_buffering = false;

  if (get_sync_type() == TIMED_TEXT_SYNC) {
    determine_payload_type_from_rtp();
    // set the buffer time to 0, so we can pass buffering immediately
    m_rtp_byte_stream->set_rtp_buffer_time(0);
    try_bytestream_buffering = true;
  } else {
    if (m_head != NULL) {
      /*
       * Make sure that the payload type is the same
       */
      if (m_head->rtp_pak_pt == m_tail->rtp_pak_pt) {
	// we either want only 1 possible protocol, or at least
	// 10 packets of the same consecutively.  10 is arbitrary.
	if (m_media_info->fmt_list->next == NULL || 
	    m_rtp_queue_len > 10) { 
	  if (determine_payload_type_from_rtp() == FALSE) {
	    clear_rtp_packets(); 
	  } else {
	    // call this function again so we begin the buffering check
	    // right away - better than a go-to.
	    try_bytestream_buffering = true;
	  }
	}
      } else {
	clear_rtp_packets();
      }
    }
  }
  // if we've set the rtp bytestream, immediately try and see if they are done
  // buffering;  if so, start the decode task moving.
  if (try_bytestream_buffering) {
    if (m_rtp_byte_stream->check_buffering() != 0) {
      m_rtp_buffering = 1;
      start_decoding();
    }
  }
}
/*
 * Main decode thread.
 */
int CPlayerMedia::decode_thread (void) 
{
  //  uint32_t msec_per_frame = 0;
  int ret = 0;
  int thread_stop = 0, decoding = 0;
  uint32_t decode_skipped_frames = 0;
  frame_timestamp_t ourtime, lasttime;
      // Tell bytestream we're starting the next frame - they'll give us
      // the time.
  uint8_t *frame_buffer;
  uint32_t frame_len;
  void *ud = NULL;
  
  uint32_t frames_decoded;
  uint64_t start_decode_time = 0;
  uint64_t last_decode_time = 0;
  bool have_start_time = false;
  bool have_frame_ts = false;
  bool found_out_of_range_ts = false;
  uint64_t bytes_decoded;

  lasttime.msec_timestamp = 0;
  frames_decoded = 0;
  bytes_decoded = 0;


  while (thread_stop == 0) {
    // waiting here for decoding or thread stop
    ret = SDL_SemWait(m_decode_thread_sem);
#ifdef DEBUG_DECODE
    media_message(LOG_DEBUG, "%s Decode thread awake",
		  get_name());
#endif
    parse_decode_message(thread_stop, decoding);

    if (decoding == 1) {
      // We've been told to start decoding - if we don't have a codec, 
      // create one
      m_sync->set_wait_sem(m_decode_thread_sem);
      if (m_plugin == NULL) {
	switch (m_sync_type) {
	case VIDEO_SYNC:
	  create_video_plugin(NULL, 
			      STREAM_TYPE_RTP,
			      NULL,
			      -1,
			      -1,
			      m_media_fmt,
			      NULL,
			      m_user_data,
			      m_user_data_size);
	  break;
	case AUDIO_SYNC:
	  create_audio_plugin(NULL,
			      STREAM_TYPE_RTP,
			      NULL,
			      -1, 
			      -1, 
			      m_media_fmt,
			      NULL,
			      m_user_data,
			      m_user_data_size);
	  break;
	case TIMED_TEXT_SYNC:
	  create_text_plugin(NULL,
			     STREAM_TYPE_RTP, 
			     NULL, 
			     m_media_fmt, 
			     m_user_data, 
			     m_user_data_size);
	  break;
	}
	if (m_plugin_data == NULL) {
	  m_plugin = NULL;
	} else {
	  media_message(LOG_DEBUG, "Starting %s codec from decode thread",
			m_plugin->c_name);
	}
      }
      if (m_plugin != NULL) {
	m_plugin->c_do_pause(m_plugin_data);
      } else {
	while (thread_stop == 0 && decoding) {
	  SDL_Delay(100);
	  if (m_rtp_byte_stream) {
	    m_rtp_byte_stream->flush_rtp_packets();
	  }
	  parse_decode_message(thread_stop, decoding);
	}
      }
    }
    /*
     * this is our main decode loop
     */
#ifdef DEBUG_DECODE
    media_message(LOG_DEBUG, "%s Into decode loop", get_name());
#endif
    while ((thread_stop == 0) && decoding) {
      parse_decode_message(thread_stop, decoding);
      if (thread_stop != 0)
	continue;
      if (decoding == 0) {
	m_plugin->c_do_pause(m_plugin_data);
	have_frame_ts = false;
	continue;
      }
      if (m_byte_stream->eof()) {
	media_message(LOG_INFO, "%s hit eof", get_name());
	if (m_sync) m_sync->set_eof();
	decoding = 0;
	continue;
      }
      if (m_byte_stream->have_frame() == false) {
	// Indicate that we're waiting, and wait for a message from RTP
	// task.
	wait_on_bytestream();
	continue;
      }

      frame_buffer = NULL;
      bool have_frame;
      memset(&ourtime, 0, sizeof(ourtime));
      have_frame = m_byte_stream->start_next_frame(&frame_buffer, 
						   &frame_len,
						   &ourtime,
						   &ud);
      if (have_frame == false) continue;
      /*
       * If we're decoding video, see if we're playing - if so, check
       * if we've fallen significantly behind the audio
       */
      if (get_sync_type() == VIDEO_SYNC &&
	  (m_parent->get_session_state() == SESSION_PLAYING) &&
	  have_frame_ts) {
	int64_t ts_diff = ourtime.msec_timestamp - lasttime.msec_timestamp;

	if (ts_diff > TO_D64(1000) ||
	    ts_diff < TO_D64(-1000)) {
	  // out of range timestamp - we'll want to not skip here
	  found_out_of_range_ts = true;
	  media_message(LOG_INFO, "found out of range ts "U64" last "U64" "D64,
			ourtime.msec_timestamp, 
			lasttime.msec_timestamp,
			ts_diff);
	} else {
	  uint64_t current_time = m_parent->get_playing_time();
	  if (found_out_of_range_ts) {
	    ts_diff = current_time - ourtime.msec_timestamp;
	    if (ts_diff > TO_D64(0) && ts_diff < TO_D64(5000)) {
	      found_out_of_range_ts = false;
	      media_message(LOG_INFO, 
			    "ts back in playing range "U64" "D64,
			    ourtime.msec_timestamp, ts_diff);
	    }
	  } else {
	    // regular time
	    if (current_time >= ourtime.msec_timestamp) {
	      media_message(LOG_INFO, 
			    "Candidate for skip decode "U64" our "U64, 
			    current_time, ourtime.msec_timestamp);
	      // If the bytestream can skip ahead, let's do so
	      if (m_byte_stream->can_skip_frame() != 0) {
		int ret;
		int hassync;
		int count;
		current_time += 200; 
		count = 0;
		// Skip up to the current time + 200 msec
		ud = NULL;
		do {
		  if (ud != NULL) free(ud);
		  frame_buffer = NULL;
		  ret = m_byte_stream->skip_next_frame(&ourtime, 
						       &hassync,
						       &frame_buffer, 
						       &frame_len,
						       &ud);
		  decode_skipped_frames++;
		} while (ret != 0 &&
			 !m_byte_stream->eof() && 
			 current_time > ourtime.msec_timestamp);
		if (m_byte_stream->eof() || ret == 0) continue;
		media_message(LOG_INFO, "Skipped ahead "U64 " to "U64, 
			      current_time - 200, ourtime.msec_timestamp);
		/*
		 * Ooh - fun - try to match to the next sync value - if not, 
		 * 15 frames
		 */
		do {
		  if (ud != NULL) free(ud);
		  ret = m_byte_stream->skip_next_frame(&ourtime, 
						       &hassync,
						       &frame_buffer, 
						       &frame_len,
						       &ud);
		  if (hassync < 0) {
		    uint64_t diff = ourtime.msec_timestamp - current_time;
		    if (diff > TO_U64(200)) {
		      hassync = 1;
		    }
		  }
		  decode_skipped_frames++;
		  count++;
		} while (ret != 0 &&
			 hassync <= 0 &&
			 count < 30 &&
			 !m_byte_stream->eof());
		if (m_byte_stream->eof() || ret == 0) continue;
#ifdef DEBUG_DECODE
		media_message(LOG_INFO, 
			      "Matched ahead - count %d, sync %d time "U64,
			      count, hassync, ourtime.msec_timestamp);
#endif
	      }
	    }
	  } // end regular time
	}
      }
      lasttime = ourtime;
      have_frame_ts = true;
#ifdef DEBUG_DECODE
      media_message(LOG_DEBUG, "Decoding %s frame " U64, get_name(),
		    ourtime.msec_timestamp);
#endif
      if (frame_buffer != NULL && frame_len != 0) {
	int sync_frame;
	ret = m_plugin->c_decode_frame(m_plugin_data,
				       &ourtime,
				       m_streaming,
				       &sync_frame,
				       frame_buffer, 
				       frame_len,
				       ud);
#ifdef DEBUG_DECODE
	media_message(LOG_DEBUG, "Decoding %s frame return %d", 
		      get_name(), ret);
#endif
	if (ret > 0) {
	  frames_decoded++;
	  if (have_start_time == false) {
	    have_start_time = true;
	    start_decode_time = ourtime.msec_timestamp;
	  }
	  last_decode_time = ourtime.msec_timestamp;
	  m_byte_stream->used_bytes_for_frame(ret);
	  bytes_decoded += ret;
	} else {
	  m_byte_stream->used_bytes_for_frame(frame_len);
	}

      }
    }
    // calculate frame rate for session
  }
  if (is_audio() == false)
    media_message(LOG_NOTICE, "Video decoder skipped %u frames", 
		  decode_skipped_frames);
  if (last_decode_time > start_decode_time) {
    double fps, bps;
    double secs;
    uint64_t total_time = last_decode_time - start_decode_time;
    secs = UINT64_TO_DOUBLE(total_time);
    secs /= 1000.0;
#if 0
    media_message(LOG_DEBUG, "last time "U64" first "U64, 
		  last_decode_time, start_decode_time);
#endif
    fps = frames_decoded;
    fps /= secs;
    bps = UINT64_TO_DOUBLE(bytes_decoded);
    bps *= 8.0 / secs;
    media_message(LOG_NOTICE, "%s - bytes "U64", seconds %g, fps %g bps %g",
		  get_name(),
		  bytes_decoded, secs, 
		  fps, bps);
  }
  if (m_plugin) {
    m_plugin->c_close(m_plugin_data);
    m_plugin_data = NULL;
  }
  return (0);
}