/* * 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); }