commit
0c9dd568b0
|
|
@ -1,6 +1,6 @@
|
||||||
[submodule "ZLToolKit"]
|
[submodule "ZLToolKit"]
|
||||||
path = 3rdpart/ZLToolKit
|
path = 3rdpart/ZLToolKit
|
||||||
url = https://gitee.com/xiahcu/ZLToolKit
|
url = ../ZLToolKit
|
||||||
[submodule "3rdpart/media-server"]
|
[submodule "3rdpart/media-server"]
|
||||||
path = 3rdpart/media-server
|
path = 3rdpart/media-server
|
||||||
url = https://gitee.com/xiahcu/media-server
|
url = ../media-server
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ It is recommended to compile on Ubuntu or MacOS,compiling on windows is cumber
|
||||||
### Before build
|
### Before build
|
||||||
- **You must use git to clone the complete code. Do not download the source code by downloading zip package. Otherwise, the sub-module code will not be downloaded by default.You can do it like this:**
|
- **You must use git to clone the complete code. Do not download the source code by downloading zip package. Otherwise, the sub-module code will not be downloaded by default.You can do it like this:**
|
||||||
```
|
```
|
||||||
git clone https://github.com/zlmediakit/ZLMediaKit.git
|
git clone https://github.com/xiongziliang/ZLMediaKit.git
|
||||||
cd ZLMediaKit
|
cd ZLMediaKit
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -98,16 +98,15 @@ API_EXPORT void API_CALL mk_media_input_h265(mk_media ctx, void *data, int len,
|
||||||
*/
|
*/
|
||||||
API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts);
|
API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, uint32_t dts, void *adts);
|
||||||
|
|
||||||
#ifdef ENABLE_FAAC
|
|
||||||
/**
|
/**
|
||||||
* 输入单帧PCM音频
|
* 输入单帧PCM音频,启用ENABLE_FAAC编译时,该函数才有效
|
||||||
* @param ctx 对象指针
|
* @param ctx 对象指针
|
||||||
* @param data 单帧PCM数据
|
* @param data 单帧PCM数据
|
||||||
* @param len 单帧PCM数据字节数
|
* @param len 单帧PCM数据字节数
|
||||||
* @param dts 时间戳,毫秒
|
* @param dts 时间戳,毫秒
|
||||||
*/
|
*/
|
||||||
API_EXPORT void API_CALL mk_media_input_PCM(mk_media ctx, void *Data, int len, uint32_t pts);
|
API_EXPORT void API_CALL mk_media_input_pcm(mk_media ctx, void *data, int len, uint32_t pts);
|
||||||
#endif //ENABLE_FAAC
|
|
||||||
/**
|
/**
|
||||||
* 输入单帧G711音频
|
* 输入单帧G711音频
|
||||||
* @param ctx 对象指针
|
* @param ctx 对象指针
|
||||||
|
|
|
||||||
|
|
@ -157,14 +157,15 @@ API_EXPORT void API_CALL mk_media_input_aac(mk_media ctx, void *data, int len, u
|
||||||
(*obj)->getChannel()->inputAAC((char *) data, len, dts, (char *) adts);
|
(*obj)->getChannel()->inputAAC((char *) data, len, dts, (char *) adts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
API_EXPORT void API_CALL mk_media_input_pcm(mk_media ctx, void *data , int len, uint32_t pts){
|
||||||
#ifdef ENABLE_FAAC
|
#ifdef ENABLE_FAAC
|
||||||
API_EXPORT void API_CALL mk_media_input_PCM(mk_media ctx, void *data , int len, uint32_t pts)
|
|
||||||
{
|
|
||||||
assert(ctx && data && len > 0);
|
assert(ctx && data && len > 0);
|
||||||
MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx;
|
MediaHelper::Ptr* obj = (MediaHelper::Ptr*) ctx;
|
||||||
(*obj)->getChannel()->inputPCM((char*)data, len, pts);
|
(*obj)->getChannel()->inputPCM((char*)data, len, pts);
|
||||||
}
|
#else
|
||||||
|
WarnL << "aac编码未启用,该方法无效,编译时请打开ENABLE_FAAC选项";
|
||||||
#endif //ENABLE_FAAC
|
#endif //ENABLE_FAAC
|
||||||
|
}
|
||||||
|
|
||||||
API_EXPORT void API_CALL mk_media_input_g711(mk_media ctx, void* data, int len, uint32_t dts){
|
API_EXPORT void API_CALL mk_media_input_g711(mk_media ctx, void* data, int len, uint32_t dts){
|
||||||
assert(ctx && data && len > 0);
|
assert(ctx && data && len > 0);
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,8 @@ rootPath=./www
|
||||||
sendBufSize=65536
|
sendBufSize=65536
|
||||||
#https服务器监听端口
|
#https服务器监听端口
|
||||||
sslport=443
|
sslport=443
|
||||||
|
#是否显示文件夹菜单,开启后可以浏览文件夹
|
||||||
|
dirMenu=1
|
||||||
|
|
||||||
[multicast]
|
[multicast]
|
||||||
#rtp组播截止组播ip地址
|
#rtp组播截止组播ip地址
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,8 @@ bool DtsGenerator::getDts_l(uint32_t pts, uint32_t &dts){
|
||||||
_sorter_max_size = _frames_since_last_max_pts;
|
_sorter_max_size = _frames_since_last_max_pts;
|
||||||
//我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计)
|
//我们记录P帧间时间间隔(也就是多个B帧时间戳增量累计)
|
||||||
_dts_pts_offset = (pts - _last_max_pts);
|
_dts_pts_offset = (pts - _last_max_pts);
|
||||||
|
//除以2,防止dts大于pts
|
||||||
|
_dts_pts_offset /= 2;
|
||||||
}
|
}
|
||||||
//遇到P帧或关键帧,连续B帧计数清零
|
//遇到P帧或关键帧,连续B帧计数清零
|
||||||
_frames_since_last_max_pts = 0;
|
_frames_since_last_max_pts = 0;
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,15 @@ const string kCharSet = HTTP_FIELD"charSet";
|
||||||
const string kRootPath = HTTP_FIELD"rootPath";
|
const string kRootPath = HTTP_FIELD"rootPath";
|
||||||
//http 404错误提示内容
|
//http 404错误提示内容
|
||||||
const string kNotFound = HTTP_FIELD"notFound";
|
const string kNotFound = HTTP_FIELD"notFound";
|
||||||
|
//是否显示文件夹菜单
|
||||||
|
const string kDirMenu = HTTP_FIELD"dirMenu";
|
||||||
|
|
||||||
onceToken token([](){
|
onceToken token([](){
|
||||||
mINI::Instance()[kSendBufSize] = 64 * 1024;
|
mINI::Instance()[kSendBufSize] = 64 * 1024;
|
||||||
mINI::Instance()[kMaxReqSize] = 4*1024;
|
mINI::Instance()[kMaxReqSize] = 4*1024;
|
||||||
mINI::Instance()[kKeepAliveSecond] = 15;
|
mINI::Instance()[kKeepAliveSecond] = 15;
|
||||||
|
mINI::Instance()[kDirMenu] = true;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
mINI::Instance()[kCharSet] = "gb2312";
|
mINI::Instance()[kCharSet] = "gb2312";
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -193,6 +193,8 @@ extern const string kCharSet;
|
||||||
extern const string kRootPath;
|
extern const string kRootPath;
|
||||||
//http 404错误提示内容
|
//http 404错误提示内容
|
||||||
extern const string kNotFound;
|
extern const string kNotFound;
|
||||||
|
//是否显示文件夹菜单
|
||||||
|
extern const string kDirMenu;
|
||||||
}//namespace Http
|
}//namespace Http
|
||||||
|
|
||||||
////////////SHELL配置///////////
|
////////////SHELL配置///////////
|
||||||
|
|
|
||||||
|
|
@ -138,14 +138,18 @@ public:
|
||||||
if (_cfg.empty()) {
|
if (_cfg.empty()) {
|
||||||
//未获取到aac_cfg信息
|
//未获取到aac_cfg信息
|
||||||
if (frame->prefixSize()) {
|
if (frame->prefixSize()) {
|
||||||
//7个字节的adts头
|
//根据7个字节的adts头生成aac config
|
||||||
_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
|
_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
|
||||||
onReady();
|
onReady();
|
||||||
} else {
|
} else {
|
||||||
WarnL << "无法获取adts头!";
|
WarnL << "无法获取adts头!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AudioTrack::inputFrame(frame);
|
|
||||||
|
if (frame->size() > frame->prefixSize()) {
|
||||||
|
//除adts头外,有实际负载
|
||||||
|
AudioTrack::inputFrame(frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,10 @@ static string getAacCfg(const RtmpPacket &thiz) {
|
||||||
bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
||||||
if (pkt->isCfgFrame()) {
|
if (pkt->isCfgFrame()) {
|
||||||
_aac_cfg = getAacCfg(*pkt);
|
_aac_cfg = getAacCfg(*pkt);
|
||||||
|
onGetAAC(nullptr, 0, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_aac_cfg.empty()) {
|
if (!_aac_cfg.empty()) {
|
||||||
onGetAAC(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2, pkt->timeStamp);
|
onGetAAC(pkt->strBuf.data() + 2, pkt->strBuf.size() - 2, pkt->timeStamp);
|
||||||
}
|
}
|
||||||
|
|
@ -42,7 +44,6 @@ bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
||||||
|
|
||||||
void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) {
|
void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) {
|
||||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||||
|
|
||||||
//生成adts头
|
//生成adts头
|
||||||
char adts_header[32] = {0};
|
char adts_header[32] = {0};
|
||||||
auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header));
|
auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header));
|
||||||
|
|
@ -54,12 +55,16 @@ void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) {
|
||||||
frame->_prefix_size = 0;
|
frame->_prefix_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//追加负载数据
|
if(len > 0){
|
||||||
frame->_buffer.append(data, len);
|
//追加负载数据
|
||||||
frame->_dts = stamp;
|
frame->_buffer.append(data, len);
|
||||||
|
frame->_dts = stamp;
|
||||||
|
}
|
||||||
|
|
||||||
//写入环形缓存
|
if(size > 0 || len > 0){
|
||||||
RtmpCodec::inputFrame(frame);
|
//有adts头或者实际aac负载
|
||||||
|
RtmpCodec::inputFrame(frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -243,9 +243,8 @@ RtmpCodec::Ptr Factory::getRtmpCodecByTrack(const Track::Ptr &track, bool is_enc
|
||||||
|
|
||||||
AMFValue Factory::getAmfByCodecId(CodecId codecId) {
|
AMFValue Factory::getAmfByCodecId(CodecId codecId) {
|
||||||
switch (codecId){
|
switch (codecId){
|
||||||
//此处用string标明rtmp编码类型目的是为了兼容某些android系统
|
case CodecAAC: return AMFValue(FLV_CODEC_AAC);
|
||||||
case CodecAAC: return AMFValue("mp4a");
|
case CodecH264: return AMFValue(FLV_CODEC_H264);
|
||||||
case CodecH264: return AMFValue("avc1");
|
|
||||||
case CodecH265: return AMFValue(FLV_CODEC_H265);
|
case CodecH265: return AMFValue(FLV_CODEC_H265);
|
||||||
case CodecG711A: return AMFValue(FLV_CODEC_G711A);
|
case CodecG711A: return AMFValue(FLV_CODEC_G711A);
|
||||||
case CodecG711U: return AMFValue(FLV_CODEC_G711U);
|
case CodecG711U: return AMFValue(FLV_CODEC_G711U);
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,11 @@ static string searchIndexFile(const string &dir){
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool makeFolderMenu(const string &httpPath, const string &strFullPath, string &strRet) {
|
static bool makeFolderMenu(const string &httpPath, const string &strFullPath, string &strRet) {
|
||||||
|
GET_CONFIG(bool, dirMenu, Http::kDirMenu);
|
||||||
|
if(!dirMenu){
|
||||||
|
//不允许浏览文件夹
|
||||||
|
return false;
|
||||||
|
}
|
||||||
string strPathPrefix(strFullPath);
|
string strPathPrefix(strFullPath);
|
||||||
string last_dir_name;
|
string last_dir_name;
|
||||||
if(strPathPrefix.back() == '/'){
|
if(strPathPrefix.back() == '/'){
|
||||||
|
|
|
||||||
|
|
@ -257,8 +257,8 @@ void RtmpSession::sendPlayResponse(const string &err,const RtmpMediaSource::Ptr
|
||||||
invoke.clear();
|
invoke.clear();
|
||||||
invoke << "onMetaData" << metadata;
|
invoke << "onMetaData" << metadata;
|
||||||
sendResponse(MSG_DATA, invoke.data());
|
sendResponse(MSG_DATA, invoke.data());
|
||||||
auto duration = metadata["duration"].as_number();
|
auto duration = metadata["duration"];
|
||||||
if(duration > 0){
|
if(duration && duration.as_number() > 0){
|
||||||
//这是点播,使用绝对时间戳
|
//这是点播,使用绝对时间戳
|
||||||
_stamp[0].setPlayBack();
|
_stamp[0].setPlayBack();
|
||||||
_stamp[1].setPlayBack();
|
_stamp[1].setPlayBack();
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,11 @@ void DecoderImp::onDecode(int stream,int codecid,int flags,int64_t pts,int64_t d
|
||||||
}
|
}
|
||||||
|
|
||||||
case PSI_STREAM_AAC: {
|
case PSI_STREAM_AAC: {
|
||||||
|
uint8_t *ptr = (uint8_t *)data;
|
||||||
|
if(!(bytes > 7 && ptr[0] == 0xFF && (ptr[1] & 0xF0) == 0xF0)){
|
||||||
|
//这不是aac
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!_codecid_audio) {
|
if (!_codecid_audio) {
|
||||||
//获取到音频
|
//获取到音频
|
||||||
_codecid_audio = codecid;
|
_codecid_audio = codecid;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "Decoder.h"
|
|
||||||
#include "Common/MediaSink.h"
|
#include "Common/MediaSink.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
|
||||||
|
|
@ -73,11 +73,6 @@ RtpProcess::RtpProcess(uint32_t ssrc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RtpProcess::~RtpProcess() {
|
RtpProcess::~RtpProcess() {
|
||||||
DebugP(this);
|
|
||||||
if (_addr) {
|
|
||||||
delete _addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t duration = (_last_rtp_time.createdTime() - _last_rtp_time.elapsedTime()) / 1000;
|
uint64_t duration = (_last_rtp_time.createdTime() - _last_rtp_time.elapsedTime()) / 1000;
|
||||||
WarnP(this) << "RTP推流器("
|
WarnP(this) << "RTP推流器("
|
||||||
<< _media_info._vhost << "/"
|
<< _media_info._vhost << "/"
|
||||||
|
|
@ -90,6 +85,11 @@ RtpProcess::~RtpProcess() {
|
||||||
if (_total_bytes > iFlowThreshold * 1024) {
|
if (_total_bytes > iFlowThreshold * 1024) {
|
||||||
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, false, static_cast<SockInfo &>(*this));
|
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _total_bytes, duration, false, static_cast<SockInfo &>(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_addr) {
|
||||||
|
delete _addr;
|
||||||
|
_addr = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RtpProcess::inputRtp(const Socket::Ptr &sock, const char *data, int data_len,const struct sockaddr *addr,uint32_t *dts_out) {
|
bool RtpProcess::inputRtp(const Socket::Ptr &sock, const char *data, int data_len,const struct sockaddr *addr,uint32_t *dts_out) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue