/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "rtsp_player.h" #include "utils.h" #include "rtp.h" /***************************************************************************************/ int rtsp_notify_cb(int evt, void * puser) { CRtspPlayer * pPlayer = (CRtspPlayer *) puser; pPlayer->onNotify(evt); return 0; } int rtsp_audio_cb(uint8 * pdata, int len, uint32 ts, uint16 seq, void *puser) { CRtspPlayer * pPlayer = (CRtspPlayer *) puser; pPlayer->onAudio(pdata, len, ts, seq); return 0; } int rtsp_video_cb(uint8 * pdata, int len, uint32 ts, uint16 seq, void *puser) { CRtspPlayer * pPlayer = (CRtspPlayer *) puser; pPlayer->onVideo(pdata, len, ts, seq); return 0; } int rtsp_rtcp_cb(uint8 * pdata, int len, int type, void *puser) { CRtspPlayer * pPlayer = (CRtspPlayer *) puser; pPlayer->onRtcp(pdata, len, type); return 0; } int rtsp_metadata_cb(uint8 * pdata, int len, uint32 ts, uint16 seq, void *puser) { CRtspPlayer * pPlayer = (CRtspPlayer *) puser; return 0; } /***************************************************************************************/ CRtspPlayer::CRtspPlayer(QObject * parent) : CVideoPlayer(parent) , m_port(554) { memset(m_ip, 0, sizeof(m_ip)); } CRtspPlayer::~CRtspPlayer() { close(); } BOOL CRtspPlayer::open(QString fileName, WId hWnd) { close(); CVideoPlayer::open(fileName, hWnd); int port; char proto[32], username[100], password[100], host[100], path[200]; url_split(fileName.toStdString().c_str(), proto, sizeof(proto), username, sizeof(username), password, sizeof(password), host, sizeof(host), &port, path, sizeof(path)); if (strcasecmp(proto, "rtsp") == 0) { port = (port == -1) ? 554 : port; } #ifdef OVER_HTTP else if (strcasecmp(proto, "http") == 0) { port = (port == -1) ? 80 : port; } else if (strcasecmp(proto, "https") == 0) { port = (port == -1) ? 443 : port; } #endif #ifdef OVER_WEBSOCKET else if (strcasecmp(proto, "ws") == 0) { port = (port == -1) ? 80 : port; } else if (strcasecmp(proto, "wss") == 0) { port = (port == -1) ? 443 : port; } #endif else { return FALSE; } if (host[0] == '\0') { return FALSE; } if (username[0] != '\0') { m_acct = username; } if (password[0] != '\0') { m_pass = password; } strncpy(m_ip, host, sizeof(m_ip) - 1); m_port = port; m_rtsp.set_notify_cb(rtsp_notify_cb, this); m_rtsp.set_audio_cb(rtsp_audio_cb); m_rtsp.set_video_cb(rtsp_video_cb); m_rtsp.set_rtcp_cb(rtsp_rtcp_cb); #ifdef METADATA m_rtsp.set_metadata_cb(rtsp_metadata_cb); #endif return TRUE; } void CRtspPlayer::close() { // stop rtsp connection m_rtsp.rtsp_stop(); m_rtsp.rtsp_close(); m_bPlaying = FALSE; m_bPaused = FALSE; m_port = 554; memset(m_ip, 0, sizeof(m_ip)); CVideoPlayer::close(); } BOOL CRtspPlayer::play() { if (m_rtsp.rtsp_start(m_sFileName.toStdString().c_str(), m_acct.toStdString().c_str(), m_pass.toStdString().c_str())) { m_bPlaying = TRUE; } return m_bPlaying; } void CRtspPlayer::stop() { if (m_bPlaying || m_bPaused) { m_rtsp.rtsp_stop(); } m_bPlaying = FALSE; m_bPaused = FALSE; } BOOL CRtspPlayer::pause() { if (m_bPlaying) { if (m_rtsp.rtsp_pause()) { m_bPaused = TRUE; m_bPlaying = FALSE; } } else if (m_bPaused) { if (m_rtsp.rtsp_play(0)) { m_bPaused = FALSE; m_bPlaying = TRUE; } } return m_bPaused; } BOOL CRtspPlayer::seek(int pos) { if (pos < 0 || pos > 100) { return FALSE; } int64 duration = getDuration(); if (duration <= 0) { return FALSE; } int ntp_pos = duration / 100 * pos; m_rtsp.rtsp_play(ntp_pos); return TRUE; } int64 CRtspPlayer::getElapse() { uint32 cur_ts; uint32 init_ts; int frequency; RCUA * p_rua = m_rtsp.get_rua(); if (NULL == p_rua) { return 0; } if (m_videoClock.SyncTime.tv_sec > m_audioClock.SyncTime.tv_sec) { cur_ts = m_videoClock.SyncTimestamp; init_ts = p_rua->video_init_ts; frequency = getVideoClock(); } else if (m_videoClock.SyncTime.tv_sec == m_audioClock.SyncTime.tv_sec && m_videoClock.SyncTime.tv_usec > m_audioClock.SyncTime.tv_usec) { cur_ts = m_videoClock.SyncTimestamp; init_ts = p_rua->video_init_ts; frequency = getVideoClock(); } else { cur_ts = m_audioClock.SyncTimestamp; init_ts = p_rua->audio_init_ts; frequency = getAudioClock(); } if (init_ts == (uint32)-1) { return 0; } int64 elapse; int timestampDiff = cur_ts - init_ts; // Divide this by the timestamp frequency to get real time: double timeDiff = timestampDiff / (double)frequency; if (timeDiff >= 0.0) { elapse = p_rua->media_start + timeDiff * 1000; } else { timeDiff = -timeDiff; elapse = p_rua->media_start + timeDiff * 1000; } return elapse; } int64 CRtspPlayer::getDuration() { RCUA * p_rua = m_rtsp.get_rua(); if (p_rua) { return p_rua->play_end - p_rua->play_start; } return 0; } int CRtspPlayer::getVideoClock() { return 90000; } int CRtspPlayer::getAudioClock() { return m_nSampleRate; } int CRtspPlayer::getVideoCodec() { return m_rtsp.video_codec(); } int CRtspPlayer::getAudioCodec() { return m_rtsp.audio_codec(); } void CRtspPlayer::setRtpMulticast(BOOL flag) { m_rtsp.set_rtp_multicast(flag); } void CRtspPlayer::setRtpOverUdp(BOOL flag) { m_rtsp.set_rtp_over_udp(flag); } #ifdef BACKCHANNEL int CRtspPlayer::getBCFlag() { return m_rtsp.get_bc_flag(); } void CRtspPlayer::setBCFlag(int flag) { m_rtsp.set_bc_flag(flag); } int CRtspPlayer::getBCDataFlag() { return m_rtsp.get_bc_data_flag(); } void CRtspPlayer::setBCDataFlag(int flag) { if (m_rtsp.get_bc_data_flag()) { m_rtsp.set_bc_data_flag(0); } else { m_rtsp.set_bc_data_flag(1); } } void CRtspPlayer::setAudioDevice(int index) { m_rtsp.set_audio_device(index); } #endif // end of BACKCHANNEL #ifdef REPLAY int CRtspPlayer::getReplayFlag() { return m_rtsp.get_replay_flag(); } void CRtspPlayer::setReplayFlag(int flag) { m_rtsp.set_replay_flag(flag); } void CRtspPlayer::setScale(double scale) { m_rtsp.set_scale(scale); } void CRtspPlayer::setRateControlFlag(int flag) { m_rtsp.set_rate_control_flag(flag); } void CRtspPlayer::setImmediateFlag(int flag) { m_rtsp.set_immediate_flag(flag); } void CRtspPlayer::setFramesFlag(int flag, int interval) { m_rtsp.set_frames_flag(flag, interval); } void CRtspPlayer::setReplayRange(time_t start, time_t end) { m_rtsp.set_replay_range(start, end); } #endif // end of REPLAY #ifdef OVER_HTTP void CRtspPlayer::setRtspOverHttp(int flag, int port) { m_rtsp.set_rtsp_over_http(flag, port); } #endif // OVER_HTTP #ifdef OVER_WEBSOCKET void CRtspPlayer::setRtspOverWs(int flag, int port) { m_rtsp.set_rtsp_over_ws(flag, port); } #endif // OVER_WEBSOCKET void CRtspPlayer::onNotify(int evt) { if (evt == RTSP_EVE_CONNSUCC) { int videoCodec = m_rtsp.video_codec(); int audioCodec = m_rtsp.audio_codec(); if (VIDEO_CODEC_NONE != videoCodec) { BOOL ret; uint8 extradata[1024]; int extradata_size = 0; if (VIDEO_CODEC_H264 == videoCodec) { ret = m_rtsp.get_h264_params(m_h26XParamSets.sps, &m_h26XParamSets.sps_size, m_h26XParamSets.pps, &m_h26XParamSets.pps_size); if (ret) { memcpy(extradata, m_h26XParamSets.sps, m_h26XParamSets.sps_size); extradata_size += m_h26XParamSets.sps_size; memcpy(extradata+extradata_size, m_h26XParamSets.pps, m_h26XParamSets.pps_size); extradata_size += m_h26XParamSets.pps_size; // init video decoder openVideo(videoCodec, extradata, extradata_size); } } else if (VIDEO_CODEC_H265 == videoCodec) { ret = m_rtsp.get_h265_params(m_h26XParamSets.sps, &m_h26XParamSets.sps_size, m_h26XParamSets.pps, &m_h26XParamSets.pps_size, m_h26XParamSets.vps, &m_h26XParamSets.vps_size); if (ret) { memcpy(extradata, m_h26XParamSets.vps, m_h26XParamSets.vps_size); extradata_size += m_h26XParamSets.vps_size; memcpy(extradata+extradata_size, m_h26XParamSets.sps, m_h26XParamSets.sps_size); extradata_size += m_h26XParamSets.sps_size; memcpy(extradata+extradata_size, m_h26XParamSets.pps, m_h26XParamSets.pps_size); extradata_size += m_h26XParamSets.pps_size; // init video decoder openVideo(videoCodec, extradata, extradata_size); } } else { openVideo(videoCodec); } } if (AUDIO_CODEC_NONE != audioCodec) { openAudio(audioCodec, m_rtsp.get_audio_samplerate(), m_rtsp.get_audio_channels(), m_rtsp.get_audio_bitpersample()); } } emit notify(evt); } void CRtspPlayer::onAudio(uint8 * pdata, int len, uint32 ts, uint16 seq) { playAudio(pdata, len, ts, seq); } void CRtspPlayer::onVideo(uint8 * pdata, int len, uint32 ts, uint16 seq) { playVideo(pdata, len, ts, seq); } void CRtspPlayer::onRtcp(uint8 * pdata, int len, int type) { uint8 * p_rtp = pdata; uint32 rtp_len = len; // Check for the 20-byte RTCP header: if (rtp_len < 20) { return; } uint8 pt = p_rtp[1]; uint32 rtpHdr = ntohl(*(uint32*)p_rtp); p_rtp += 4; rtp_len -= 4; uint32 ssrc = ntohl(*(uint32*)(p_rtp)); p_rtp += 4; rtp_len -= 4; uint32 ntpMSW = ntohl(*(uint32*)(p_rtp)); p_rtp += 4; rtp_len -= 4; uint32 ntpLSW = ntohl(*(uint32*)(p_rtp)); p_rtp += 4; rtp_len -= 4; uint32 rtpTimestamp = ntohl(*(uint32*)(p_rtp)); if (pt != RTCP_SR) { return; } // Check the RTP version number (it should be 2) if ((rtpHdr & 0xC0000000) != 0x80000000) { return; } if (AV_TYPE_AUDIO == type) { m_audioClock.SyncTimestamp = rtpTimestamp; m_audioClock.SyncTime.tv_sec = ntpMSW - 0x83AA7E80; // 1/1/1900 -> 1/1/1970 double microseconds = (ntpLSW * 15625.0) / 0x04000000; // 10^6/2^32 m_audioClock.SyncTime.tv_usec = (unsigned)(microseconds+0.5); } else if (AV_TYPE_VIDEO == type) { m_videoClock.SyncTimestamp = rtpTimestamp; m_videoClock.SyncTime.tv_sec = ntpMSW - 0x83AA7E80; // 1/1/1900 -> 1/1/1970 double microseconds = (ntpLSW * 15625.0) / 0x04000000; // 10^6/2^32 m_videoClock.SyncTime.tv_usec = (unsigned)(microseconds+0.5); } } BOOL CRtspPlayer::onRecord() { CRtspClient * p_rtsp = &m_rtsp; AVICTX * p_avictx = m_pAviCtx; int vcodec = p_rtsp->video_codec(); int v_extra_len = 0; uint8 v_extra[1024]; if (VIDEO_CODEC_H264 == vcodec) { avi_set_video_info(p_avictx, 0, 0, 0, "H264"); uint8 sps[512], pps[512]; int sps_len = 0, pps_len = 0; if (p_rtsp->get_h264_params(sps, &sps_len, pps, &pps_len)) { memcpy(v_extra, sps, sps_len); memcpy(v_extra + sps_len, pps, pps_len); v_extra_len = sps_len + pps_len; } if (v_extra_len > 0) { avi_set_video_extra_info(p_avictx, v_extra, v_extra_len); } } else if (VIDEO_CODEC_H265 == vcodec) { avi_set_video_info(p_avictx, 0, 0, 0, "H265"); uint8 vps[512], sps[512], pps[512]; int vps_len = 0, sps_len = 0, pps_len = 0; if (p_rtsp->get_h265_params(sps, &sps_len, pps, &pps_len, vps, &vps_len)) { memcpy(v_extra, vps, vps_len); memcpy(v_extra + vps_len, sps, sps_len); memcpy(v_extra + vps_len + sps_len, pps, pps_len); v_extra_len = vps_len + sps_len + pps_len; } if (v_extra_len > 0) { avi_set_video_extra_info(p_avictx, v_extra, v_extra_len); } } else if (VIDEO_CODEC_JPEG == vcodec) { avi_set_video_info(p_avictx, 0, 0, 0, "JPEG"); } else if (VIDEO_CODEC_MP4 == vcodec) { avi_set_video_info(p_avictx, 0, 0, 0, "MP4V"); } int acodec = p_rtsp->audio_codec(); int sr = p_rtsp->get_audio_samplerate(); int ch = p_rtsp->get_audio_channels(); if (AUDIO_CODEC_G711A == acodec) { avi_set_audio_info(p_avictx, ch, sr, AUDIO_FORMAT_ALAW); } else if (AUDIO_CODEC_G711U == acodec) { avi_set_audio_info(p_avictx, ch, sr, AUDIO_FORMAT_MULAW); } else if (AUDIO_CODEC_G726 == acodec) { avi_set_audio_info(p_avictx, ch, sr, AUDIO_FORMAT_G726); } else if (AUDIO_CODEC_G722 == acodec) { avi_set_audio_info(p_avictx, ch, sr, AUDIO_FORMAT_G722); } else if (AUDIO_CODEC_AAC == acodec) { avi_set_audio_info(p_avictx, ch, sr, AUDIO_FORMAT_AAC); avi_set_audio_extra_info(p_avictx, p_rtsp->get_audio_config(), p_rtsp->get_audio_config_len()); } avi_update_header(p_avictx); if (p_avictx->ctxf_video) { if (v_extra_len > 0) { recordVideo(v_extra, v_extra_len, 0, 0); } } return TRUE; } void CRtspPlayer::onRecordFileSwitch() { AVICTX * p_ctx; AVICTX * p_oldctx = m_pAviCtx; QString path = getRecordPath(); QString file = path + "/" + getTempFile(m_ip, ".avi"); p_ctx = avi_write_open(file.toLocal8Bit().toStdString().c_str()); if (NULL == p_ctx) { return; } p_ctx->ctxf_video = p_oldctx->ctxf_video; p_ctx->ctxf_audio = p_oldctx->ctxf_audio; if (p_ctx->ctxf_video) { avi_calc_fps(p_oldctx); avi_set_video_info(p_ctx, p_oldctx->v_fps, p_oldctx->v_width, p_oldctx->v_height, p_oldctx->v_fcc); avi_set_video_extra_info(p_ctx, p_oldctx->v_extra, p_oldctx->v_extra_len); } if (p_ctx->ctxf_audio) { avi_set_audio_info(p_ctx, p_oldctx->a_chns, p_oldctx->a_rate, p_oldctx->a_fmt); avi_set_audio_extra_info(p_ctx, p_oldctx->a_extra, p_oldctx->a_extra_len); } avi_write_close(p_oldctx); avi_update_header(p_ctx); m_pAviCtx = p_ctx; if (m_h26XParamSets.vps_size > 0 || m_h26XParamSets.sps_size > 0 || m_h26XParamSets.pps_size > 0) { avi_write_nalu(m_pAviCtx, m_h26XParamSets.vps, m_h26XParamSets.vps_size, m_h26XParamSets.sps, m_h26XParamSets.sps_size, m_h26XParamSets.pps, m_h26XParamSets.pps_size); } }