mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-12-02 08:13:02 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
394c540bba
@ -68,8 +68,11 @@ const string& MediaSource::getId() const {
|
|||||||
return _stream_id;
|
return _stream_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MediaSource::getBytesSpeed(){
|
int MediaSource::getBytesSpeed(TrackType type){
|
||||||
return _speed.getSpeed();
|
if(type == TrackInvalid){
|
||||||
|
return _speed[TrackVideo].getSpeed() + _speed[TrackAudio].getSpeed();
|
||||||
|
}
|
||||||
|
return _speed[type].getSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t MediaSource::getCreateStamp() const {
|
uint64_t MediaSource::getCreateStamp() const {
|
||||||
|
@ -220,7 +220,7 @@ public:
|
|||||||
virtual void setTimeStamp(uint32_t stamp) {};
|
virtual void setTimeStamp(uint32_t stamp) {};
|
||||||
|
|
||||||
// 获取数据速率,单位bytes/s
|
// 获取数据速率,单位bytes/s
|
||||||
int getBytesSpeed();
|
int getBytesSpeed(TrackType type = TrackInvalid);
|
||||||
// 获取流创建GMT unix时间戳,单位秒
|
// 获取流创建GMT unix时间戳,单位秒
|
||||||
uint64_t getCreateStamp() const;
|
uint64_t getCreateStamp() const;
|
||||||
// 获取流上线时间,单位秒
|
// 获取流上线时间,单位秒
|
||||||
@ -286,7 +286,7 @@ private:
|
|||||||
void emitEvent(bool regist);
|
void emitEvent(bool regist);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BytesSpeed _speed;
|
BytesSpeed _speed[TrackMax];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
time_t _create_stamp;
|
time_t _create_stamp;
|
||||||
|
@ -185,7 +185,7 @@ Sdp::Ptr AACTrack::getSdp() {
|
|||||||
WarnL << getCodecName() << " Track未准备好";
|
WarnL << getCodecName() << " Track未准备好";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_shared<AACSdp>(getAacCfg(),getAudioSampleRate(), getAudioChannel());
|
return std::make_shared<AACSdp>(getAacCfg(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
@ -177,10 +177,12 @@ public:
|
|||||||
AACSdp(const string &aac_cfg,
|
AACSdp(const string &aac_cfg,
|
||||||
int sample_rate,
|
int sample_rate,
|
||||||
int channels,
|
int channels,
|
||||||
int payload_type = 98,
|
int bitrate = 128,
|
||||||
int bitrate = 128) : Sdp(sample_rate,payload_type){
|
int payload_type = 98) : Sdp(sample_rate,payload_type){
|
||||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||||
|
if (bitrate) {
|
||||||
_printer << "b=AS:" << bitrate << "\r\n";
|
_printer << "b=AS:" << bitrate << "\r\n";
|
||||||
|
}
|
||||||
_printer << "a=rtpmap:" << payload_type << " MPEG4-GENERIC/" << sample_rate << "/" << channels << "\r\n";
|
_printer << "a=rtpmap:" << payload_type << " MPEG4-GENERIC/" << sample_rate << "/" << channels << "\r\n";
|
||||||
|
|
||||||
string configStr;
|
string configStr;
|
||||||
|
@ -17,7 +17,7 @@ Sdp::Ptr G711Track::getSdp() {
|
|||||||
WarnL << getCodecName() << " Track未准备好";
|
WarnL << getCodecName() << " Track未准备好";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_shared<G711Sdp>(getCodecId(), getAudioSampleRate(), getAudioChannel());
|
return std::make_shared<G711Sdp>(getCodecId(), getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
@ -48,9 +48,12 @@ public:
|
|||||||
G711Sdp(CodecId codecId,
|
G711Sdp(CodecId codecId,
|
||||||
int sample_rate,
|
int sample_rate,
|
||||||
int channels,
|
int channels,
|
||||||
int payload_type = 98,
|
int bitrate = 128,
|
||||||
int bitrate = 128) : Sdp(sample_rate,payload_type), _codecId(codecId){
|
int payload_type = 98) : Sdp(sample_rate,payload_type), _codecId(codecId){
|
||||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||||
|
if (bitrate) {
|
||||||
|
_printer << "b=AS:" << bitrate << "\r\n";
|
||||||
|
}
|
||||||
_printer << "a=rtpmap:" << payload_type << (codecId == CodecG711A ? " PCMA/" : " PCMU/") << sample_rate << "/" << channels << "\r\n";
|
_printer << "a=rtpmap:" << payload_type << (codecId == CodecG711A ? " PCMA/" : " PCMU/") << sample_rate << "/" << channels << "\r\n";
|
||||||
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
|
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,7 @@ Sdp::Ptr H264Track::getSdp() {
|
|||||||
WarnL << getCodecName() << " Track未准备好";
|
WarnL << getCodecName() << " Track未准备好";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_shared<H264Sdp>(getSps(),getPps());
|
return std::make_shared<H264Sdp>(getSps(), getPps(), getBitRate() / 1024);
|
||||||
}
|
}
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
|
||||||
|
@ -292,11 +292,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
H264Sdp(const string &strSPS,
|
H264Sdp(const string &strSPS,
|
||||||
const string &strPPS,
|
const string &strPPS,
|
||||||
int payload_type = 96,
|
int bitrate = 4000,
|
||||||
int bitrate = 4000) : Sdp(90000,payload_type) {
|
int payload_type = 96) : Sdp(90000,payload_type) {
|
||||||
//视频通道
|
//视频通道
|
||||||
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
|
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
|
||||||
|
if (bitrate) {
|
||||||
_printer << "b=AS:" << bitrate << "\r\n";
|
_printer << "b=AS:" << bitrate << "\r\n";
|
||||||
|
}
|
||||||
_printer << "a=rtpmap:" << payload_type << " H264/" << 90000 << "\r\n";
|
_printer << "a=rtpmap:" << payload_type << " H264/" << 90000 << "\r\n";
|
||||||
_printer << "a=fmtp:" << payload_type << " packetization-mode=1; profile-level-id=";
|
_printer << "a=fmtp:" << payload_type << " packetization-mode=1; profile-level-id=";
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ Sdp::Ptr H265Track::getSdp() {
|
|||||||
WarnL << getCodecName() << " Track未准备好";
|
WarnL << getCodecName() << " Track未准备好";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_shared<H265Sdp>(getVps(),getSps(),getPps());
|
return std::make_shared<H265Sdp>(getVps(), getSps(), getPps(), getBitRate() / 1024);
|
||||||
}
|
}
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
||||||
|
|
||||||
|
@ -321,11 +321,13 @@ public:
|
|||||||
H265Sdp(const string &strVPS,
|
H265Sdp(const string &strVPS,
|
||||||
const string &strSPS,
|
const string &strSPS,
|
||||||
const string &strPPS,
|
const string &strPPS,
|
||||||
int payload_type = 96,
|
int bitrate = 4000,
|
||||||
int bitrate = 4000) : Sdp(90000,payload_type) {
|
int payload_type = 96) : Sdp(90000,payload_type) {
|
||||||
//视频通道
|
//视频通道
|
||||||
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
|
_printer << "m=video 0 RTP/AVP " << payload_type << "\r\n";
|
||||||
|
if (bitrate) {
|
||||||
_printer << "b=AS:" << bitrate << "\r\n";
|
_printer << "b=AS:" << bitrate << "\r\n";
|
||||||
|
}
|
||||||
_printer << "a=rtpmap:" << payload_type << " H265/" << 90000 << "\r\n";
|
_printer << "a=rtpmap:" << payload_type << " H265/" << 90000 << "\r\n";
|
||||||
_printer << "a=fmtp:" << payload_type << " ";
|
_printer << "a=fmtp:" << payload_type << " ";
|
||||||
_printer << "sprop-vps=";
|
_printer << "sprop-vps=";
|
||||||
|
@ -17,7 +17,7 @@ Sdp::Ptr OpusTrack::getSdp() {
|
|||||||
WarnL << getCodecName() << " Track未准备好";
|
WarnL << getCodecName() << " Track未准备好";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return std::make_shared<OpusSdp>(getAudioSampleRate(), getAudioChannel());
|
return std::make_shared<OpusSdp>(getAudioSampleRate(), getAudioChannel(), getBitRate() / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
}//namespace mediakit
|
}//namespace mediakit
|
@ -46,9 +46,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
OpusSdp(int sample_rate,
|
OpusSdp(int sample_rate,
|
||||||
int channels,
|
int channels,
|
||||||
int payload_type = 98,
|
int bitrate = 128,
|
||||||
int bitrate = 128) : Sdp(sample_rate,payload_type){
|
int payload_type = 98) : Sdp(sample_rate,payload_type){
|
||||||
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
_printer << "m=audio 0 RTP/AVP " << payload_type << "\r\n";
|
||||||
|
if (bitrate) {
|
||||||
|
_printer << "b=AS:" << bitrate << "\r\n";
|
||||||
|
}
|
||||||
_printer << "a=rtpmap:" << payload_type << " opus/" << sample_rate << "/" << channels << "\r\n";
|
_printer << "a=rtpmap:" << payload_type << " opus/" << sample_rate << "/" << channels << "\r\n";
|
||||||
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
|
_printer << "a=control:trackID=" << (int)TrackAudio << "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否准备好,准备好才能获取譬如sps pps等信息
|
* 是否准备好,准备好才能获取譬如sps pps等信息
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual bool ready() = 0;
|
virtual bool ready() = 0;
|
||||||
|
|
||||||
@ -40,7 +39,6 @@ public:
|
|||||||
* 克隆接口,用于复制本对象用
|
* 克隆接口,用于复制本对象用
|
||||||
* 在调用该接口时只会复制派生类的信息
|
* 在调用该接口时只会复制派生类的信息
|
||||||
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
|
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual Track::Ptr clone() = 0;
|
virtual Track::Ptr clone() = 0;
|
||||||
|
|
||||||
@ -50,12 +48,28 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual Sdp::Ptr getSdp() = 0;
|
virtual Sdp::Ptr getSdp() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回比特率
|
||||||
|
* @return 比特率
|
||||||
|
*/
|
||||||
|
virtual int getBitRate() const { return _bit_rate; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置比特率
|
||||||
|
* @param bit_rate 比特率
|
||||||
|
*/
|
||||||
|
virtual void setBitRate(int bit_rate) { _bit_rate = bit_rate; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制拷贝,只能拷贝派生类的信息,
|
* 复制拷贝,只能拷贝派生类的信息,
|
||||||
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
|
* 环形缓存和代理关系不能拷贝,否则会关系紊乱
|
||||||
* @param that
|
|
||||||
*/
|
*/
|
||||||
Track(const Track &that){}
|
Track(const Track &that){
|
||||||
|
_bit_rate = that._bit_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _bit_rate = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,19 +81,16 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回视频高度
|
* 返回视频高度
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual int getVideoHeight() const {return 0;};
|
virtual int getVideoHeight() const {return 0;};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回视频宽度
|
* 返回视频宽度
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual int getVideoWidth() const {return 0;};
|
virtual int getVideoWidth() const {return 0;};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回视频fps
|
* 返回视频fps
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual float getVideoFps() const {return 0;};
|
virtual float getVideoFps() const {return 0;};
|
||||||
};
|
};
|
||||||
@ -93,19 +104,16 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回音频采样率
|
* 返回音频采样率
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual int getAudioSampleRate() const {return 0;};
|
virtual int getAudioSampleRate() const {return 0;};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回音频采样位数,一般为16或8
|
* 返回音频采样位数,一般为16或8
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual int getAudioSampleBit() const {return 0;};
|
virtual int getAudioSampleBit() const {return 0;};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回音频通道数
|
* 返回音频通道数
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
virtual int getAudioChannel() const {return 0;};
|
virtual int getAudioChannel() const {return 0;};
|
||||||
};
|
};
|
||||||
|
@ -88,7 +88,7 @@ public:
|
|||||||
if (key) {
|
if (key) {
|
||||||
_have_video = true;
|
_have_video = true;
|
||||||
}
|
}
|
||||||
_speed += packet->size();
|
_speed[TrackVideo] += packet->size();
|
||||||
auto stamp = packet->time_stamp;
|
auto stamp = packet->time_stamp;
|
||||||
PacketCache<FMP4Packet>::inputPacket(stamp, true, std::move(packet), key);
|
PacketCache<FMP4Packet>::inputPacket(stamp, true, std::move(packet), key);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ HttpTSPlayer::HttpTSPlayer(const EventPoller::Ptr &poller, bool split_ts){
|
|||||||
HttpTSPlayer::~HttpTSPlayer() {}
|
HttpTSPlayer::~HttpTSPlayer() {}
|
||||||
|
|
||||||
int64_t HttpTSPlayer::onResponseHeader(const string &status, const HttpClient::HttpHeader &headers) {
|
int64_t HttpTSPlayer::onResponseHeader(const string &status, const HttpClient::HttpHeader &headers) {
|
||||||
|
_status = status;
|
||||||
if (status != "200" && status != "206") {
|
if (status != "200" && status != "206") {
|
||||||
//http状态码不符合预期
|
//http状态码不符合预期
|
||||||
shutdown(SockException(Err_other, StrPrinter << "bad http status code:" + status));
|
shutdown(SockException(Err_other, StrPrinter << "bad http status code:" + status));
|
||||||
@ -35,6 +36,9 @@ int64_t HttpTSPlayer::onResponseHeader(const string &status, const HttpClient::H
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HttpTSPlayer::onResponseBody(const char *buf, int64_t size, int64_t recvedSize, int64_t totalSize) {
|
void HttpTSPlayer::onResponseBody(const char *buf, int64_t size, int64_t recvedSize, int64_t totalSize) {
|
||||||
|
if (_status != "200" && _status != "206") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (recvedSize == size) {
|
if (recvedSize == size) {
|
||||||
//开始接收数据
|
//开始接收数据
|
||||||
if (buf[0] == TS_SYNC_BYTE) {
|
if (buf[0] == TS_SYNC_BYTE) {
|
||||||
|
@ -48,6 +48,7 @@ private:
|
|||||||
bool _is_first_packet_ts = false;
|
bool _is_first_packet_ts = false;
|
||||||
//是否判断是否是ts并split
|
//是否判断是否是ts并split
|
||||||
bool _split_ts;
|
bool _split_ts;
|
||||||
|
string _status;
|
||||||
TSSegment _segment;
|
TSSegment _segment;
|
||||||
onShutdown _on_disconnect;
|
onShutdown _on_disconnect;
|
||||||
TSSegment::onSegment _on_segment;
|
TSSegment::onSegment _on_segment;
|
||||||
|
@ -80,7 +80,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onSegmentSize(uint64_t bytes) {
|
void onSegmentSize(uint64_t bytes) {
|
||||||
_speed += bytes;
|
_speed[TrackVideo] += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#ifdef ENABLE_MP4
|
#ifdef ENABLE_MP4
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include "Util/File.h"
|
||||||
#include "Common/config.h"
|
#include "Common/config.h"
|
||||||
#include "MP4Recorder.h"
|
#include "MP4Recorder.h"
|
||||||
#include "Thread/WorkThreadPool.h"
|
#include "Thread/WorkThreadPool.h"
|
||||||
@ -77,12 +78,19 @@ void MP4Recorder::asyncClose() {
|
|||||||
const_cast<RecordInfo&>(info).time_len = ::time(NULL) - info.start_time;
|
const_cast<RecordInfo&>(info).time_len = ::time(NULL) - info.start_time;
|
||||||
//关闭mp4非常耗时,所以要放在后台线程执行
|
//关闭mp4非常耗时,所以要放在后台线程执行
|
||||||
muxer->closeMP4();
|
muxer->closeMP4();
|
||||||
//临时文件名改成正式文件名,防止mp4未完成时被访问
|
|
||||||
rename(strFileTmp.data(),strFile.data());
|
|
||||||
//获取文件大小
|
//获取文件大小
|
||||||
struct stat fileData;
|
struct stat fileData;
|
||||||
stat(strFile.data(), &fileData);
|
stat(strFileTmp.data(), &fileData);
|
||||||
const_cast<RecordInfo&>(info).file_size = fileData.st_size;
|
const_cast<RecordInfo &>(info).file_size = fileData.st_size;
|
||||||
|
if (fileData.st_size < 1024) {
|
||||||
|
//录像文件太小,删除之
|
||||||
|
File::delete_file(strFileTmp.data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//临时文件名改成正式文件名,防止mp4未完成时被访问
|
||||||
|
rename(strFileTmp.data(),strFile.data());
|
||||||
|
|
||||||
/////record 业务逻辑//////
|
/////record 业务逻辑//////
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastRecordMP4,info);
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "Extension/Factory.h"
|
#include "Extension/Factory.h"
|
||||||
namespace mediakit{
|
namespace mediakit{
|
||||||
|
|
||||||
VideoMeta::VideoMeta(const VideoTrack::Ptr &video,int datarate ){
|
VideoMeta::VideoMeta(const VideoTrack::Ptr &video){
|
||||||
if(video->getVideoWidth() > 0 ){
|
if(video->getVideoWidth() > 0 ){
|
||||||
_metadata.set("width", video->getVideoWidth());
|
_metadata.set("width", video->getVideoWidth());
|
||||||
}
|
}
|
||||||
@ -22,13 +22,17 @@ VideoMeta::VideoMeta(const VideoTrack::Ptr &video,int datarate ){
|
|||||||
if(video->getVideoFps() > 0 ){
|
if(video->getVideoFps() > 0 ){
|
||||||
_metadata.set("framerate", video->getVideoFps());
|
_metadata.set("framerate", video->getVideoFps());
|
||||||
}
|
}
|
||||||
_metadata.set("videodatarate", datarate);
|
if (video->getBitRate()) {
|
||||||
|
_metadata.set("videodatarate", video->getBitRate() / 1024);
|
||||||
|
}
|
||||||
_codecId = video->getCodecId();
|
_codecId = video->getCodecId();
|
||||||
_metadata.set("videocodecid", Factory::getAmfByCodecId(_codecId));
|
_metadata.set("videocodecid", Factory::getAmfByCodecId(_codecId));
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioMeta::AudioMeta(const AudioTrack::Ptr &audio,int datarate){
|
AudioMeta::AudioMeta(const AudioTrack::Ptr &audio){
|
||||||
_metadata.set("audiodatarate", datarate);
|
if (audio->getBitRate()) {
|
||||||
|
_metadata.set("audiodatarate", audio->getBitRate() / 1024);
|
||||||
|
}
|
||||||
if(audio->getAudioSampleRate() > 0){
|
if(audio->getAudioSampleRate() > 0){
|
||||||
_metadata.set("audiosamplerate", audio->getAudioSampleRate());
|
_metadata.set("audiosamplerate", audio->getAudioSampleRate());
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ class VideoMeta : public Metadata{
|
|||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<VideoMeta> Ptr;
|
typedef std::shared_ptr<VideoMeta> Ptr;
|
||||||
|
|
||||||
VideoMeta(const VideoTrack::Ptr &video,int datarate = 5000);
|
VideoMeta(const VideoTrack::Ptr &video);
|
||||||
virtual ~VideoMeta(){}
|
virtual ~VideoMeta(){}
|
||||||
|
|
||||||
CodecId getCodecId() const override{
|
CodecId getCodecId() const override{
|
||||||
@ -276,7 +276,7 @@ class AudioMeta : public Metadata{
|
|||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<AudioMeta> Ptr;
|
typedef std::shared_ptr<AudioMeta> Ptr;
|
||||||
|
|
||||||
AudioMeta(const AudioTrack::Ptr &audio,int datarate = 160);
|
AudioMeta(const AudioTrack::Ptr &audio);
|
||||||
|
|
||||||
virtual ~AudioMeta(){}
|
virtual ~AudioMeta(){}
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ bool RtmpDemuxer::loadMetaData(const AMFValue &val){
|
|||||||
int audiosamplerate = 0;
|
int audiosamplerate = 0;
|
||||||
int audiochannels = 0;
|
int audiochannels = 0;
|
||||||
int audiosamplesize = 0;
|
int audiosamplesize = 0;
|
||||||
|
int videodatarate = 0;
|
||||||
|
int audiodatarate = 0;
|
||||||
const AMFValue *audiocodecid = nullptr;
|
const AMFValue *audiocodecid = nullptr;
|
||||||
const AMFValue *videocodecid = nullptr;
|
const AMFValue *videocodecid = nullptr;
|
||||||
val.object_for_each([&](const string &key, const AMFValue &val) {
|
val.object_for_each([&](const string &key, const AMFValue &val) {
|
||||||
@ -48,16 +50,24 @@ bool RtmpDemuxer::loadMetaData(const AMFValue &val){
|
|||||||
audiocodecid = &val;
|
audiocodecid = &val;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (key == "audiodatarate") {
|
||||||
|
audiodatarate = val.as_integer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key == "videodatarate") {
|
||||||
|
videodatarate = val.as_integer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (videocodecid) {
|
if (videocodecid) {
|
||||||
//有视频
|
//有视频
|
||||||
ret = true;
|
ret = true;
|
||||||
makeVideoTrack(*videocodecid);
|
makeVideoTrack(*videocodecid, videodatarate * 1024);
|
||||||
}
|
}
|
||||||
if (audiocodecid) {
|
if (audiocodecid) {
|
||||||
//有音频
|
//有音频
|
||||||
ret = true;
|
ret = true;
|
||||||
makeAudioTrack(*audiocodecid, audiosamplerate, audiochannels, audiosamplesize);
|
makeAudioTrack(*audiocodecid, audiosamplerate, audiochannels, audiosamplesize, audiodatarate * 1024);
|
||||||
}
|
}
|
||||||
} catch (std::exception &ex) {
|
} catch (std::exception &ex) {
|
||||||
WarnL << ex.what();
|
WarnL << ex.what();
|
||||||
@ -71,7 +81,7 @@ void RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
|||||||
if (!_try_get_video_track) {
|
if (!_try_get_video_track) {
|
||||||
_try_get_video_track = true;
|
_try_get_video_track = true;
|
||||||
auto codec = AMFValue(pkt->getMediaType());
|
auto codec = AMFValue(pkt->getMediaType());
|
||||||
makeVideoTrack(codec);
|
makeVideoTrack(codec, 0);
|
||||||
}
|
}
|
||||||
if (_video_rtmp_decoder) {
|
if (_video_rtmp_decoder) {
|
||||||
_video_rtmp_decoder->inputRtmp(pkt);
|
_video_rtmp_decoder->inputRtmp(pkt);
|
||||||
@ -83,7 +93,7 @@ void RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
|||||||
if (!_try_get_audio_track) {
|
if (!_try_get_audio_track) {
|
||||||
_try_get_audio_track = true;
|
_try_get_audio_track = true;
|
||||||
auto codec = AMFValue(pkt->getMediaType());
|
auto codec = AMFValue(pkt->getMediaType());
|
||||||
makeAudioTrack(codec, pkt->getAudioSampleRate(), pkt->getAudioChannel(), pkt->getAudioSampleBit());
|
makeAudioTrack(codec, pkt->getAudioSampleRate(), pkt->getAudioChannel(), pkt->getAudioSampleBit(), 0);
|
||||||
}
|
}
|
||||||
if (_audio_rtmp_decoder) {
|
if (_audio_rtmp_decoder) {
|
||||||
_audio_rtmp_decoder->inputRtmp(pkt);
|
_audio_rtmp_decoder->inputRtmp(pkt);
|
||||||
@ -94,10 +104,11 @@ void RtmpDemuxer::inputRtmp(const RtmpPacket::Ptr &pkt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
|
void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec, int bit_rate) {
|
||||||
//生成Track对象
|
//生成Track对象
|
||||||
_videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getVideoTrackByAmf(videoCodec));
|
_videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getVideoTrackByAmf(videoCodec));
|
||||||
if (_videoTrack) {
|
if (_videoTrack) {
|
||||||
|
_videoTrack->setBitRate(bit_rate);
|
||||||
//生成rtmpCodec对象以便解码rtmp
|
//生成rtmpCodec对象以便解码rtmp
|
||||||
_video_rtmp_decoder = Factory::getRtmpCodecByTrack(_videoTrack, false);
|
_video_rtmp_decoder = Factory::getRtmpCodecByTrack(_videoTrack, false);
|
||||||
if (_video_rtmp_decoder) {
|
if (_video_rtmp_decoder) {
|
||||||
@ -112,10 +123,11 @@ void RtmpDemuxer::makeVideoTrack(const AMFValue &videoCodec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtmpDemuxer::makeAudioTrack(const AMFValue &audioCodec,int sample_rate, int channels, int sample_bit) {
|
void RtmpDemuxer::makeAudioTrack(const AMFValue &audioCodec,int sample_rate, int channels, int sample_bit, int bit_rate) {
|
||||||
//生成Track对象
|
//生成Track对象
|
||||||
_audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getAudioTrackByAmf(audioCodec, sample_rate, channels, sample_bit));
|
_audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getAudioTrackByAmf(audioCodec, sample_rate, channels, sample_bit));
|
||||||
if (_audioTrack) {
|
if (_audioTrack) {
|
||||||
|
_audioTrack->setBitRate(bit_rate);
|
||||||
//生成rtmpCodec对象以便解码rtmp
|
//生成rtmpCodec对象以便解码rtmp
|
||||||
_audio_rtmp_decoder = Factory::getRtmpCodecByTrack(_audioTrack, false);
|
_audio_rtmp_decoder = Factory::getRtmpCodecByTrack(_audioTrack, false);
|
||||||
if (_audio_rtmp_decoder) {
|
if (_audio_rtmp_decoder) {
|
||||||
|
@ -39,8 +39,8 @@ public:
|
|||||||
void inputRtmp(const RtmpPacket::Ptr &pkt);
|
void inputRtmp(const RtmpPacket::Ptr &pkt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void makeVideoTrack(const AMFValue &val);
|
void makeVideoTrack(const AMFValue &val, int bit_rate);
|
||||||
void makeAudioTrack(const AMFValue &val, int sample_rate, int channels, int sample_bit);
|
void makeAudioTrack(const AMFValue &val, int sample_rate, int channels, int sample_bit, int bit_rate);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _try_get_video_track = false;
|
bool _try_get_video_track = false;
|
||||||
|
@ -119,7 +119,8 @@ public:
|
|||||||
* @param pkt rtmp包
|
* @param pkt rtmp包
|
||||||
*/
|
*/
|
||||||
void onWrite(RtmpPacket::Ptr pkt, bool = true) override {
|
void onWrite(RtmpPacket::Ptr pkt, bool = true) override {
|
||||||
_speed += pkt->size();
|
bool is_video = pkt->type_id == MSG_VIDEO;
|
||||||
|
_speed[is_video ? TrackVideo : TrackAudio] += pkt->size();
|
||||||
//保存当前时间戳
|
//保存当前时间戳
|
||||||
switch (pkt->type_id) {
|
switch (pkt->type_id) {
|
||||||
case MSG_VIDEO : _track_stamps[TrackVideo] = pkt->time_stamp, _have_video = true; break;
|
case MSG_VIDEO : _track_stamps[TrackVideo] = pkt->time_stamp, _have_video = true; break;
|
||||||
@ -153,7 +154,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool key = pkt->isVideoKeyFrame();
|
bool key = pkt->isVideoKeyFrame();
|
||||||
bool is_video = pkt->type_id == MSG_VIDEO;
|
|
||||||
auto stamp = pkt->time_stamp;
|
auto stamp = pkt->time_stamp;
|
||||||
PacketCache<RtmpPacket>::inputPacket(stamp, is_video, std::move(pkt), key);
|
PacketCache<RtmpPacket>::inputPacket(stamp, is_video, std::move(pkt), key);
|
||||||
}
|
}
|
||||||
|
@ -101,16 +101,18 @@ bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate,
|
|||||||
//ssrc匹配正确,不匹配计数清零
|
//ssrc匹配正确,不匹配计数清零
|
||||||
_ssrc_err_count[track_index] = 0;
|
_ssrc_err_count[track_index] = 0;
|
||||||
|
|
||||||
//获取rtp中媒体数据偏移量
|
//rtp 12个固定字节头
|
||||||
rtp.offset = 12 + 4;
|
rtp.offset = 12;
|
||||||
|
//rtp有csrc
|
||||||
rtp.offset += 4 * csrc;
|
rtp.offset += 4 * csrc;
|
||||||
if (ext && rtp_raw_len >= rtp.offset) {
|
if (ext) {
|
||||||
/* calculate the header extension length (stored as number of 32-bit words) */
|
//rtp有ext
|
||||||
ext = (AV_RB16(rtp_raw_ptr + rtp.offset - 2) + 1) << 2;
|
uint16_t reserved = AV_RB16(rtp_raw_ptr + rtp.offset);
|
||||||
rtp.offset += ext;
|
uint16_t extlen = AV_RB16(rtp_raw_ptr + rtp.offset + 2) << 2;
|
||||||
|
rtp.offset += extlen + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtp_raw_len + 4 <= rtp.offset) {
|
if (rtp_raw_len <= rtp.offset) {
|
||||||
WarnL << "无有效负载的rtp包:" << rtp_raw_len << " <= " << (int) rtp.offset;
|
WarnL << "无有效负载的rtp包:" << rtp_raw_len << " <= " << (int) rtp.offset;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -128,9 +130,10 @@ bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate,
|
|||||||
payload_ptr[1] = rtp.interleaved;
|
payload_ptr[1] = rtp.interleaved;
|
||||||
payload_ptr[2] = rtp_raw_len >> 8;
|
payload_ptr[2] = rtp_raw_len >> 8;
|
||||||
payload_ptr[3] = (rtp_raw_len & 0x00FF);
|
payload_ptr[3] = (rtp_raw_len & 0x00FF);
|
||||||
|
//添加rtp over tcp前4个字节的偏移量
|
||||||
|
rtp.offset += 4;
|
||||||
//拷贝rtp负载
|
//拷贝rtp负载
|
||||||
memcpy(payload_ptr + 4, rtp_raw_ptr, rtp_raw_len);
|
memcpy(payload_ptr + 4, rtp_raw_ptr, rtp_raw_len);
|
||||||
|
|
||||||
//排序rtp
|
//排序rtp
|
||||||
auto seq = rtp_ptr->sequence;
|
auto seq = rtp_ptr->sequence;
|
||||||
_rtp_sortor[track_index].sortPacket(seq, std::move(rtp_ptr));
|
_rtp_sortor[track_index].sortPacket(seq, std::move(rtp_ptr));
|
||||||
|
@ -63,11 +63,21 @@ bool RtspDemuxer::inputRtp(const RtpPacket::Ptr & rtp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setBitRate(const SdpTrack::Ptr &sdp, const Track::Ptr &track){
|
||||||
|
if (!sdp->_b.empty()) {
|
||||||
|
int data_rate = 0;
|
||||||
|
sscanf(sdp->_b.data(), "AS:%d", &data_rate);
|
||||||
|
if (data_rate) {
|
||||||
|
track->setBitRate(data_rate * 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) {
|
void RtspDemuxer::makeAudioTrack(const SdpTrack::Ptr &audio) {
|
||||||
//生成Track对象
|
//生成Track对象
|
||||||
_audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getTrackBySdp(audio));
|
_audioTrack = dynamic_pointer_cast<AudioTrack>(Factory::getTrackBySdp(audio));
|
||||||
if(_audioTrack){
|
if(_audioTrack){
|
||||||
|
setBitRate(audio, _audioTrack);
|
||||||
//生成RtpCodec对象以便解码rtp
|
//生成RtpCodec对象以便解码rtp
|
||||||
_audioRtpDecoder = Factory::getRtpDecoderByTrack(_audioTrack);
|
_audioRtpDecoder = Factory::getRtpDecoderByTrack(_audioTrack);
|
||||||
if(_audioRtpDecoder){
|
if(_audioRtpDecoder){
|
||||||
@ -85,6 +95,7 @@ void RtspDemuxer::makeVideoTrack(const SdpTrack::Ptr &video) {
|
|||||||
//生成Track对象
|
//生成Track对象
|
||||||
_videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getTrackBySdp(video));
|
_videoTrack = dynamic_pointer_cast<VideoTrack>(Factory::getTrackBySdp(video));
|
||||||
if(_videoTrack){
|
if(_videoTrack){
|
||||||
|
setBitRate(video, _videoTrack);
|
||||||
//生成RtpCodec对象以便解码rtp
|
//生成RtpCodec对象以便解码rtp
|
||||||
_videoRtpDecoder = Factory::getRtpDecoderByTrack(_videoTrack);
|
_videoRtpDecoder = Factory::getRtpDecoderByTrack(_videoTrack);
|
||||||
if(_videoRtpDecoder){
|
if(_videoRtpDecoder){
|
||||||
|
@ -157,7 +157,7 @@ public:
|
|||||||
* @param keyPos 该包是否为关键帧的第一个包
|
* @param keyPos 该包是否为关键帧的第一个包
|
||||||
*/
|
*/
|
||||||
void onWrite(RtpPacket::Ptr rtp, bool keyPos) override {
|
void onWrite(RtpPacket::Ptr rtp, bool keyPos) override {
|
||||||
_speed += rtp->size();
|
_speed[rtp->type] += rtp->size();
|
||||||
assert(rtp->type >= 0 && rtp->type < TrackMax);
|
assert(rtp->type >= 0 && rtp->type < TrackMax);
|
||||||
auto &track = _tracks[rtp->type];
|
auto &track = _tracks[rtp->type];
|
||||||
if (track) {
|
if (track) {
|
||||||
|
@ -65,7 +65,7 @@ public:
|
|||||||
* @param key 是否为关键帧第一个包
|
* @param key 是否为关键帧第一个包
|
||||||
*/
|
*/
|
||||||
void onWrite(TSPacket::Ptr packet, bool key) override {
|
void onWrite(TSPacket::Ptr packet, bool key) override {
|
||||||
_speed += packet->size();
|
_speed[TrackVideo] += packet->size();
|
||||||
if (!_ring) {
|
if (!_ring) {
|
||||||
createRing();
|
createRing();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user