/*************************************************************************************** * * 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 "http_flv_player.h" #include "utils.h" /***************************************************************************************/ int http_flv_notify_callback(int evt, void * puser) { CHttpFlvPlayer * pPlayer = (CHttpFlvPlayer *) puser; pPlayer->onNotify(evt); return 0; } int http_flv_audio_callback(uint8 * pdata, int len, uint32 ts, void *puser) { CHttpFlvPlayer * pPlayer = (CHttpFlvPlayer *) puser; pPlayer->onAudio(pdata, len, ts); return 0; } int http_flv_video_callback(uint8 * pdata, int len, uint32 ts, void *puser) { CHttpFlvPlayer * pPlayer = (CHttpFlvPlayer *) puser; pPlayer->onVideo(pdata, len, ts); return 0; } /***************************************************************************************/ CHttpFlvPlayer::CHttpFlvPlayer(): CVideoPlayer() { memset(m_ip, 0, sizeof(m_ip)); } CHttpFlvPlayer::~CHttpFlvPlayer() { close(); } std::string CHttpFlvPlayer::createNewFLVUrl(const std::string& username, const std::string& password, const std::string& url) { // Copy the original strings to avoid modifying the originals std::string modUsername = username; std::string modPassword = password; // Replace '@' with '_' in username and password std::replace(modUsername.begin(), modUsername.end(), '@', '_'); std::replace(modPassword.begin(), modPassword.end(), '@', '_'); // Extract the protocol and rest of the URL size_t protocolEndPos = url.find("://") + 3; // Find the position right after "://" std::string protocol = url.substr(0, protocolEndPos); // Include "://" // Construct the new URL with modified credentials std::string newUrl = protocol; newUrl += modUsername + ":" + modPassword + "@"; newUrl += url.substr(protocolEndPos); return newUrl; } BOOL CHttpFlvPlayer::open(std::string fileName) { close(); CVideoPlayer::open(fileName); char host[100]; url_split(fileName.c_str(), NULL, 0, NULL, 0, NULL, 0, host, sizeof(host), NULL, NULL, 0); if (host[0] == '\0') { return FALSE; } strncpy(m_ip, host, sizeof(m_ip) - 1); m_httpflv.set_notify_cb(http_flv_notify_callback, this); m_httpflv.set_audio_cb(http_flv_audio_callback); m_httpflv.set_video_cb(http_flv_video_callback); return TRUE; } BOOL CHttpFlvPlayer::open(std::string _username, std::string _password, std::string _url) { close(); CVideoPlayer::open(_username, _password, _url); char host[100]; std::string fileName = createNewFLVUrl(_username, _password, _url); url_split(fileName.c_str(), NULL, 0, NULL, 0, NULL, 0, host, sizeof(host), NULL, NULL, 0); if (host[0] == '\0') { return FALSE; } strncpy(m_ip, host, sizeof(m_ip) - 1); m_httpflv.set_notify_cb(http_flv_notify_callback, this); m_httpflv.set_audio_cb(http_flv_audio_callback); m_httpflv.set_video_cb(http_flv_video_callback); return TRUE; } void CHttpFlvPlayer::setBbox(cv::Rect bbox) { CVideoPlayer::setBbox(bbox); } void CHttpFlvPlayer::setCrop(bool crop) { CVideoPlayer::setCrop(crop); } void CHttpFlvPlayer::close() { // stop http-flv connection m_httpflv.http_flv_stop(); m_httpflv.http_flv_close(); m_bPlaying = FALSE; m_bPaused = FALSE; CVideoPlayer::StopVideoDecoder(); CVideoPlayer::close(); } BOOL CHttpFlvPlayer::play() { if (m_httpflv.http_flv_start(m_sFileName.c_str(), m_acct.c_str(), m_pass.c_str())) { m_bPlaying = TRUE; m_bPaused = FALSE; } CVideoPlayer::StartVideoDecoder();// Start the video decoder return m_bPlaying; } void CHttpFlvPlayer::stop() { if (m_bPlaying || m_bPaused) { m_httpflv.http_flv_stop(); } // Set flags BEFORE stopping decoder so rx thread stops calling decode() m_bPlaying = FALSE; m_bPaused = FALSE; CVideoPlayer::StopVideoDecoder(); // Stop the video decoder } BOOL CHttpFlvPlayer::pause() { if (m_bPlaying) { if (m_httpflv.http_flv_pause()) { m_bPaused = TRUE; m_bPlaying = FALSE; } } else if (m_bPaused) { if (m_httpflv.http_flv_play()) { m_bPaused = FALSE; m_bPlaying = TRUE; } } CVideoPlayer::StopVideoDecoder(); // Stop the video decoder return m_bPaused; } BOOL CHttpFlvPlayer::seek(int pos) { return FALSE; } int64 CHttpFlvPlayer::getElapse() { uint32 cur_ts; uint32 init_ts; int frequency; if (m_videoClock.SyncTime.tv_sec > m_audioClock.SyncTime.tv_sec) { cur_ts = m_videoClock.SyncTimestamp; init_ts = m_httpflv.get_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 = m_httpflv.get_video_init_ts(); frequency = getVideoClock(); } else { cur_ts = m_audioClock.SyncTimestamp; init_ts = m_httpflv.get_audio_init_ts(); frequency = getAudioClock(); } if (init_ts == 0) { 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 = timeDiff * 1000; } else { timeDiff = -timeDiff; elapse = timeDiff * 1000; } return elapse; } int64 CHttpFlvPlayer::getDuration() { return 0; } int CHttpFlvPlayer::getVideoCodec() { return m_httpflv.video_codec(); } int CHttpFlvPlayer::getAudioCodec() { return m_httpflv.audio_codec(); } void CHttpFlvPlayer::onNotify(int evt) { if (evt == HTTP_FLV_EVE_VIDEOREADY) { int videoCodec = m_httpflv.video_codec(); if (VIDEO_CODEC_NONE != videoCodec) { openVideo(videoCodec); } } else if (evt == HTTP_FLV_EVE_AUDIOREADY) { int audioCodec = m_httpflv.audio_codec(); if (AUDIO_CODEC_NONE != audioCodec) { openAudio(audioCodec, m_httpflv.get_audio_samplerate(), m_httpflv.get_audio_channels()); } } } void CHttpFlvPlayer::onAudio(uint8 * pdata, int len, uint32 ts) { playAudio(pdata, len, ts, 0); } void CHttpFlvPlayer::onVideo(uint8 * pdata, int len, uint32 ts) { playVideo(pdata, len, ts, 0); } BOOL CHttpFlvPlayer::onRecord() { CHttpFlvClient * p_httpflv = &m_httpflv; AVICTX * p_avictx = m_pAviCtx; int vcodec = p_httpflv->video_codec(); int fps = p_httpflv->get_video_framerate(); int v_extra_len = 0; uint8 v_extra[1024]; if (VIDEO_CODEC_H264 == vcodec) { avi_set_video_info(p_avictx, fps, 0, 0, "H264"); uint8 sps[512], pps[512]; int sps_len = 0, pps_len = 0; if (p_httpflv->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, fps, 0, 0, "H265"); uint8 vps[512], sps[512], pps[512]; int vps_len = 0, sps_len = 0, pps_len = 0; if (p_httpflv->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, fps, 0, 0, "JPEG"); } else if (VIDEO_CODEC_MP4 == vcodec) { avi_set_video_info(p_avictx, fps, 0, 0, "MP4V"); } int acodec = p_httpflv->audio_codec(); int sr = p_httpflv->get_audio_samplerate(); int ch = p_httpflv->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_httpflv->get_audio_config(), p_httpflv->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; }