Commit c76930e3 by xiongziliang

支持http-ts/websocket-ts直播

parent f84981dc
......@@ -13,7 +13,7 @@
## 项目特点
- 基于C++11开发,避免使用裸指针,代码稳定可靠,性能优越。
- 支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV/GB28181/MP4),支持协议互转。
- 支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV/GB28181/HTTP-TS/Websocket-TS/MP4),支持协议互转。
- 使用多路复用/多线程/异步网络IO模式开发,并发性能优越,支持海量客户端连接。
- 代码经过长期大量的稳定性、性能测试,已经在线上商用验证已久。
- 支持linux、macos、ios、android、windows全平台。
......@@ -59,6 +59,10 @@
- 通过cookie追踪技术,可以模拟HLS播放为长连接,可以实现HLS按需拉流、播放统计等业务
- 支持HLS播发器,支持拉流HLS转rtsp/rtmp/mp4
- 支持H264/H265/AAC/G711/OPUS编码
- TS
- 支持http[s]-ts直播
- 支持ws[s]-ts直播
- HTTP[S]与WebSocket
- 服务器支持`目录索引生成`,`文件下载`,`表单提交请求`
......
......@@ -11,7 +11,7 @@
## Why ZLMediaKit?
- Developed based on C++ 11, the code is stable and reliable, avoiding the use of raw pointers, cross-platform porting is simple and convenient, and the code is clear and concise.
- Support rich streaming media protocols(`RTSP/RTMP/HLS/HTTP-FLV/Websocket-flv`),and support Inter-protocol conversion.
- Support rich streaming media protocols(`RTSP/RTMP/HLS/HTTP-FLV/WebSocket-flv/HTTP-TS/WebSocket-TS`),and support Inter-protocol conversion.
- Multiplexing asynchronous network IO based on epoll and multi thread,extreme performance.
- Well performance and stable test,can be used commercially.
- Support linux, macos, ios, android, Windows Platforms.
......@@ -31,7 +31,7 @@
- RTMP[S]
- RTMP[S] server,support player and pusher.
- RTMP[S] player and pusher.
- Support HTTP-FLV player.
- Support HTTP-FLV/WebSocket-FLV sever.
- H265/H264/AAC/G711/OPUS codec.
- Recorded as flv or mp4.
- Vod of mp4.
......@@ -41,6 +41,9 @@
- RTSP RTMP can be converted into HLS,built-in HTTP server.
- Play authentication based on cookie.
- Support HLS player, support streaming HLS proxy to RTSP / RTMP / MP4.
- TS
- Support HTTP-TS/WebSocket-TS sever.
- HTTP[S]
- HTTP server,suppor directory meun、RESTful http api.
......
......@@ -32,6 +32,8 @@ MultiMuxerPrivate::MultiMuxerPrivate(const string &vhost, const string &app, con
if (enable_mp4) {
_mp4 = Recorder::createRecorder(Recorder::type_mp4, vhost, app, stream);
}
_ts = std::make_shared<TSMediaSourceMuxer>(vhost, app, stream);
}
void MultiMuxerPrivate::resetTracks() {
......@@ -41,6 +43,9 @@ void MultiMuxerPrivate::resetTracks() {
if (_rtsp) {
_rtsp->resetTracks();
}
if (_ts) {
_ts->resetTracks();
}
//拷贝智能指针,目的是为了防止跨线程调用设置录像相关api导致的线程竞争问题
auto hls = _hls;
......@@ -62,6 +67,9 @@ void MultiMuxerPrivate::setMediaListener(const std::weak_ptr<MediaSourceEvent> &
if (_rtsp) {
_rtsp->setListener(listener);
}
if (_ts) {
_ts->setListener(listener);
}
auto hls = _hls;
if (hls) {
hls->setListener(listener);
......@@ -70,7 +78,10 @@ void MultiMuxerPrivate::setMediaListener(const std::weak_ptr<MediaSourceEvent> &
int MultiMuxerPrivate::totalReaderCount() const {
auto hls = _hls;
return (_rtsp ? _rtsp->readerCount() : 0) + (_rtmp ? _rtmp->readerCount() : 0) + (hls ? hls->readerCount() : 0);
return (_rtsp ? _rtsp->readerCount() : 0) +
(_rtmp ? _rtmp->readerCount() : 0) +
(_ts ? _ts->readerCount() : 0) +
(hls ? hls->readerCount() : 0) ;
}
static std::shared_ptr<MediaSinkInterface> makeRecorder(const vector<Track::Ptr> &tracks, Recorder::type type, const string &custom_path, MediaSource &sender){
......@@ -145,6 +156,9 @@ void MultiMuxerPrivate::onTrackReady(const Track::Ptr &track) {
if (_rtsp) {
_rtsp->addTrack(track);
}
if (_ts) {
_ts->addTrack(track);
}
//拷贝智能指针,目的是为了防止跨线程调用设置录像相关api导致的线程竞争问题
auto hls = _hls;
......@@ -161,6 +175,7 @@ bool MultiMuxerPrivate::isEnabled(){
auto hls = _hls;
return (_rtmp ? _rtmp->isEnabled() : false) ||
(_rtsp ? _rtsp->isEnabled() : false) ||
(_ts ? _ts->isEnabled() : false) ||
(hls ? hls->isEnabled() : false) || _mp4;
}
......@@ -171,6 +186,10 @@ void MultiMuxerPrivate::onTrackFrame(const Frame::Ptr &frame) {
if (_rtsp) {
_rtsp->inputFrame(frame);
}
if (_ts) {
_ts->inputFrame(frame);
}
//拷贝智能指针,目的是为了防止跨线程调用设置录像相关api导致的线程竞争问题
//此处使用智能指针拷贝来确保线程安全,比互斥锁性能更优
auto hls = _hls;
......
......@@ -18,6 +18,7 @@
#include "Record/HlsMediaSource.h"
#include "Rtsp/RtspMediaSourceMuxer.h"
#include "Rtmp/RtmpMediaSourceMuxer.h"
#include "TS/TSMediaSourceMuxer.h"
namespace mediakit{
......@@ -56,6 +57,7 @@ private:
RtspMediaSourceMuxer::Ptr _rtsp;
HlsRecorder::Ptr _hls;
MediaSinkInterface::Ptr _mp4;
TSMediaSourceMuxer::Ptr _ts;
std::weak_ptr<MediaSourceEvent> _listener;
};
......
......@@ -47,6 +47,7 @@ bool loadIniConfig(const char *ini_path = nullptr);
#define RTSP_SCHEMA "rtsp"
#define RTMP_SCHEMA "rtmp"
#define HLS_SCHEMA "hls"
#define TS_SCHEMA "ts"
#define DEFAULT_VHOST "__defaultVhost__"
////////////广播名称///////////
......
......@@ -19,6 +19,7 @@
#include "WebSocketSplitter.h"
#include "HttpCookieManager.h"
#include "HttpFileManager.h"
#include "TS/TSMediaSource.h"
using namespace std;
using namespace toolkit;
......@@ -104,7 +105,11 @@ private:
void Handle_Req_POST(int64_t &content_len);
void Handle_Req_HEAD(int64_t &content_len);
bool checkLiveFlvStream(const function<void()> &cb = nullptr);
bool checkLiveStream(const string &schema, const string &url_suffix, const function<void(const MediaSource::Ptr &src)> &cb);
bool checkLiveStreamFlv(const function<void()> &cb = nullptr);
bool checkLiveStreamTS(const function<void()> &cb = nullptr);
bool checkWebSocket();
bool emitHttpEvent(bool doInvoke);
void urlDecode(Parser &parser);
......@@ -117,17 +122,17 @@ private:
void setSocketFlags();
private:
bool _is_live_stream = false;
bool _live_over_websocket = false;
//消耗的总流量
uint64_t _total_bytes_usage = 0;
string _origin;
Parser _parser;
Ticker _ticker;
//消耗的总流量
uint64_t _ui64TotalBytes = 0;
//flv over http
MediaInfo _mediaInfo;
TSMediaSource::RingType::RingReader::Ptr _ts_reader;
//处理content数据的callback
function<bool (const char *data,uint64_t len) > _contentCallBack;
bool _flv_over_websocket = false;
bool _is_flv_stream = false;
};
......
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_TSMEDIASOURCE_H
#define ZLMEDIAKIT_TSMEDIASOURCE_H
#include "Common/MediaSource.h"
using namespace toolkit;
#define TS_GOP_SIZE 512
namespace mediakit {
//TS直播数据包
class TSPacket : public BufferRaw{
public:
using Ptr = std::shared_ptr<TSPacket>;
template<typename ...ARGS>
TSPacket(ARGS && ...args) : BufferRaw(std::forward<ARGS>(args)...) {};
~TSPacket() override = default;
public:
uint32_t time_stamp = 0;
};
//TS直播合并写策略类
class TSFlushPolicy : public FlushPolicy{
public:
TSFlushPolicy() = default;
~TSFlushPolicy() = default;
uint32_t getStamp(const TSPacket::Ptr &packet) {
return packet->time_stamp;
}
};
//TS直播源
class TSMediaSource : public MediaSource, public RingDelegate<TSPacket::Ptr>, public PacketCache<TSPacket, TSFlushPolicy>{
public:
using PoolType = ResourcePool<TSPacket>;
using Ptr = std::shared_ptr<TSMediaSource>;
using RingDataType = std::shared_ptr<List<TSPacket::Ptr> >;
using RingType = RingBuffer<RingDataType>;
TSMediaSource(const string &vhost,
const string &app,
const string &stream_id,
int ring_size = TS_GOP_SIZE) : MediaSource(TS_SCHEMA, vhost, app, stream_id), _ring_size(ring_size) {}
~TSMediaSource() override = default;
/**
* 获取媒体源的环形缓冲
*/
const RingType::Ptr &getRing() const {
return _ring;
}
/**
* 获取播放器个数
*/
int readerCount() override {
return _ring ? _ring->readerCount() : 0;
}
/**
* 输入TS包
* @param packet TS包
* @param key 是否为关键帧第一个包
*/
void onWrite(const TSPacket::Ptr &packet, bool key) override {
if (!_ring) {
createRing();
}
if (key) {
_have_video = true;
}
PacketCache<TSPacket, TSFlushPolicy>::inputPacket(true, packet, key);
}
/**
* 情况GOP缓存
*/
void clearCache() override {
PacketCache<TSPacket, TSFlushPolicy>::clearCache();
_ring->clearCache();
}
private:
void createRing(){
weak_ptr<TSMediaSource> weak_self = dynamic_pointer_cast<TSMediaSource>(shared_from_this());
_ring = std::make_shared<RingType>(_ring_size, [weak_self](int size) {
auto strong_self = weak_self.lock();
if (!strong_self) {
return;
}
strong_self->onReaderChanged(size);
});
onReaderChanged(0);
//注册媒体源
regist();
}
/**
* 合并写回调
* @param packet_list 合并写缓存列队
* @param key_pos 是否包含关键帧
*/
void onFlush(std::shared_ptr<List<TSPacket::Ptr> > &packet_list, bool key_pos) override {
//如果不存在视频,那么就没有存在GOP缓存的意义,所以确保一直清空GOP缓存
_ring->write(packet_list, _have_video ? key_pos : true);
}
private:
bool _have_video = false;
int _ring_size;
RingType::Ptr _ring;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_TSMEDIASOURCE_H
/*
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
*
* This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef ZLMEDIAKIT_TSMEDIASOURCEMUXER_H
#define ZLMEDIAKIT_TSMEDIASOURCEMUXER_H
#include "TSMediaSource.h"
#include "Record/TsMuxer.h"
namespace mediakit {
class TSMediaSourceMuxer : public TsMuxer, public MediaSourceEventInterceptor,
public std::enable_shared_from_this<TSMediaSourceMuxer> {
public:
using Ptr = std::shared_ptr<TSMediaSourceMuxer>;
TSMediaSourceMuxer(const string &vhost,
const string &app,
const string &stream_id) {
_media_src = std::make_shared<TSMediaSource>(vhost, app, stream_id);
_pool.setSize(256);
}
~TSMediaSourceMuxer() override = default;
void setListener(const std::weak_ptr<MediaSourceEvent> &listener){
_listener = listener;
_media_src->setListener(shared_from_this());
}
int readerCount() const{
return _media_src->readerCount();
}
void onReaderChanged(MediaSource &sender, int size) override {
_enabled = size;
if (!size) {
_clear_cache = true;
}
MediaSourceEventInterceptor::onReaderChanged(sender, size);
}
void inputFrame(const Frame::Ptr &frame) override {
if (_clear_cache) {
_clear_cache = false;
_media_src->clearCache();
}
if (_enabled) {
TsMuxer::inputFrame(frame);
}
}
bool isEnabled() {
//缓存尚未清空时,还允许触发inputFrame函数,以便及时清空缓存
return _clear_cache ? true : _enabled;
}
protected:
void onTs(const void *data, int len,uint32_t timestamp,bool is_idr_fast_packet) override{
if(!data || !len){
return;
}
TSPacket::Ptr packet = _pool.obtain();
packet->assign((char *) data, len);
packet->time_stamp = timestamp;
_media_src->onWrite(packet, is_idr_fast_packet);
}
private:
bool _enabled = true;
bool _clear_cache = false;
TSMediaSource::PoolType _pool;
TSMediaSource::Ptr _media_src;
};
}//namespace mediakit
#endif //ZLMEDIAKIT_TSMEDIASOURCEMUXER_H
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论