diff --git a/3rdpart/ZLToolKit b/3rdpart/ZLToolKit index 82f82e72..9300828f 160000 --- a/3rdpart/ZLToolKit +++ b/3rdpart/ZLToolKit @@ -1 +1 @@ -Subproject commit 82f82e723eda127777aaf91ad0e4615e8d56e8d5 +Subproject commit 9300828fd9df9f581d1422171a5f13bdc2a4e6ab diff --git a/player/test_player.cpp b/player/test_player.cpp index 40d3fcbb..b0bba649 100644 --- a/player/test_player.cpp +++ b/player/test_player.cpp @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) { Logger::Instance().add(std::make_shared()); Logger::Instance().setWriter(std::make_shared()); - if (argc != 3) { + if (argc < 3) { ErrorL << "\r\n测试方法:./test_player rtxp_url rtp_type\r\n" << "例如:./test_player rtsp://admin:123456@127.0.0.1/live/0 0\r\n" << endl; @@ -119,6 +119,9 @@ int main(int argc, char *argv[]) { (*player)[Client::kRtpType] = atoi(argv[2]); //不等待track ready再回调播放成功事件,这样可以加快秒开速度 (*player)[Client::kWaitTrackReady] = false; + if (argc > 3) { + (*player)[Client::kPlayTrack] = atoi(argv[3]); + } player->play(argv[1]); SDLDisplayerHelper::Instance().runLoop(); return 0; diff --git a/src/Common/config.cpp b/src/Common/config.cpp index 5dd4a02c..4520f798 100644 --- a/src/Common/config.cpp +++ b/src/Common/config.cpp @@ -317,6 +317,7 @@ const string kMediaTimeoutMS = "media_timeout_ms"; const string kBeatIntervalMS = "beat_interval_ms"; const string kBenchmarkMode = "benchmark_mode"; const string kWaitTrackReady = "wait_track_ready"; +const string kPlayTrack = "play_track"; } // namespace Client } // namespace mediakit diff --git a/src/Common/config.h b/src/Common/config.h index 7e6b68a9..65176b5e 100644 --- a/src/Common/config.h +++ b/src/Common/config.h @@ -375,6 +375,9 @@ extern const std::string kBeatIntervalMS; extern const std::string kBenchmarkMode; // 播放器在触发播放成功事件时,是否等待所有track ready时再回调 extern const std::string kWaitTrackReady; +// rtsp播放指定track,可选项有0(不指定,默认)、1(视频)、2(音频) +// 设置方法:player[Client::kPlayTrack] = 0/1/2; +extern const std::string kPlayTrack; } // namespace Client } // namespace mediakit diff --git a/src/Rtsp/RtspPlayer.cpp b/src/Rtsp/RtspPlayer.cpp index 38b53669..e94e8dcd 100644 --- a/src/Rtsp/RtspPlayer.cpp +++ b/src/Rtsp/RtspPlayer.cpp @@ -197,13 +197,24 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) { _content_base.pop_back(); } - SdpParser sdpParser(parser.Content()); //解析sdp - _sdp_track = sdpParser.getAvailableTrack(); + SdpParser sdpParser(parser.Content()); + + string sdp; + auto play_track = (TrackType)((int)(*this)[Client::kPlayTrack] - 1); + if (play_track != TrackInvalid) { + auto track = sdpParser.getTrack(play_track); + _sdp_track.emplace_back(track); + sdp = track->toString(); + } else { + _sdp_track = sdpParser.getAvailableTrack(); + sdp = sdpParser.toString(); + } + if (_sdp_track.empty()) { throw std::runtime_error("无有效的Sdp Track"); } - if (!onCheckSDP(sdpParser.toString())) { + if (!onCheckSDP(sdp)) { throw std::runtime_error("onCheckSDP faied"); } _rtcp_context.clear(); diff --git a/src/Rtsp/RtspSession.cpp b/src/Rtsp/RtspSession.cpp index 196d222f..e5d2d9db 100644 --- a/src/Rtsp/RtspSession.cpp +++ b/src/Rtsp/RtspSession.cpp @@ -801,13 +801,14 @@ void RtspSession::handleReq_Play(const Parser &parser) { InfoP(this) << "rtsp seekTo(ms):" << iStartTime; } + vector inited_tracks; _StrPrinter rtp_info; for (auto &track : _sdp_track) { if (track->_inited == false) { - //还有track没有setup - shutdown(SockException(Err_shutdown, "track not setuped")); - return; + //为支持播放器播放单一track, 不校验没有发setup的track + continue; } + inited_tracks.emplace_back(track->_type); track->_ssrc = play_src->getSsrc(track->_type); track->_seq = play_src->getSeqence(track->_type); track->_time_stamp = play_src->getTimeStamp(track->_type); @@ -824,6 +825,12 @@ void RtspSession::handleReq_Play(const Parser &parser) { res_header.emplace("Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << play_src->getTimeStamp(TrackInvalid) / 1000.0); sendRtspResponse("200 OK", res_header); + //设置播放track + if (inited_tracks.size() == 1) { + _target_play_track = inited_tracks[0]; + InfoP(this) << "指定播放track:" << _target_play_track; + } + //在回复rtsp信令后再恢复播放 play_src->pause(false); @@ -956,13 +963,17 @@ void RtspSession::onRcvPeerUdpData(int interleaved, const Buffer::Ptr &buf, cons } else if (!_udp_connected_flags.count(interleaved)) { //这是rtsp播放器的rtp打洞包 _udp_connected_flags.emplace(interleaved); - _rtp_socks[interleaved / 2]->bindPeerAddr((struct sockaddr *)&addr); + if (_rtp_socks[interleaved / 2]) { + _rtp_socks[interleaved / 2]->bindPeerAddr((struct sockaddr *)&addr); + } } } else { //rtcp包 if (!_udp_connected_flags.count(interleaved)) { _udp_connected_flags.emplace(interleaved); - _rtcp_socks[(interleaved - 1) / 2]->bindPeerAddr((struct sockaddr *)&addr); + if (_rtcp_socks[(interleaved - 1) / 2]) { + _rtcp_socks[(interleaved - 1) / 2]->bindPeerAddr((struct sockaddr *)&addr); + } } onRtcpPacket((interleaved - 1) / 2, _sdp_track[(interleaved - 1) / 2], buf->data(), buf->size()); } @@ -1190,32 +1201,39 @@ void RtspSession::updateRtcpContext(const RtpPacket::Ptr &rtp){ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { switch (_rtp_type) { case Rtsp::RTP_TCP: { - size_t i = 0; - auto size = pkt->size(); setSendFlushFlag(false); pkt->for_each([&](const RtpPacket::Ptr &rtp) { - updateRtcpContext(rtp); - if (++i == size) { - setSendFlushFlag(true); + if (_target_play_track == TrackInvalid || _target_play_track == rtp->type) { + updateRtcpContext(rtp); + send(rtp); } - send(rtp); }); + flushAll(); + setSendFlushFlag(true); } break; case Rtsp::RTP_UDP: { - size_t i = 0; - auto size = pkt->size(); + //下标0表示视频,1表示音频 + Socket::Ptr rtp_socks[2]; + rtp_socks[TrackVideo] = _rtp_socks[getTrackIndexByTrackType(TrackVideo)]; + rtp_socks[TrackAudio] = _rtp_socks[getTrackIndexByTrackType(TrackAudio)]; pkt->for_each([&](const RtpPacket::Ptr &rtp) { - updateRtcpContext(rtp); - int track_index = getTrackIndexByTrackType(rtp->type); - auto &pSock = _rtp_socks[track_index]; - if (!pSock) { - shutdown(SockException(Err_shutdown, "udp sock not opened yet")); - return; + if (_target_play_track == TrackInvalid || _target_play_track == rtp->type) { + updateRtcpContext(rtp); + auto &sock = rtp_socks[rtp->type]; + if (!sock) { + shutdown(SockException(Err_shutdown, "udp sock not opened yet")); + return; + } + _bytes_usage += rtp->size() - RtpPacket::kRtpTcpHeaderSize; + sock->send(std::make_shared(rtp, RtpPacket::kRtpTcpHeaderSize), nullptr, 0, false); } - _bytes_usage += rtp->size() - RtpPacket::kRtpTcpHeaderSize; - pSock->send(std::make_shared(rtp, RtpPacket::kRtpTcpHeaderSize), nullptr, 0, ++i == size); }); + for (auto &sock : rtp_socks) { + if (sock) { + sock->flushAll(); + } + } } break; default: diff --git a/src/Rtsp/RtspSession.h b/src/Rtsp/RtspSession.h index b07428aa..a4efabe5 100644 --- a/src/Rtsp/RtspSession.h +++ b/src/Rtsp/RtspSession.h @@ -195,6 +195,8 @@ private: RtspMediaSource::RingType::RingReader::Ptr _play_reader; //sdp里面有效的track,包含音频或视频 std::vector _sdp_track; + //播放器setup指定的播放track,默认为TrackInvalid表示不指定即音视频都推 + TrackType _target_play_track = TrackInvalid; ////////RTP over udp//////// //RTP端口,trackid idx 为数组下标