Commit def2d71d by nanguantong Committed by GitHub

Merge pull request #2 from zlmediakit/master

pull
parents 205b01f6 b3c53391
Subproject commit b7485c4b48b277bfaba2ad930cf1f30e2806299c
Subproject commit 2970df35c5c8c48013f91c818845c5c90914ea57
......@@ -4,7 +4,7 @@ android {
compileSdkVersion 28
defaultConfig {
applicationId "com.zlmediakit.demo"
minSdkVersion 19
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
......
......@@ -174,6 +174,7 @@ JNI_API(jboolean,startDemo,jstring ini_dir){
mINI::Instance()["http.sslport"] = 8443;
mINI::Instance()["rtsp.port"] = 8554;
mINI::Instance()["rtsp.sslport"] = 8332;
mINI::Instance()["general.enableVhost"] = 0;
for(auto &pr : mINI::Instance()){
//替换hook默认地址
replace(pr.second,"https://127.0.0.1/","http://127.0.0.1:8080/");
......
......@@ -38,10 +38,10 @@ public class MainActivity extends AppCompatActivity {
if(permissionSuccess){
Toast.makeText(this,"你可以修改配置文件再启动:" + sd_dir + "/zlmediakit.ini" ,Toast.LENGTH_LONG).show();
Toast.makeText(this,"SSL证书请放置在:" + sd_dir + "/zlmediakit.pem" ,Toast.LENGTH_LONG).show();
ZLMediaKit.startDemo(sd_dir);
}else{
Toast.makeText(this,"请给予我权限,否则无法启动测试!" ,Toast.LENGTH_LONG).show();
}
ZLMediaKit.startDemo(sd_dir);
}
private ZLMediaKit.MediaPlayer _player;
......
......@@ -163,7 +163,7 @@ class Parser {
for (string &key_val : arg_vec) {
auto key = FindField(key_val.data(), NULL, key_delim);
auto val = FindField(key_val.data(), key_delim, NULL);
ret.emplace_force(key,val);
ret.emplace_force(trim(key),trim(val));
}
return ret;
}
......
......@@ -60,10 +60,8 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
}
if (strcasecmp(track->_codec.data(), "h264") == 0) {
auto map = Parser::parseArgs(track->_fmtp," ","=");
for(auto &pr : map){
trim(pr.second," ;");
}
//a=fmtp:96 packetization-mode=1;profile-level-id=42C01F;sprop-parameter-sets=Z0LAH9oBQBboQAAAAwBAAAAPI8YMqA==,aM48gA==
auto map = Parser::parseArgs(FindField(track->_fmtp.data()," ", nullptr),";","=");
auto sps_pps = map["sprop-parameter-sets"];
if(sps_pps.empty()){
return std::make_shared<H264Track>();
......@@ -77,10 +75,7 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
if (strcasecmp(track->_codec.data(), "h265") == 0) {
//a=fmtp:96 sprop-sps=QgEBAWAAAAMAsAAAAwAAAwBdoAKAgC0WNrkky/AIAAADAAgAAAMBlQg=; sprop-pps=RAHA8vA8kAA=
auto map = Parser::parseArgs(track->_fmtp," ","=");
for(auto &pr : map){
trim(pr.second," ;");
}
auto map = Parser::parseArgs(FindField(track->_fmtp.data()," ", nullptr),";","=");
auto vps = decodeBase64(map["sprop-vps"]);
auto sps = decodeBase64(map["sprop-sps"]);
auto pps = decodeBase64(map["sprop-pps"]);
......
......@@ -390,7 +390,7 @@ public:
_printer << "m=video 0 RTP/AVP " << playload_type << "\r\n";
_printer << "b=AS:" << bitrate << "\r\n";
_printer << "a=rtpmap:" << playload_type << " H264/" << 90000 << "\r\n";
_printer << "a=fmtp:" << playload_type << " packetization-mode=1;profile-level-id=";
_printer << "a=fmtp:" << playload_type << " packetization-mode=1; profile-level-id=";
char strTemp[100];
uint32_t profile_level_id = 0;
......@@ -402,7 +402,7 @@ public:
memset(strTemp, 0, 100);
sprintf(strTemp, "%06X", profile_level_id);
_printer << strTemp;
_printer << ";sprop-parameter-sets=";
_printer << "; sprop-parameter-sets=";
memset(strTemp, 0, 100);
av_base64_encode(strTemp, 100, (uint8_t *) strSPS.data(), strSPS.size());
_printer << strTemp << ",";
......
......@@ -28,54 +28,51 @@
namespace mediakit {
void Stamp::revise(uint32_t dts, uint32_t pts, int64_t &dts_out, int64_t &pts_out) {
if(!pts){
//没有播放时间戳,使其赋值为解码时间戳
pts = dts;
int64_t DeltaStamp::deltaStamp(int64_t stamp) {
if(!_last_stamp){
//第一次计算时间戳增量,时间戳增量为0
_last_stamp = stamp;
return 0;
}
//pts和dts的差值
int pts_dts_diff = pts - dts;
if(_first){
//记录第一次时间戳,后面好计算时间戳增量
_start_dts = dts;
_first = false;
_ticker.resetTime();
}
if (!dts) {
//没有解码时间戳,我们生成解码时间戳
dts = _ticker.elapsedTime();
int64_t ret = stamp - _last_stamp;
if(ret >= 0){
//时间戳增量为正,返回之
_last_stamp = stamp;
return ret;
}
//相对时间戳
dts_out = dts - _start_dts;
if(!_playback){
if(dts_out < _dts_inc){
//本次相对时间戳竟然小于上次?
if(dts_out < 0 || _dts_inc - dts_out > 0xFFFF){
//时间戳回环,保证下次相对时间戳与本次相对合理增长
_start_dts = dts - _dts_inc;
//本次时间戳强制等于上次时间戳
dts_out = _dts_inc;
}else{
//时间戳变小了?,那么取上次时间戳
dts_out = _dts_inc;
}
}else if(dts_out - _dts_inc > 1000){
//直播时,不允许时间戳跳跃性增加
dts_out = _dts_inc;
}
//时间戳增量为负,说明时间戳回环了或回退了
_last_stamp = stamp;
return _playback ? ret : 0;
}
void DeltaStamp::setPlayBack(bool playback) {
_playback = playback;
}
void Stamp::revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out) {
if(!dts && !pts){
//没有时间戳,我们生成时间戳
pts = dts = _ticker.elapsedTime();
}else if(!pts){
//只是没有播放时间戳,使其赋值为解码时间戳
pts = dts;
}
//pts和dts的差值
int pts_dts_diff = pts - dts;
//保留这次相对时间戳,以便下次对比是否回环或乱序
_dts_inc = dts_out;
//相对时间戳
_relativeStamp += deltaStamp(dts);
dts_out = _relativeStamp;
//////////////以下是播放时间戳的计算//////////////////
if(pts_dts_diff > 200 || pts_dts_diff < -200){
//如果差值大于200毫秒,则认为由于回环导致时间戳错乱了
pts_dts_diff = 0;
}
pts_out = dts_out + pts_dts_diff;
if(pts_out < 0){
//时间戳不能小于0
......@@ -83,8 +80,13 @@ void Stamp::revise(uint32_t dts, uint32_t pts, int64_t &dts_out, int64_t &pts_ou
}
}
void Stamp::setPlayBack(bool playback) {
_playback = playback;
void Stamp::setRelativeStamp(int64_t relativeStamp) {
_relativeStamp = relativeStamp;
}
int64_t Stamp::getRelativeStamp() const {
return _relativeStamp;
}
}//namespace mediakit
\ No newline at end of file
......@@ -33,18 +33,33 @@ using namespace toolkit;
namespace mediakit {
//该类解决时间戳回环、回退问题
//计算相对时间戳或者产生平滑时间戳
class Stamp {
class DeltaStamp{
public:
Stamp() = default;
~Stamp() = default;
DeltaStamp() = default;
~DeltaStamp() = default;
/**
* 设置回放模式,回放模式时间戳可以回退
* 计算时间戳增量
* @param stamp 绝对时间戳
* @return 时间戳增量
*/
int64_t deltaStamp(int64_t stamp);
/**
* 设置是否为回放模式,回放模式运行时间戳回退
* @param playback 是否为回放模式
*/
void setPlayBack(bool playback = true);
private:
int64_t _last_stamp = 0;
bool _playback = false;
};
//该类解决时间戳回环、回退问题
//计算相对时间戳或者产生平滑时间戳
class Stamp : public DeltaStamp{
public:
Stamp() = default;
~Stamp() = default;
/**
* 修正时间戳
......@@ -53,12 +68,21 @@ public:
* @param dts_out 输出dts
* @param pts_out 输出pts
*/
void revise(uint32_t dts, uint32_t pts, int64_t &dts_out, int64_t &pts_out);
void revise(int64_t dts, int64_t pts, int64_t &dts_out, int64_t &pts_out);
/**
* 再设置相对时间戳,用于seek用
* @param relativeStamp 相对时间戳
*/
void setRelativeStamp(int64_t relativeStamp);
/**
* 获取当前相对时间戳
* @return
*/
int64_t getRelativeStamp() const ;
private:
bool _playback = false;
int64_t _start_dts = 0;
int64_t _dts_inc = 0;
bool _first = true;
int64_t _relativeStamp = 0;
SmoothTicker _ticker;
};
......
......@@ -68,12 +68,9 @@ void RtspPlayer::teardown(){
CLEAR_ARR(_aui64RtpRecv)
CLEAR_ARR(_aui64RtpRecv)
CLEAR_ARR(_aui16NowSeq)
CLEAR_ARR(_aiFistStamp);
CLEAR_ARR(_aiNowStamp);
_pPlayTimer.reset();
_pPlayTimer.reset();
_pRtpTimer.reset();
_iSeekTo = 0;
_uiCseq = 1;
_onHandshake = nullptr;
}
......@@ -222,6 +219,16 @@ void RtspPlayer::handleResDESCRIBE(const Parser& parser) {
SdpParser sdpParser(parser.Content());
//解析sdp
_aTrackInfo = sdpParser.getAvailableTrack();
auto title = sdpParser.getTrack(TrackTitle);
bool isPlayback = false;
if(title && title->_duration ){
isPlayback = true;
}
for(auto &stamp : _stamp){
stamp.setPlayBack(isPlayback);
stamp.setRelativeStamp(0);
}
if (_aTrackInfo.empty()) {
throw std::runtime_error("无有效的Sdp Track");
......@@ -386,7 +393,7 @@ void RtspPlayer::handleResSETUP(const Parser &parser, unsigned int uiTrackIndex)
}
//所有setup命令发送完毕
//发送play命令
pause(false);
sendPause(false, 0,false);
}
void RtspPlayer::sendOptions() {
......@@ -403,25 +410,19 @@ void RtspPlayer::sendDescribe() {
}
void RtspPlayer::sendPause(bool bPause,uint32_t seekMS){
if(!bPause){
//修改时间轴
int iTimeInc = seekMS - getProgressMilliSecond();
for(unsigned int i = 0 ;i < _aTrackInfo.size() ;i++){
_aiFistStamp[i] = _aiNowStamp[i] + iTimeInc;
_aiNowStamp[i] = _aiFistStamp[i];
}
_iSeekTo = seekMS;
}
void RtspPlayer::sendPause(bool bPause,uint32_t seekMS,bool range){
//开启或暂停rtsp
_onHandshake = std::bind(&RtspPlayer::handleResPAUSE,this, placeholders::_1,bPause);
sendRtspRequest(bPause ? "PAUSE" : "PLAY",
_strContentBase,
{"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"});
if(!bPause && range){
sendRtspRequest(bPause ? "PAUSE" : "PLAY", _strContentBase,
{"Range",StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << seekMS / 1000.0 << "-"});
} else{
sendRtspRequest(bPause ? "PAUSE" : "PLAY", _strContentBase);
}
}
void RtspPlayer::pause(bool bPause) {
sendPause(bPause, getProgressMilliSecond());
sendPause(bPause, getProgressMilliSecond(),false);
}
void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
......@@ -430,6 +431,7 @@ void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
return;
}
if (!bPause) {
uint32_t iSeekTo = 0;
//修正时间轴
auto strRange = parser["Range"];
if (strRange.size()) {
......@@ -437,25 +439,12 @@ void RtspPlayer::handleResPAUSE(const Parser& parser, bool bPause) {
if (strStart == "now") {
strStart = "0";
}
_iSeekTo = 1000 * atof(strStart.data());
DebugL << "seekTo(ms):" << _iSeekTo ;
}
auto strRtpInfo = parser["RTP-Info"];
if (strRtpInfo.size()) {
strRtpInfo.append(",");
vector<string> vec = split(strRtpInfo, ",");
for(auto &strTrack : vec){
strTrack.append(";");
auto strControlSuffix = strTrack.substr(1 + strTrack.rfind('/'),strTrack.find(';') - strTrack.rfind('/') - 1);
auto strRtpTime = FindField(strTrack.data(), "rtptime=", ";");
auto idx = getTrackIndexByControlSuffix(strControlSuffix);
if(idx != -1){
_aiFistStamp[idx] = _aTrackInfo[idx]->_samplerate>0?atoll(strRtpTime.data()) * 1000 / _aTrackInfo[idx]->_samplerate :1;
_aiNowStamp[idx] = _aiFistStamp[idx];
DebugL << "rtptime(ms):" << strControlSuffix <<" " << strRtpTime;
}
}
iSeekTo = 1000 * atof(strStart.data());
DebugL << "seekTo(ms):" << iSeekTo ;
}
//设置相对时间戳
_stamp[0].setRelativeStamp(iSeekTo);
_stamp[1].setRelativeStamp(iSeekTo);
onPlayResult_l(SockException(Err_success, "rtsp play success"));
} else {
_pRtpTimer.reset();
......@@ -630,12 +619,11 @@ void RtspPlayer::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx){
}
_aui64RtpRecv[trackidx] ++;
_aui16NowSeq[trackidx] = rtppt->sequence;
_aiNowStamp[trackidx] = rtppt->timeStamp;
if( _aiFistStamp[trackidx] == 0){
_aiFistStamp[trackidx] = _aiNowStamp[trackidx];
}
rtppt->timeStamp -= _aiFistStamp[trackidx];
//计算相对时间戳
int64_t dts_out;
_stamp[trackidx].revise(rtppt->timeStamp,rtppt->timeStamp,dts_out,dts_out);
rtppt->timeStamp = dts_out;
onRecvRTP_l(rtppt,_aTrackInfo[trackidx]);
}
float RtspPlayer::getPacketLossRate(TrackType type) const{
......@@ -653,7 +641,6 @@ float RtspPlayer::getPacketLossRate(TrackType type) const{
return 1.0 - (double)totalRecv / totalSend;
}
if(_aui16NowSeq[iTrackIdx] - _aui16FirstSeq[iTrackIdx] + 1 == 0){
return 0;
}
......@@ -661,14 +648,10 @@ float RtspPlayer::getPacketLossRate(TrackType type) const{
}
uint32_t RtspPlayer::getProgressMilliSecond() const{
uint32_t iTime[2] = {0,0};
for(unsigned int i = 0 ;i < _aTrackInfo.size() ;i++){
iTime[i] = _aiNowStamp[i] - _aiFistStamp[i];
}
return _iSeekTo + MAX(iTime[0],iTime[1]);
return MAX(_stamp[0].getRelativeStamp(),_stamp[1].getRelativeStamp());
}
void RtspPlayer::seekToMilliSecond(uint32_t ms) {
sendPause(false,ms);
sendPause(false,ms, true);
}
void RtspPlayer::sendRtspRequest(const string &cmd, const string &url, const std::initializer_list<string> &header) {
......
......@@ -40,6 +40,7 @@
#include "Network/TcpClient.h"
#include "RtspSplitter.h"
#include "RtpReceiver.h"
#include "MediaFile/Stamp.h"
using namespace std;
using namespace toolkit;
......@@ -114,7 +115,7 @@ private:
//发送SETUP命令
void sendSetup(unsigned int uiTrackIndex);
void sendPause(bool bPause,uint32_t ms);
void sendPause(bool bPause,uint32_t ms, bool range);
void sendOptions();
void sendDescribe();
......@@ -148,12 +149,8 @@ private:
std::shared_ptr<Timer> _pPlayTimer;
std::shared_ptr<Timer> _pRtpTimer;
//播放进度控制,单位毫秒
uint32_t _iSeekTo = 0;
//单位毫秒
uint32_t _aiFistStamp[2] = {0,0};
uint32_t _aiNowStamp[2] = {0,0};
//时间戳
Stamp _stamp[2];
//rtcp相关
RtcpCounter _aRtcpCnt[2]; //rtcp统计,trackid idx 为数组下标
......
......@@ -101,6 +101,7 @@ int main(int argc, char *argv[]) {
#endif
static char *url = argv[1];
//设置退出信号处理函数
signal(SIGINT, [](int) { SDLDisplayerHelper::Instance().shutdown(); });
//设置日志
......@@ -140,7 +141,7 @@ int main(int argc, char *argv[]) {
decoder.set<H264Decoder>();
}
if(!displayer){
displayer.set<YuvDisplayer>();
displayer.set<YuvDisplayer>(nullptr,url);
}
if(!merger){
merger.set<FrameMerger>();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论