📄 player_media_decode.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
*/
/*
* player_media_decode.cpp
* decode task thread for a CPlayerMedia
*/
#include "systems.h"
#include "player_session.h"
#include "player_media.h"
#include "player_sdp.h"
#include "player_util.h"
#include "media_utils.h"
#include "audio.h"
#include "video.h"
#include "rtp_bytestream.h"
#include "codec_plugin_private.h"
//#define DEBUG_DECODE 1
//#define DEBUG_DECODE_MSGS 1
/*
* start_decoding - API function to call for telling the decoding
* task it can start
*/
void CPlayerMedia::start_decoding (void)
{
m_decode_msg_queue.send_message(MSG_START_DECODING,
NULL,
0,
m_decode_thread_sem);
}
void CPlayerMedia::bytestream_primed (void)
{
if (m_decode_thread_waiting != 0) {
m_decode_thread_waiting = 0;
SDL_SemPost(m_decode_thread_sem);
}
}
void CPlayerMedia::wait_on_bytestream (void)
{
m_decode_thread_waiting = 1;
#ifdef DEBUG_DECODE
media_message(LOG_INFO, "decode thread %s waiting", m_media_info->media);
#endif
SDL_SemWait(m_decode_thread_sem);
m_decode_thread_waiting = 0;
}
/*
* parse_decode_message - handle messages to the decode task
*/
void CPlayerMedia::parse_decode_message (int &thread_stop, int &decoding)
{
CMsg *newmsg;
if ((newmsg = m_decode_msg_queue.get_message()) != NULL) {
#ifdef DEBUG_DECODE_MSGS
media_message(LOG_DEBUG, "decode thread message %d",newmsg->get_value());
#endif
switch (newmsg->get_value()) {
case MSG_STOP_THREAD:
thread_stop = 1;
break;
case MSG_PAUSE_SESSION:
decoding = 0;
if (m_video_sync != NULL) {
m_video_sync->flush_decode_buffers();
}
if (m_audio_sync != NULL) {
m_audio_sync->flush_decode_buffers();
}
break;
case MSG_START_DECODING:
if (m_video_sync != NULL) {
m_video_sync->flush_decode_buffers();
}
if (m_audio_sync != NULL) {
m_audio_sync->flush_decode_buffers();
}
decoding = 1;
break;
}
delete newmsg;
}
}
/*
* 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;
uint64_t ourtime;
// 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 bytes_decoded;
uint32_t frames_decoded_last_sec;
uint64_t bytes_decoded_last_sec;
uint64_t current_second;
uint32_t total_secs;
uint32_t last_div = 0;
total_secs = 0;
frames_decoded = 0;
bytes_decoded = 0;
frames_decoded_last_sec = 0;
bytes_decoded_last_sec = 0;
current_second = 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",
is_video() ? "video" : "audio");
#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
if (is_video()) {
if (m_video_sync == NULL) {
m_video_sync = m_parent->set_up_video_sync();
}
m_video_sync->set_wait_sem(m_decode_thread_sem);
} else {
if (m_audio_sync == NULL) {
m_audio_sync = m_parent->set_up_audio_sync();
}
m_audio_sync->set_wait_sem(m_decode_thread_sem);
}
if (m_plugin == NULL) {
if (is_video()) {
m_plugin = check_for_video_codec(NULL,
m_media_fmt,
-1,
-1,
m_user_data,
m_user_data_size);
if (m_plugin != NULL) {
m_plugin_data = (m_plugin->vc_create)(m_media_fmt,
m_video_info,
m_user_data,
m_user_data_size,
get_video_vft(),
m_video_sync);
if (m_plugin_data == NULL) {
m_plugin = NULL;
} else {
media_message(LOG_DEBUG, "Starting %s codec from decode thread",
m_plugin->c_name);
}
}
} else {
m_plugin = check_for_audio_codec(NULL,
m_media_fmt,
-1,
-1,
m_user_data,
m_user_data_size);
if (m_plugin != NULL) {
m_plugin_data = (m_plugin->ac_create)(m_media_fmt,
m_audio_info,
m_user_data,
m_user_data_size,
get_audio_vft(),
m_audio_sync);
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",
is_video() ? "video" : "audio");
#endif
frames_decoded_last_sec = 0;
bytes_decoded_last_sec = 0;
current_second = 0;
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);
continue;
}
if (m_byte_stream->eof()) {
media_message(LOG_INFO, "%s hit eof", m_is_video ? "video" : "audio");
if (m_audio_sync) m_audio_sync->set_eof();
if (m_video_sync) m_video_sync->set_eof();
decoding = 0;
continue;
}
if (m_byte_stream->have_no_data()) {
// Indicate that we're waiting, and wait for a message from RTP
// task.
wait_on_bytestream();
continue;
}
frame_buffer = NULL;
ourtime = m_byte_stream->start_next_frame(&frame_buffer,
&frame_len,
&ud);
/*
* If we're decoding video, see if we're playing - if so, check
* if we've fallen significantly behind the audio
*/
if (is_video() &&
(m_parent->get_session_state() == SESSION_PLAYING)) {
uint64_t current_time = m_parent->get_playing_time();
if (current_time >= ourtime) {
#ifdef DEBUG_DECODE
media_message(LOG_INFO, "Candidate for skip decode %llu our %llu",
current_time, ourtime);
#endif
// 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
do {
ret = m_byte_stream->skip_next_frame(&ourtime, &hassync,
&frame_buffer, &frame_len);
decode_skipped_frames++;
} while (ret != 0 &&
!m_byte_stream->eof() &&
current_time > ourtime);
if (m_byte_stream->eof() || ret == 0) continue;
#if 1
media_message(LOG_INFO, "Skipped ahead %llu to %llu",
current_time - 200, ourtime);
#endif
/*
* Ooh - fun - try to match to the next sync value - if not,
* 15 frames
*/
do {
ret = m_byte_stream->skip_next_frame(&ourtime, &hassync,
&frame_buffer, &frame_len);
if (hassync < 0) {
uint64_t diff = ourtime - current_time;
if (diff > (2 * C_LLU)) {
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 %llu",
count, hassync, ourtime);
#endif
}
}
}
#ifdef DEBUG_DECODE
media_message(LOG_DEBUG, "Decoding %c frame " LLU,
m_is_video ? 'v' : 'a', ourtime);
#endif
if (frame_buffer != NULL && frame_len != 0) {
int sync_frame;
ret = m_plugin->c_decode_frame(m_plugin_data,
ourtime,
m_streaming != 0,
&sync_frame,
frame_buffer,
frame_len,
ud);
#ifdef DEBUG_DECODE
media_message(LOG_DEBUG, "Decoding %c frame return %d",
m_is_video ? 'v' : 'a', ret);
#endif
if (ret > 0) {
frames_decoded++;
m_byte_stream->used_bytes_for_frame(ret);
bytes_decoded += ret;
last_div = ourtime % 1000;
if ((ourtime / 1000) > current_second) {
if (frames_decoded_last_sec != 0) {
#if 0
media_message(LOG_DEBUG, "%s - Second "LLU", frames %d bytes "LLU,
m_is_video ? "video" : "audio",
current_second,
frames_decoded_last_sec,
bytes_decoded_last_sec);
#endif
}
current_second = ourtime / 1000;
total_secs++;
frames_decoded_last_sec = 1;
bytes_decoded_last_sec = ret;
} else {
frames_decoded_last_sec++;
bytes_decoded_last_sec += ret;
}
} else {
m_byte_stream->used_bytes_for_frame(frame_len);
}
}
}
// calculate frame rate for session
}
if (m_is_video)
media_message(LOG_NOTICE, "Video decoder skipped %u frames",
decode_skipped_frames);
if (total_secs != 0) {
double fps, bps;
double secs;
secs = last_div;
secs /= 1000.0;
secs += total_secs;
fps = frames_decoded;
fps /= secs;
bps =
#ifdef _WIN32
(int64_t)
#endif
bytes_decoded;
bps *= 8.0 / secs;
media_message(LOG_NOTICE, "%s - bytes "LLU", seconds %g, fps %g bps "LLU,
m_is_video ? "video" : "audio",
bytes_decoded, secs,
fps, bytes_decoded * 8 / total_secs);
}
if (m_plugin) {
m_plugin->c_close(m_plugin_data);
m_plugin_data = NULL;
}
return (0);
}
/* end file player_media_decode.cpp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -