📄 player_media.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.cpp - handle generic information about a stream */#include "systems.h"#include "player_session.h"#include "player_media.h"#include "player_sdp.h"#include "player_util.h"#include <rtp/memory.h>#include "rtp_bytestream.h"#include "our_config_file.h"#include "media_utils.h"#include "ip_port.h"#include "codec_plugin.h"#include "audio.h"//#define DROP_PAKS 1/* * c routines for callbacks */static int c_recv_thread (void *data){ CPlayerMedia *media; media = (CPlayerMedia *)data; return (media->recv_thread());}static int c_decode_thread (void *data){ CPlayerMedia *media; media = (CPlayerMedia *)data; return (media->decode_thread());}static void c_rtp_packet_callback (void *data, unsigned char interleaved, struct rtp_packet *pak, int len){ ((CPlayerMedia *)data)->rtp_receive_packet(interleaved, pak, len);}static int c_init_rtp_tcp (void *data){ ((CPlayerMedia *)data)->rtp_init_tcp(); return 0;}static int c_rtp_start (void *data){ ((CPlayerMedia *)data)->rtp_start(); return 0;}static int c_rtp_periodic (void *data){ ((CPlayerMedia *)data)->rtp_periodic(); return 0;}CPlayerMedia::CPlayerMedia (CPlayerSession *p){ m_plugin = NULL; m_plugin_data = NULL; m_next = NULL; m_parent = p; m_media_info = NULL; m_media_fmt = NULL; m_our_port = 0; m_ports = NULL; m_server_port = 0; m_source_addr = NULL; m_recv_thread = NULL; m_rtptime_tickpersec = 0; m_rtsp_base_seq_received = 0; m_rtsp_base_ts_received = 0; m_head = NULL; m_rtp_queue_len = 0; m_rtp_ssrc_set = FALSE; m_rtsp_session = NULL; m_decode_thread_waiting = 0; m_sync_time_set = FALSE; m_decode_thread = NULL; m_decode_thread_sem = NULL; m_video_sync = NULL; m_audio_sync = NULL; m_paused = 0; m_byte_stream = NULL; m_rtp_byte_stream = NULL; m_video_info = NULL; m_audio_info = NULL; m_user_data = NULL; m_rtcp_received = 0; m_streaming = 0; m_stream_ondemand = 0; m_rtp_use_rtsp = 0;}CPlayerMedia::~CPlayerMedia(){ rtsp_decode_t *rtsp_decode; media_message(LOG_DEBUG, "closing down media %d", m_is_video); if (m_rtsp_session) { // If control is aggregate, m_rtsp_session will be freed by // CPlayerSession if (m_parent->session_control_is_aggregate() == 0) { rtsp_send_teardown(m_rtsp_session, NULL, &rtsp_decode); free_decode_response(rtsp_decode); } m_rtsp_session = NULL; } if (m_recv_thread) { m_rtp_msg_queue.send_message(MSG_STOP_THREAD); SDL_WaitThread(m_recv_thread, NULL); m_recv_thread = NULL; } if (m_decode_thread) { m_decode_msg_queue.send_message(MSG_STOP_THREAD, NULL, 0, m_decode_thread_sem); SDL_WaitThread(m_decode_thread, NULL); m_decode_thread = NULL; } if (m_source_addr != NULL) free(m_source_addr); m_next = NULL; m_parent = NULL; if (m_ports) { delete m_ports; m_ports = NULL; } if (m_rtp_byte_stream) { double diff; diff = difftime(time(NULL), m_start_time); media_message(LOG_INFO, "Media %s", m_media_info->media); media_message(LOG_INFO, "Time: %g seconds", diff);#if 0 double div; player_debug_message("Packets received: %u", m_rtp_packet_received); player_debug_message("Payload received: "LLU" bytes", m_rtp_data_received); div = m_rtp_packet_received / diff; player_debug_message("Packets per sec : %g", div); div = UINT64_TO_DOUBLE(m_rtp_data_received); div *= 8.0; div /= diff; media_message(LOG_INFO, "Bits per sec : %g", div);#endif } if (m_byte_stream) { delete m_byte_stream; m_byte_stream = NULL; m_rtp_byte_stream = NULL; } if (m_video_info) { free(m_video_info); m_video_info = NULL; } if (m_audio_info) { free(m_audio_info); m_audio_info = NULL; } if (m_user_data) { free((void *)m_user_data); m_user_data = NULL; } if (m_decode_thread_sem) { SDL_DestroySemaphore(m_decode_thread_sem); m_decode_thread_sem = NULL; }}void CPlayerMedia::clear_rtp_packets (void){ if (m_head != NULL) { m_tail->rtp_next = NULL; while (m_head != NULL) { rtp_packet *p; p = m_head; m_head = m_head->rtp_next; p->rtp_next = p->rtp_prev = NULL; xfree(p); } } m_tail = NULL; m_rtp_queue_len = 0;}int CPlayerMedia::create_common (int is_video, char *errmsg, uint32_t errlen){ m_parent->add_media(this); m_is_video = is_video; m_decode_thread_sem = SDL_CreateSemaphore(0); m_decode_thread = SDL_CreateThread(c_decode_thread, this); if (m_decode_thread_sem == NULL || m_decode_thread == NULL) { const char *outmedia; if (m_media_info == NULL) { outmedia = m_is_video ? "video" : "audio"; } else outmedia = m_media_info->media; if (errmsg != NULL) snprintf(errmsg, errlen, "Couldn't start media thread for %s", outmedia); media_message(LOG_ERR, "Failed to create decode thread for media %s", outmedia); return (-1); } return 0;}/* * CPlayerMedia::create - create when we've already got a * bytestream */int CPlayerMedia::create (COurInByteStream *b, int is_video, char *errmsg, uint32_t errlen, int streaming){ m_byte_stream = b; m_streaming = streaming; return create_common(is_video, errmsg, errlen);}/* * CPlayerMedia::create_streaming - create a streaming media session, * including setting up rtsp session, rtp and rtp bytestream */int CPlayerMedia::create_streaming (media_desc_t *sdp_media, char *errmsg, uint32_t errlen, int ondemand, int use_rtsp, int media_number_in_session){ char buffer[80]; rtsp_command_t cmd; rtsp_decode_t *decode; m_streaming = 1; if (sdp_media == NULL) { snprintf(errmsg, errlen, "Internal media error - sdp is NULL"); return(-1); } if (strncasecmp(sdp_media->proto, "RTP", strlen("RTP")) != 0) { snprintf(errmsg, errlen, "Media %s doesn't use RTP", sdp_media->media); media_message(LOG_ERR, "%s doesn't use RTP", sdp_media->media); return (-1); } if (sdp_media->fmt == NULL) { snprintf(errmsg, errlen, "Media %s doesn't have any usuable formats", sdp_media->media); media_message(LOG_ERR, "%s doesn't have any formats", sdp_media->media); return (-1); } m_media_info = sdp_media; m_stream_ondemand = ondemand; if (ondemand != 0) { /* * Get 2 consecutive IP ports. If we don't have this, don't even * bother */ if (use_rtsp == 0) { m_ports = new C2ConsecIpPort(m_parent->get_unused_ip_port_ptr()); if (m_ports == NULL || !m_ports->valid()) { snprintf(errmsg, errlen, "Could not find any valid IP ports"); media_message(LOG_ERR, "Couldn't get valid IP ports"); return (-1); } m_our_port = m_ports->first_port(); /* * Send RTSP setup message - first create the transport string for that * message */ create_rtsp_transport_from_sdp(m_parent->get_sdp_info(), m_media_info, m_our_port, buffer, sizeof(buffer)); } else { m_rtp_use_rtsp = 1; m_rtp_media_number_in_session = media_number_in_session; snprintf(buffer, sizeof(buffer), "RTP/AVP/TCP;unicast;interleaved=%d-%d", media_number_in_session * 2, (media_number_in_session * 2) + 1); } memset(&cmd, 0, sizeof(rtsp_command_t)); cmd.transport = buffer; int err = rtsp_send_setup(m_parent->get_rtsp_client(), m_media_info->control_string, &cmd, &m_rtsp_session, &decode, m_parent->session_control_is_aggregate()); if (err != 0) { snprintf(errmsg, errlen, "Couldn't set up session %s", m_media_info->control_string); media_message(LOG_ERR, "Can't create session %s - error code %d", m_media_info->media, err); if (decode != NULL) free_decode_response(decode); return (-1); } cmd.transport = NULL; media_message(LOG_INFO, "Transport returned is %s", decode->transport); /* * process the transport they sent. They need to send port numbers, * addresses, rtptime information, that sort of thing */ if (process_rtsp_transport(decode->transport) != 0) { snprintf(errmsg, errlen, "Couldn't process transport information in RTSP response: %s", decode->transport); free_decode_response(decode); return(-1); } free_decode_response(decode); } else { m_server_port = m_our_port = m_media_info->port; } connect_desc_t *cptr; cptr = get_connect_desc_from_media(m_media_info); if (cptr == NULL) { snprintf(errmsg, errlen, "Server did not return address"); return (-1); } // // okay - here we want to check that the server port is set up, and // go ahead and init rtp, and the associated task // m_start_time = time(NULL); if (create_common(strcmp(sdp_media->media, "video") == 0, errmsg, errlen) < 0) { return -1; } if (ondemand == 0 || use_rtsp == 0) { m_rtp_inited = 0; m_recv_thread = SDL_CreateThread(c_recv_thread, this); if (m_recv_thread == NULL) { snprintf(errmsg, errlen, "Couldn't create media %s RTP recv thread", m_media_info->media); media_message(LOG_ERR, errmsg); return (-1); } while (m_rtp_inited == 0) { SDL_Delay(10); } if (m_rtp_session == NULL) { snprintf(errmsg, errlen, "Could not start RTP - check debug log"); media_message(LOG_ERR, errmsg); return (-1); } } else { int ret; ret = rtsp_thread_set_rtp_callback(m_parent->get_rtsp_client(), c_rtp_packet_callback, c_rtp_periodic, m_rtp_media_number_in_session, this); if (ret < 0) { snprintf(errmsg, errlen, "Can't setup TCP/RTP callback"); return -1; } ret = rtsp_thread_perform_callback(m_parent->get_rtsp_client(), c_init_rtp_tcp, this); if (ret < 0) { snprintf(errmsg, errlen, "Can't init RTP in RTSP thread"); return -1; } } if (m_rtp_session == NULL) { snprintf(errmsg, errlen, "Couldn't create RTP session for media %s", m_media_info->media); media_message(LOG_ERR, errmsg); return (-1); } return (0);}int CPlayerMedia::create_video_plugin (const codec_plugin_t *p, const char *compressor, int type, int profile, format_list_t *sdp_media, video_info_t *video, const uint8_t *user_data, uint32_t userdata_size){ if (m_video_sync == NULL) { m_video_sync = m_parent->set_up_video_sync(); } if (m_video_sync == NULL) return -1; m_plugin = p; m_video_info = video; m_plugin_data = (p->vc_create)(compressor, type, profile, sdp_media, video, user_data, userdata_size, get_video_vft(), m_video_sync); if (m_plugin_data == NULL) return -1; if (user_data != NULL) set_user_data(user_data, userdata_size); return 0;}void CPlayerMedia::set_plugin_data (const codec_plugin_t *p, codec_data_t *d, video_vft_t *v, audio_vft_t *a){ m_plugin = p; m_plugin_data = d; if (is_video()) { if (m_video_sync == NULL) { m_video_sync = m_parent->set_up_video_sync(); } d->ifptr = m_video_sync; d->v.video_vft = v; } else { if (m_audio_sync == NULL) { m_audio_sync = m_parent->set_up_audio_sync(); } d->ifptr = m_audio_sync; d->v.audio_vft = a; } }int CPlayerMedia::get_plugin_status (char *buffer, uint32_t buflen){ if (m_plugin == NULL) return -1; if (m_plugin->c_print_status == NULL) return -1; return ((m_plugin->c_print_status)(m_plugin_data, buffer, buflen));}int CPlayerMedia::create_audio_plugin (const codec_plugin_t *p, const char *compressor, int type, int profile, format_list_t *sdp_media, audio_info_t *audio, const uint8_t *user_data, uint32_t userdata_size){ if (m_audio_sync == NULL) { m_audio_sync = m_parent->set_up_audio_sync(); } if (m_audio_sync == NULL) return -1; m_audio_info = audio; m_plugin = p; m_plugin_data = (p->ac_create)(compressor, type, profile, sdp_media, audio, user_data, userdata_size, get_audio_vft(), m_audio_sync); if (m_plugin_data == NULL) return -1; if (user_data != NULL) set_user_data(user_data, userdata_size); return 0;}/* * CPlayerMedia::do_play - get play command */int CPlayerMedia::do_play (double start_time_offset, char *errmsg, uint32_t errlen){ if (m_streaming != 0) { if (m_stream_ondemand != 0) { /* * We're streaming - send the RTSP play command */ if (m_parent->session_control_is_aggregate() == 0) { char buffer[80]; rtsp_command_t cmd; rtsp_decode_t *decode; range_desc_t *range; memset(&cmd, 0, sizeof(rtsp_command_t)); // only do range if we're not paused range = get_range_from_media(m_media_info); if (range == NULL) { if (errmsg != NULL) { snprintf(errmsg, errlen, "Can't find range in media play"); } return (-1); } if (start_time_offset < range->range_start || start_time_offset > range->range_end) start_time_offset = range->range_start; // need to check for smpte sprintf(buffer, "npt=%g-%g", start_time_offset, range->range_end); cmd.range = buffer; if (rtsp_send_play(m_rtsp_session, &cmd, &decode) != 0) { media_message(LOG_ERR, "RTSP play command failed"); if (errmsg != NULL) { snprintf(errmsg, errlen, "RTSP Play Error %s-%s", decode->retcode, decode->retresp != NULL ? decode->retresp : ""); } free_decode_response(decode); return (-1); } /* * process the return information
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -