📄 player_media.cpp
字号:
if (strncasecmp(transport,
transport_types[ix].name,
transport_types[ix].namelen - 1) == 0) {
transport += transport_types[ix].namelen - 1;
ADV_SPACE(transport);
transport = (transport_types[ix].routine)(transport, this);
break;
}
}
if (transport_types[ix].name == NULL) {
media_message(LOG_INFO, "Illegal mime type in transport - skipping %s",
transport);
while (*transport != ';' && *transport != '\0') transport++;
if (*transport != '\0') transport++;
}
} while (transport != NULL && *transport != '\0');
if (transport == NULL) {
return (-1);
}
return (0);
}
struct {
const char *name;
uint32_t namelen;
char *(*routine)(char *transport, CPlayerMedia *, int &end_for_url);
} rtpinfo_types[] =
{
TTYPE("seq", rtpinfo_parse_seq),
TTYPE("rtptime", rtpinfo_parse_rtptime),
TTYPE("ssrc", rtpinfo_parse_ssrc),
{NULL, 0, NULL},
};
int process_rtsp_rtpinfo (char *rtpinfo,
CPlayerSession *session,
CPlayerMedia *media)
{
int ix;
CPlayerMedia *newmedia;
if (rtpinfo == NULL)
return (0);
do {
int no_mimes = 0;
ADV_SPACE(rtpinfo);
if (strncasecmp(rtpinfo, "url", strlen("url")) != 0) {
media_message(LOG_ERR, "Url not found");
return (-1);
}
rtpinfo += strlen("url");
ADV_SPACE(rtpinfo);
if (*rtpinfo != '=') {
media_message(LOG_ERR, "Can't find = after url");
return (-1);
}
rtpinfo++;
ADV_SPACE(rtpinfo);
char *url = rtpinfo;
while (*rtpinfo != '\0' && *rtpinfo != ';' && *rtpinfo != ',') {
rtpinfo++;
}
if (*rtpinfo == '\0') {
no_mimes = 1;
} else {
if (*rtpinfo == ',') {
no_mimes = 1;
}
*rtpinfo++ = '\0';
}
char *temp = url;
newmedia = session->rtsp_url_to_media(url);
if (newmedia == NULL) {
media_message(LOG_ERR, "Can't find media from %s", url);
return -1;
} else if (media != NULL && media != newmedia) {
media_message(LOG_ERR, "Url in rtpinfo does not match media %s", url);
return -1;
}
if (temp != url)
free(url);
if (no_mimes == 0) {
int endofurl = 0;
do {
ADV_SPACE(rtpinfo);
for (ix = 0; rtpinfo_types[ix].name != NULL; ix++) {
if (strncasecmp(rtpinfo,
rtpinfo_types[ix].name,
rtpinfo_types[ix].namelen - 1) == 0) {
rtpinfo += rtpinfo_types[ix].namelen - 1;
ADV_SPACE(rtpinfo);
rtpinfo = (rtpinfo_types[ix].routine)(rtpinfo, newmedia, endofurl);
break;
}
}
if (rtpinfo_types[ix].name == NULL) {
#if 1
media_message(LOG_INFO, "Unknown mime-type in RtpInfo - skipping %s",
rtpinfo);
#endif
while (*rtpinfo != ';' && *rtpinfo != '\0') rtpinfo++;
if (*rtpinfo != '\0') rtpinfo++;
}
} while (endofurl == 0 && rtpinfo != NULL && *rtpinfo != '\0');
}
newmedia = NULL;
} while (rtpinfo != NULL && *rtpinfo != '\0');
if (rtpinfo == NULL) {
return (-1);
}
return (1);
}
int CPlayerMedia::rtp_receive_packet (unsigned char interleaved,
struct rtp_packet *pak,
int len)
{
int ret;
if ((interleaved & 1) == 0) {
ret = rtp_process_recv_data(m_rtp_session, 0, pak, len);
if (ret < 0) {
xfree(pak);
}
} else {
uint8_t *pakbuf = (uint8_t *)pak;
pakbuf += sizeof(rtp_packet_data);
rtp_process_ctrl(m_rtp_session, pakbuf, len);
xfree(pak);
ret = 0;
}
return ret;
}
void CPlayerMedia::rtp_periodic (void)
{
rtp_send_ctrl(m_rtp_session,
m_rtp_byte_stream != NULL ?
m_rtp_byte_stream->get_last_rtp_timestamp() : 0,
NULL);
rtp_update(m_rtp_session);
if (m_rtp_byte_stream != NULL) {
int ret = m_rtp_byte_stream->recv_task(m_decode_thread_waiting);
if (ret > 0) {
if (m_rtp_buffering == 0) {
m_rtp_buffering = 1;
start_decoding();
} else {
bytestream_primed();
}
}
return;
}
if (m_head != NULL) {
/*
* Make sure that the payload type is the same
*/
if (m_head->rtp_pak_pt == m_tail->rtp_pak_pt) {
if (m_rtp_queue_len > 10) { // 10 packets consecutive proto same
if (determine_payload_type_from_rtp() == FALSE) {
clear_rtp_packets();
}
}
} else {
clear_rtp_packets();
}
}
}
void CPlayerMedia::rtp_start (void)
{
if (m_rtp_ssrc_set == TRUE) {
rtp_set_my_ssrc(m_rtp_session, m_rtp_ssrc);
} else {
// For now - we'll set up not to wait for RTCP validation
// before indicating if rtp library should accept.
rtp_set_option(m_rtp_session, RTP_OPT_WEAK_VALIDATION, FALSE);
rtp_set_option(m_rtp_session, RTP_OPT_PROMISC, TRUE);
}
if (m_rtp_byte_stream != NULL) {
//m_rtp_byte_stream->reset(); - gets called when pausing
m_rtp_byte_stream->flush_rtp_packets();
}
m_rtp_buffering = 0;
}
void CPlayerMedia::rtp_end(void)
{
if (m_rtp_session != NULL) {
rtp_send_bye(m_rtp_session);
rtp_done(m_rtp_session);
}
m_rtp_session = NULL;
}
int CPlayerMedia::rtcp_send_packet (uint8_t *buffer, int buflen)
{
if (config.get_config_value(CONFIG_SEND_RTCP_IN_RTP_OVER_RTSP) != 0) {
return rtsp_thread_send_rtcp(m_parent->get_rtsp_client(),
m_rtp_media_number_in_session,
buffer,
buflen);
}
return buflen;
}
/****************************************************************************
* RTP receive routines
****************************************************************************/
int CPlayerMedia::recv_thread (void)
{
struct timeval timeout;
int retcode;
CMsg *newmsg;
int recv_thread_stop = 0;
connect_desc_t *cptr;
int receiving = 0;
cptr = get_connect_desc_from_media(m_media_info);
m_rtp_buffering = 0;
if (m_stream_ondemand != 0) {
/*
* We need to free up the ports that we got before RTP tries to set
* them up, so we don't have any re-use conflicts. There is a small
* window here that they might get used...
*/
delete m_ports; // free up the port numbers
m_ports = NULL;
}
#ifdef _WINDOWS
WORD wVersionRequested;
WSADATA wsaData;
int ret;
wVersionRequested = MAKEWORD( 2, 0 );
ret = WSAStartup( wVersionRequested, &wsaData );
if ( ret != 0 ) {
abort();
}
#endif
double bw;
if (find_rtcp_bandwidth_from_media(m_media_info, &bw) < 0) {
bw = 5000.0;
} else {
media_message(LOG_DEBUG, "Using bw from sdp %g", bw);
}
m_rtp_session = rtp_init(m_source_addr == NULL ?
cptr->conn_addr : m_source_addr,
m_our_port,
m_server_port,
cptr == NULL ? 1 : cptr->ttl, // need ttl here
bw, // rtcp bandwidth ?
c_recv_callback,
(uint8_t *)this);
if (m_rtp_session != NULL) {
rtp_set_option(m_rtp_session, RTP_OPT_WEAK_VALIDATION, FALSE);
rtp_set_option(m_rtp_session, RTP_OPT_PROMISC, TRUE);
}
m_rtp_inited = 1;
while (recv_thread_stop == 0) {
/*
* See if we need to check for a state change - this will allow
* changes to the rtp info, if required.
*/
while ((newmsg = m_rtp_msg_queue.get_message()) != NULL) {
switch (newmsg->get_value()) {
case MSG_STOP_THREAD:
recv_thread_stop = 1;
continue;
case MSG_START_SESSION:
if (m_rtp_session == NULL) {
continue;
}
rtp_start();
receiving = 1;
break;
case MSG_PAUSE_SESSION:
break;
}
delete newmsg;
}
if (receiving == 0) {
SDL_Delay(50);
continue;
}
while (receiving == 1 && recv_thread_stop == 0) {
if ((newmsg = m_rtp_msg_queue.get_message()) != NULL) {
//player_debug_message("recv thread message %d", newmsg->get_value());
switch (newmsg->get_value()) {
case MSG_STOP_THREAD:
recv_thread_stop = 1;
break;
case MSG_START_SESSION:
//media_message(LOG_ERR, "Got play when playing");
break;
case MSG_PAUSE_SESSION:
// Indicate that we need to restart the session.
// But keep going...
media_message(LOG_DEBUG, "calling rtp start from pause");
rtp_start();
break;
}
delete newmsg;
newmsg = NULL;
}
if (recv_thread_stop == 1) {
continue;
}
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
retcode = rtp_recv(m_rtp_session, &timeout, 0);
// player_debug_message("rtp_recv return %d", retcode);
// Run rtp periodic after each packet received or idle time.
if (m_paused == 0)
rtp_periodic();
}
}
/*
* When we're done, send a bye, close up rtp, and go home
*/
rtp_end();
return (0);
}
#ifdef DROP_PAKS
static int dropcount = 0;
#endif
/*
* CPlayerMedia::recv_callback - callback from RTP with valid data
*/
void CPlayerMedia::recv_callback (struct rtp *session, rtp_event *e)
{
if (e == NULL) return;
/*
* If we're paused, just dump the packet. Multicast case
*/
if (m_paused != 0) {
if (e->type == RX_RTP) {
xfree(e->data);
return;
}
}
#if DROP_PAKS
if (e->type == RX_RTP && dropcount >= 50) {
xfree((rtp_packet *)e->data);
dropcount = 0;
return;
} else {
dropcount++;
}
#endif
if (m_rtp_byte_stream != NULL) {
m_rtp_byte_stream->recv_callback(session, e);
return;
}
switch (e->type) {
case RX_RTP:
/* regular rtp packet - add it to the queue */
rtp_packet *rpak;
rpak = (rtp_packet *)e->data;
if (rpak->rtp_data_len == 0) {
xfree(rpak);
} else {
add_rtp_packet_to_queue(rpak, &m_head, &m_tail);
m_rtp_queue_len++;
}
break;
case RX_SR:
rtcp_sr *srpak;
srpak = (rtcp_sr *)e->data;
m_rtcp_ntp_frac = srpak->ntp_frac;
m_rtcp_ntp_sec = srpak->ntp_sec;
m_rtcp_rtp_ts = srpak->rtp_ts;
m_rtcp_received = 1;
break;
default:
#if 0
media_message(LOG_DEBUG, "Thread %u - Callback from rtp with %d %p",
SDL_ThreadID(),e->type, e->data);
#endif
break;
}
}
/*
* determine_payload_type_from_rtp - determine with protocol we're dealing with
* in the rtp session. Set various calculations for the sync task, as well...
*/
int CPlayerMedia::determine_payload_type_from_rtp(void)
{
char payload_type = (char)m_head->rtp_pak_pt, temp;
format_list_t *fmt;
uint64_t tickpersec;
CRtpByteStreamBase *bs;
fmt = m_media_info->fmt;
while (fmt != NULL) {
temp = atoi(fmt->fmt);
if (temp == payload_type) {
m_media_fmt = fmt;
if (fmt->rtpmap != NULL) {
tickpersec = fmt->rtpmap->clock_rate;
} else {
if (payload_type >= 96) {
media_message(LOG_ERR, "Media %s, rtp payload type of %u, no rtp map",
m_media_info->media, payload_type);
return (FALSE);
}
tickpersec = 90000;
}
bs =
create_rtp_byte_stream_for_format(m_media_fmt,
payload_type,
m_stream_ondemand,
tickpersec,
&m_head,
&m_tail,
m_rtsp_base_seq_received,
m_rtp_base_seq,
m_rtsp_base_ts_received,
m_rtp_base_ts,
m_rtcp_received,
m_rtcp_ntp_frac,
m_rtcp_ntp_sec,
m_rtcp_rtp_ts);
bs->set_start_time((uint64_t)(m_play_start_time * 1000.0));
m_rtp_byte_stream = bs;
m_byte_stream = m_rtp_byte_stream;
#if 1
media_message(LOG_DEBUG, "media %s - rtp tps %u ntp per rtp ",
m_media_info->media,
m_rtptime_tickpersec);
#endif
return (TRUE);
}
fmt = fmt->next;
}
return (FALSE);
}
/*
* set up rtptime
*/
void CPlayerMedia::set_rtp_base_ts (uint32_t time)
{
m_rtsp_base_ts_received = 1;
m_rtp_base_ts = time;
if (m_rtp_byte_stream != NULL) {
m_rtp_byte_stream->set_rtp_base_ts(time);
}
}
void CPlayerMedia::set_rtp_base_seq (uint16_t seq)
{
m_rtsp_base_seq_received = 1;
m_rtp_base_seq = seq;
if (m_rtp_byte_stream != NULL) {
m_rtp_byte_stream->set_rtp_base_seq(seq);
}
}
void CPlayerMedia::rtp_init_tcp (void)
{
connect_desc_t *cptr;
cptr = get_connect_desc_from_media(m_media_info);
m_rtp_session = rtp_init_extern_net(m_source_addr == NULL ?
cptr->conn_addr : m_source_addr,
m_our_port,
m_server_port,
cptr->ttl,
5000.0, // rtcp bandwidth ?
c_recv_callback,
c_rtcp_send_packet,
(uint8_t *)this);
rtp_set_option(m_rtp_session, RTP_OPT_WEAK_VALIDATION, FALSE);
rtp_set_option(m_rtp_session, RTP_OPT_PROMISC, TRUE);
m_rtp_inited = 1;
}
/* end player_media.cpp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -