mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-23 03:10:04 +08:00
commit
5704d8171c
@ -1 +1 @@
|
|||||||
Subproject commit 91246bb01475c7336040a4b7ec35d0584887f365
|
Subproject commit b7485c4b48b277bfaba2ad930cf1f30e2806299c
|
@ -39,6 +39,7 @@ filePath=/Users/xzl/git/ZLMediaKit/release/mac/Release/httpRoot
|
|||||||
#hls最大切片时间
|
#hls最大切片时间
|
||||||
segDur=3
|
segDur=3
|
||||||
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个)
|
#m3u8索引中,hls保留切片个数(实际保留切片个数大2~3个)
|
||||||
|
#如果设置为0,则不删除切片,而是保存为点播
|
||||||
segNum=3
|
segNum=3
|
||||||
|
|
||||||
[hook]
|
[hook]
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#define IPTV_PROCESS_H
|
#define IPTV_PROCESS_H
|
||||||
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -77,12 +77,15 @@ const string kStreamNoneReaderDelayMS = GENERAL_FIELD"streamNoneReaderDelayMS";
|
|||||||
const string kMaxStreamWaitTimeMS = GENERAL_FIELD"maxStreamWaitMS";
|
const string kMaxStreamWaitTimeMS = GENERAL_FIELD"maxStreamWaitMS";
|
||||||
const string kEnableVhost = GENERAL_FIELD"enableVhost";
|
const string kEnableVhost = GENERAL_FIELD"enableVhost";
|
||||||
const string kUltraLowDelay = GENERAL_FIELD"ultraLowDelay";
|
const string kUltraLowDelay = GENERAL_FIELD"ultraLowDelay";
|
||||||
|
const string kAddMuteAudio = GENERAL_FIELD"addMuteAudio";
|
||||||
|
|
||||||
onceToken token([](){
|
onceToken token([](){
|
||||||
mINI::Instance()[kFlowThreshold] = 1024;
|
mINI::Instance()[kFlowThreshold] = 1024;
|
||||||
mINI::Instance()[kStreamNoneReaderDelayMS] = 5 * 1000;
|
mINI::Instance()[kStreamNoneReaderDelayMS] = 5 * 1000;
|
||||||
mINI::Instance()[kMaxStreamWaitTimeMS] = 5 * 1000;
|
mINI::Instance()[kMaxStreamWaitTimeMS] = 5 * 1000;
|
||||||
mINI::Instance()[kEnableVhost] = 1;
|
mINI::Instance()[kEnableVhost] = 1;
|
||||||
mINI::Instance()[kUltraLowDelay] = 1;
|
mINI::Instance()[kUltraLowDelay] = 1;
|
||||||
|
mINI::Instance()[kAddMuteAudio] = 1;
|
||||||
},nullptr);
|
},nullptr);
|
||||||
|
|
||||||
}//namespace General
|
}//namespace General
|
||||||
|
@ -177,6 +177,8 @@ extern const string kMaxStreamWaitTimeMS;
|
|||||||
extern const string kEnableVhost;
|
extern const string kEnableVhost;
|
||||||
//超低延时模式,默认打开,打开后会降低延时但是转发性能会稍差
|
//超低延时模式,默认打开,打开后会降低延时但是转发性能会稍差
|
||||||
extern const string kUltraLowDelay;
|
extern const string kUltraLowDelay;
|
||||||
|
//拉流代理时是否添加静音音频
|
||||||
|
extern const string kAddMuteAudio;
|
||||||
}//namespace General
|
}//namespace General
|
||||||
|
|
||||||
|
|
||||||
@ -276,7 +278,7 @@ extern const string kFileRepeat;
|
|||||||
namespace Hls {
|
namespace Hls {
|
||||||
//HLS切片时长,单位秒
|
//HLS切片时长,单位秒
|
||||||
extern const string kSegmentDuration;
|
extern const string kSegmentDuration;
|
||||||
//HLS切片个数
|
//HLS切片个数,如果设置为0,则不删除切片,而是保存为点播
|
||||||
extern const string kSegmentNum;
|
extern const string kSegmentNum;
|
||||||
//HLS文件写缓存大小
|
//HLS文件写缓存大小
|
||||||
extern const string kFileBufSize;
|
extern const string kFileBufSize;
|
||||||
|
@ -60,16 +60,16 @@ Track::Ptr Factory::getTrackBySdp(const SdpTrack::Ptr &track) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(track->_codec.data(), "h264") == 0) {
|
if (strcasecmp(track->_codec.data(), "h264") == 0) {
|
||||||
string sps_pps = FindField(track->_fmtp.data(), "sprop-parameter-sets=", nullptr);
|
auto map = Parser::parseArgs(track->_fmtp," ","=");
|
||||||
|
for(auto &pr : map){
|
||||||
|
trim(pr.second," ;");
|
||||||
|
}
|
||||||
|
auto sps_pps = map["sprop-parameter-sets"];
|
||||||
if(sps_pps.empty()){
|
if(sps_pps.empty()){
|
||||||
return std::make_shared<H264Track>();
|
return std::make_shared<H264Track>();
|
||||||
}
|
}
|
||||||
string base64_SPS = FindField(sps_pps.data(), NULL, ",");
|
string base64_SPS = FindField(sps_pps.data(), NULL, ",");
|
||||||
string base64_PPS = FindField(sps_pps.data(), ",", NULL);
|
string base64_PPS = FindField(sps_pps.data(), ",", NULL);
|
||||||
if(base64_PPS.back() == ';'){
|
|
||||||
base64_PPS.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sps = decodeBase64(base64_SPS);
|
auto sps = decodeBase64(base64_SPS);
|
||||||
auto pps = decodeBase64(base64_PPS);
|
auto pps = decodeBase64(base64_PPS);
|
||||||
return std::make_shared<H264Track>(sps,pps,0,0);
|
return std::make_shared<H264Track>(sps,pps,0,0);
|
||||||
|
@ -28,7 +28,8 @@
|
|||||||
namespace mediakit {
|
namespace mediakit {
|
||||||
|
|
||||||
HlsMaker::HlsMaker(float seg_duration, uint32_t seg_number) {
|
HlsMaker::HlsMaker(float seg_duration, uint32_t seg_number) {
|
||||||
seg_number = MAX(1,seg_number);
|
//最小允许设置为0,0个切片代表点播
|
||||||
|
seg_number = MAX(0,seg_number);
|
||||||
seg_duration = MAX(1,seg_duration);
|
seg_duration = MAX(1,seg_duration);
|
||||||
_seg_number = seg_number;
|
_seg_number = seg_number;
|
||||||
_seg_duration = seg_duration;
|
_seg_duration = seg_duration;
|
||||||
@ -37,12 +38,9 @@ HlsMaker::HlsMaker(float seg_duration, uint32_t seg_number) {
|
|||||||
HlsMaker::~HlsMaker() {
|
HlsMaker::~HlsMaker() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PRINT(...) file_size += snprintf(file_content + file_size,sizeof(file_content) - file_size, ##__VA_ARGS__)
|
|
||||||
|
|
||||||
void HlsMaker::makeIndexFile(bool eof) {
|
void HlsMaker::makeIndexFile(bool eof) {
|
||||||
char file_content[4 * 1024];
|
char file_content[1024];
|
||||||
int file_size = 0;
|
|
||||||
|
|
||||||
int maxSegmentDuration = 0;
|
int maxSegmentDuration = 0;
|
||||||
for (auto &tp : _seg_dur_list) {
|
for (auto &tp : _seg_dur_list) {
|
||||||
int dur = std::get<0>(tp);
|
int dur = std::get<0>(tp);
|
||||||
@ -50,7 +48,10 @@ void HlsMaker::makeIndexFile(bool eof) {
|
|||||||
maxSegmentDuration = dur;
|
maxSegmentDuration = dur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PRINT("#EXTM3U\n"
|
|
||||||
|
string m3u8;
|
||||||
|
snprintf(file_content,sizeof(file_content),
|
||||||
|
"#EXTM3U\n"
|
||||||
"#EXT-X-VERSION:3\n"
|
"#EXT-X-VERSION:3\n"
|
||||||
"#EXT-X-ALLOW-CACHE:NO\n"
|
"#EXT-X-ALLOW-CACHE:NO\n"
|
||||||
"#EXT-X-TARGETDURATION:%u\n"
|
"#EXT-X-TARGETDURATION:%u\n"
|
||||||
@ -58,14 +59,18 @@ void HlsMaker::makeIndexFile(bool eof) {
|
|||||||
(maxSegmentDuration + 999) / 1000,
|
(maxSegmentDuration + 999) / 1000,
|
||||||
_file_index);
|
_file_index);
|
||||||
|
|
||||||
|
m3u8.assign(file_content);
|
||||||
|
|
||||||
for (auto &tp : _seg_dur_list) {
|
for (auto &tp : _seg_dur_list) {
|
||||||
PRINT("#EXTINF:%.3f,\n%s\n", std::get<0>(tp) / 1000.0, std::get<1>(tp).data());
|
snprintf(file_content,sizeof(file_content), "#EXTINF:%.3f,\n%s\n", std::get<0>(tp) / 1000.0, std::get<1>(tp).data());
|
||||||
|
m3u8.append(file_content);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eof) {
|
if (eof) {
|
||||||
PRINT("#EXT-X-ENDLIST\n");
|
snprintf(file_content,sizeof(file_content),"#EXT-X-ENDLIST\n");
|
||||||
|
m3u8.append(file_content);
|
||||||
}
|
}
|
||||||
onWriteHls(file_content, file_size);
|
onWriteHls(m3u8.data(), m3u8.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -75,6 +80,10 @@ void HlsMaker::inputData(void *data, uint32_t len, uint32_t timestamp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HlsMaker::delOldFile() {
|
void HlsMaker::delOldFile() {
|
||||||
|
if(_seg_number == 0){
|
||||||
|
//如果设置为保留0个切片,则认为是保存为点播
|
||||||
|
return;
|
||||||
|
}
|
||||||
//在hls m3u8索引文件中,我们保存的切片个数跟_seg_number相关设置一致
|
//在hls m3u8索引文件中,我们保存的切片个数跟_seg_number相关设置一致
|
||||||
if (_file_index >= _seg_number + 2) {
|
if (_file_index >= _seg_number + 2) {
|
||||||
_seg_dur_list.pop_front();
|
_seg_dur_list.pop_front();
|
||||||
|
@ -81,13 +81,18 @@ protected:
|
|||||||
* @param len
|
* @param len
|
||||||
*/
|
*/
|
||||||
virtual void onWriteHls(const char *data, int len) = 0;
|
virtual void onWriteHls(const char *data, int len) = 0;
|
||||||
private:
|
|
||||||
|
/**
|
||||||
|
* 生成m3u8文件
|
||||||
|
* @param eof true代表点播
|
||||||
|
*/
|
||||||
|
void makeIndexFile(bool eof = false);
|
||||||
void delOldFile();
|
void delOldFile();
|
||||||
void addNewFile(uint32_t timestamp);
|
void addNewFile(uint32_t timestamp);
|
||||||
void makeIndexFile(bool eof = false);
|
protected:
|
||||||
|
uint32_t _seg_number = 0;
|
||||||
private:
|
private:
|
||||||
float _seg_duration = 0;
|
float _seg_duration = 0;
|
||||||
uint32_t _seg_number = 0;
|
|
||||||
uint64_t _file_index = 0;
|
uint64_t _file_index = 0;
|
||||||
Ticker _ticker;
|
Ticker _ticker;
|
||||||
string _last_file_name;
|
string _last_file_name;
|
||||||
|
@ -46,9 +46,13 @@ HlsMakerImp::HlsMakerImp(const string &m3u8_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
HlsMakerImp::~HlsMakerImp() {
|
HlsMakerImp::~HlsMakerImp() {
|
||||||
_file.reset();
|
//录制完了
|
||||||
|
makeIndexFile(true);
|
||||||
|
if(_seg_number){
|
||||||
|
//hls直播才删除文件
|
||||||
File::delete_file(_path_prefix.data());
|
File::delete_file(_path_prefix.data());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string HlsMakerImp::onOpenFile(int index) {
|
string HlsMakerImp::onOpenFile(int index) {
|
||||||
auto full_path = fullPath(index);
|
auto full_path = fullPath(index);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "Http/HttpSession.h"
|
#include "Http/HttpSession.h"
|
||||||
#include "Extension/AAC.h"
|
#include "Extension/AAC.h"
|
||||||
#include "Extension/H264.h"
|
#include "Extension/H264.h"
|
||||||
|
#include "Thread/WorkThreadPool.h"
|
||||||
|
|
||||||
using namespace toolkit;
|
using namespace toolkit;
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ namespace mediakit {
|
|||||||
|
|
||||||
#ifdef ENABLE_MP4V2
|
#ifdef ENABLE_MP4V2
|
||||||
MediaReader::MediaReader(const string &strVhost,const string &strApp, const string &strId,const string &filePath ) {
|
MediaReader::MediaReader(const string &strVhost,const string &strApp, const string &strId,const string &filePath ) {
|
||||||
_poller = EventPollerPool::Instance().getPoller();
|
_poller = WorkThreadPool::Instance().getPoller();
|
||||||
auto strFileName = filePath;
|
auto strFileName = filePath;
|
||||||
if(strFileName.empty()){
|
if(strFileName.empty()){
|
||||||
GET_CONFIG(string,recordPath,Record::kFilePath);
|
GET_CONFIG(string,recordPath,Record::kFilePath);
|
||||||
|
@ -244,13 +244,16 @@ void PlayerProxy::onPlaySuccess() {
|
|||||||
videoTrack->addDelegate(_mediaMuxer);
|
videoTrack->addDelegate(_mediaMuxer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//是否添加静音音频
|
||||||
|
GET_CONFIG(bool,addMuteAudio,General::kAddMuteAudio);
|
||||||
|
|
||||||
auto audioTrack = getTrack(TrackAudio, false);
|
auto audioTrack = getTrack(TrackAudio, false);
|
||||||
if(audioTrack){
|
if(audioTrack){
|
||||||
//添加音频
|
//添加音频
|
||||||
_mediaMuxer->addTrack(audioTrack);
|
_mediaMuxer->addTrack(audioTrack);
|
||||||
//音频数据写入_mediaMuxer
|
//音频数据写入_mediaMuxer
|
||||||
audioTrack->addDelegate(_mediaMuxer);
|
audioTrack->addDelegate(_mediaMuxer);
|
||||||
}else if(videoTrack){
|
}else if(addMuteAudio && videoTrack){
|
||||||
//没有音频信息,产生一个静音音频
|
//没有音频信息,产生一个静音音频
|
||||||
MuteAudioMaker::Ptr audioMaker = std::make_shared<MuteAudioMaker>();
|
MuteAudioMaker::Ptr audioMaker = std::make_shared<MuteAudioMaker>();
|
||||||
//videoTrack把数据写入MuteAudioMaker
|
//videoTrack把数据写入MuteAudioMaker
|
||||||
|
Loading…
Reference in New Issue
Block a user