胡斌

Merge branch '2.0release' into 2.0+

#Simple-RTMP-Server
# Simple-RTMP-Server
[![CircleCI](https://circleci.com/gh/ossrs/srs/tree/2.0release.svg?style=svg)](https://circleci.com/gh/ossrs/srs/tree/2.0release)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ossrs/srs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Wechat](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat)
[<img width="52" alt="Skype" src="https://cloud.githubusercontent.com/assets/2777660/24329166/3821a328-1230-11e7-844a-506a5d17dd3d.png">](https://github.com/ossrs/srs/wiki/v1_EN_Contact#skype-or-gitter)
SRS/2.0, [ZhouGuowen][release2]
... ... @@ -300,6 +300,8 @@ Remark:
## Releases
* 2017-04-18, [Release v2.0-r1][r2.0r1], 2.0 release1, 2.0.239, 86515 lines.
* 2017-03-03, [Release v2.0-r0][r2.0r0], 2.0 release0, 2.0.234, 86373 lines.
* 2017-01-18, [Release v2.0-b4][r2.0b4], 2.0 beta4, 2.0.230, 86334 lines.
* 2016-11-13, [Release v2.0-b3][r2.0b3], 2.0 beta3, 2.0.223, 86685 lines.
* 2016-11-09, [Release v2.0-b2][r2.0b2], 2.0 beta2, 2.0.221, 86691 lines.
... ... @@ -335,6 +337,14 @@ Remark:
## History
* v2.0, 2017-04-23, Fix [#851][bug #851], HTTP API support number of video frames for FPS. 2.0.240
* <strong>v2.0, 2017-04-18, [2.0 release1(2.0.239)][r2.0r1] released. 86515 lines.</strong>
* v2.0, 2017-04-18, Fix [#848][bug #848], crash at HTTP fast buffer grow. 2.0.239
* v2.0, 2017-04-15, Fix [#844][bug #844], support Haivision encoder. 2.0.238
* v2.0, 2017-04-15, Merge [#846][bug #846], fix fd leak for FLV stream caster. 2.0.237
* v2.0, 2017-04-15, Merge [#841][bug #841], avoid the duplicated sps/pps in ts. 2.0.236
* v2.0, 2017-04-09, Fix [#834][bug #834], crash for TS context corrupt. 2.0.235
* <strong>v2.0, 2017-03-03, [2.0 release0(2.0.234)][r2.0r0] released. 86373 lines.</strong>
* v2.0, 2017-02-25, for [#730][bug #730], remove the test code. 2.0.234
* v2.0, 2017-02-09, fix [#503][bug #503] disable utilities when reload a source. 2.0.233
* v2.0, 2017-01-22, for [#752][bug #752] release the io then free it for kbps. 2.0.232
... ... @@ -1277,10 +1287,18 @@ Winlin
[bug #750]: https://github.com/ossrs/srs/issues/750
[bug #752]: https://github.com/ossrs/srs/issues/752
[bug #503]: https://github.com/ossrs/srs/issues/503
[bug #834]: https://github.com/ossrs/srs/issues/834
[bug #841]: https://github.com/ossrs/srs/issues/841
[bug #846]: https://github.com/ossrs/srs/issues/846
[bug #844]: https://github.com/ossrs/srs/issues/844
[bug #848]: https://github.com/ossrs/srs/issues/848
[bug #851]: https://github.com/ossrs/srs/issues/851
[bug #xxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxx
[exo #828]: https://github.com/google/ExoPlayer/pull/828
[r2.0r1]: https://github.com/ossrs/srs/releases/tag/v2.0-r1
[r2.0r0]: https://github.com/ossrs/srs/releases/tag/v2.0-r0
[r2.0b4]: https://github.com/ossrs/srs/releases/tag/v2.0-b4
[r2.0b3]: https://github.com/ossrs/srs/releases/tag/v2.0-b3
[r2.0b2]: https://github.com/ossrs/srs/releases/tag/v2.0-b2
... ... @@ -1324,6 +1342,6 @@ Winlin
[branch2]: https://github.com/ossrs/srs/tree/2.0release
[release2]: https://github.com/ossrs/srs/wiki/v1_CN_Product#release20
[release3]: https://github.com/ossrs/srs/wiki/v1_CN_Product#release30
[centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.230.zip
[centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.230.zip
[centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.239.zip
[centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.239.zip
... ...
... ... @@ -42,7 +42,7 @@ else
echo "build fdk-aac-0.1.3"
cd $ff_current_dir &&
rm -rf fdk-aac-0.1.3 && unzip -q ${ff_src_dir}/fdk-aac-0.1.3.zip &&
cd fdk-aac-0.1.3 && bash autogen.sh && ./configure --prefix=${ff_release_dir} --enable-static && make ${SRS_JOBS} && make install &&
cd fdk-aac-0.1.3 && bash autogen.sh && ./configure --prefix=${ff_release_dir} --enable-static && make ${SRS_JOBS} && make install
ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build fdk-aac-0.1.3 failed"; exit 1; fi
fi
... ...
... ... @@ -86,6 +86,11 @@ void SrsAppCasterFlv::remove(SrsConnection* c)
if ((it = std::find(conns.begin(), conns.end(), c)) != conns.end()) {
conns.erase(it);
}
// fixbug: SrsHttpConn for CasterFlv is not freed, which could cause memory leak
// so, free conn which is not managed by SrsServer->conns;
// @see: https://github.com/ossrs/srs/issues/826
srs_freep(c);
}
int SrsAppCasterFlv::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
... ...
... ... @@ -257,6 +257,7 @@ SrsPublishRecvThread::SrsPublishRecvThread(
recv_error_code = ERROR_SUCCESS;
_nb_msgs = 0;
video_frames = 0;
error = st_cond_new();
ncid = cid = 0;
... ... @@ -298,6 +299,11 @@ int64_t SrsPublishRecvThread::nb_msgs()
return _nb_msgs;
}
uint64_t SrsPublishRecvThread::nb_video_frames()
{
return video_frames;
}
int SrsPublishRecvThread::error_code()
{
return recv_error_code;
... ... @@ -378,6 +384,10 @@ int SrsPublishRecvThread::handle(SrsCommonMessage* msg)
_nb_msgs++;
if (msg->header.is_video()) {
video_frames++;
}
// log to show the time of recv thread.
srs_verbose("recv thread now=%"PRId64"us, got msg time=%"PRId64"ms, size=%d",
srs_update_system_time_ms(), msg->header.timestamp, msg->size);
... ...
... ... @@ -154,6 +154,8 @@ private:
SrsRequest* req;
// the msgs already got.
int64_t _nb_msgs;
// The video frames we got.
uint64_t video_frames;
// for mr(merged read),
// @see https://github.com/ossrs/srs/issues/241
bool mr;
... ... @@ -186,6 +188,7 @@ public:
*/
virtual int wait(int timeout_ms);
virtual int64_t nb_msgs();
virtual uint64_t nb_video_frames();
virtual int error_code();
virtual void set_cid(int v);
virtual int get_cid();
... ...
... ... @@ -481,6 +481,14 @@ int SrsRtmpConn::stream_service_cycle()
return ret;
}
srs_info("security check ok");
// Never allow the empty stream name, for HLS may write to a file with empty name.
// @see https://github.com/ossrs/srs/issues/834
if (req->stream.empty()) {
ret = ERROR_RTMP_STREAM_NAME_EMPTY;
srs_error("RTMP: Empty stream name not allowed, ret=%d", ret);
return ret;
}
// client is identified, set the timeout to service timeout.
rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US);
... ... @@ -538,6 +546,16 @@ int SrsRtmpConn::stream_service_cycle()
return publishing(source);
}
case SrsRtmpConnHaivisionPublish: {
srs_verbose("Haivision start to publish stream %s.", req->stream.c_str());
if ((ret = rtmp->start_haivision_publish(res->stream_id)) != ERROR_SUCCESS) {
srs_error("start to publish stream failed. ret=%d", ret);
return ret;
}
return publishing(source);
}
case SrsRtmpConnFlashPublish: {
srs_verbose("flash start to publish stream %s.", req->stream.c_str());
... ... @@ -831,7 +849,7 @@ int SrsRtmpConn::publishing(SrsSource* source)
// @see: https://github.com/ossrs/srs/issues/237
SrsPublishRecvThread trd(rtmp, req,
st_netfd_fileno(stfd), 0, this, source,
client_type == SrsRtmpConnFMLEPublish,
client_type != SrsRtmpConnFlashPublish,
vhost_is_edge);
srs_info("start to publish stream %s success", req->stream.c_str());
... ... @@ -888,6 +906,7 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd)
}
int64_t nb_msgs = 0;
uint64_t nb_frames = 0;
while (!disposed) {
pprint->elapse();
... ... @@ -923,6 +942,14 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd)
break;
}
nb_msgs = trd->nb_msgs();
// Update the stat for video fps.
// @remark https://github.com/ossrs/srs/issues/851
SrsStatistic* stat = SrsStatistic::instance();
if ((ret = stat->on_video_frames(req, (int)(trd->nb_video_frames() - nb_frames))) != ERROR_SUCCESS) {
return ret;
}
nb_frames = trd->nb_video_frames();
// reportable
if (pprint->can_print()) {
... ...
... ... @@ -90,6 +90,7 @@ int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std:
break;
case SrsRtmpConnFMLEPublish:
case SrsRtmpConnFlashPublish:
case SrsRtmpConnHaivisionPublish:
if (rule->arg0() != "publish") {
break;
}
... ... @@ -135,6 +136,7 @@ int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::
break;
case SrsRtmpConnFMLEPublish:
case SrsRtmpConnFlashPublish:
case SrsRtmpConnHaivisionPublish:
if (rule->arg0() != "publish") {
break;
}
... ...
... ... @@ -111,6 +111,7 @@ SrsStatisticStream::SrsStatisticStream()
kbps->set_io(NULL, NULL);
nb_clients = 0;
nb_frames = 0;
}
SrsStatisticStream::~SrsStatisticStream()
... ... @@ -129,6 +130,7 @@ int SrsStatisticStream::dumps(stringstream& ss)
<< SRS_JFIELD_STR("app", app) << SRS_JFIELD_CONT
<< SRS_JFIELD_ORG("live_ms", srs_get_system_time_ms()) << SRS_JFIELD_CONT
<< SRS_JFIELD_ORG("clients", nb_clients) << SRS_JFIELD_CONT
<< SRS_JFIELD_ORG("frames", nb_frames) << SRS_JFIELD_CONT
<< SRS_JFIELD_ORG("send_bytes", kbps->get_send_bytes()) << SRS_JFIELD_CONT
<< SRS_JFIELD_ORG("recv_bytes", kbps->get_recv_bytes()) << SRS_JFIELD_CONT
<< SRS_JFIELD_OBJ("kbps")
... ... @@ -327,6 +329,18 @@ int SrsStatistic::on_audio_info(SrsRequest* req,
return ret;
}
int SrsStatistic::on_video_frames(SrsRequest* req, int nb_frames)
{
int ret = ERROR_SUCCESS;
SrsStatisticVhost* vhost = create_vhost(req);
SrsStatisticStream* stream = create_stream(vhost, req);
stream->nb_frames += nb_frames;
return ret;
}
void SrsStatistic::on_stream_publish(SrsRequest* req, int cid)
{
SrsStatisticVhost* vhost = create_vhost(req);
... ...
... ... @@ -70,6 +70,7 @@ public:
bool active;
int connection_cid;
int nb_clients;
uint64_t nb_frames;
public:
/**
* stream total kbps.
... ... @@ -173,6 +174,11 @@ public:
SrsAacObjectType aac_object
);
/**
* When got videos, update the frames.
* We only stat the total number of video frames.
*/
virtual int on_video_frames(SrsRequest* req, int nb_frames);
/**
* when publish stream.
* @param req the request object of publish connection.
* @param cid the cid of publish connection.
... ...
... ... @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
#define VERSION_REVISION 234
#define VERSION_REVISION 240
// generated by configure, only macros.
#include <srs_auto_headers.hpp>
... ...
... ... @@ -152,6 +152,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_RTSP_AUDIO_CONFIG 2047
#define ERROR_RTMP_STREAM_NOT_FOUND 2048
#define ERROR_RTMP_CLIENT_NOT_FOUND 2049
#define ERROR_RTMP_STREAM_NAME_EMPTY 2050
//
// system control message,
// not an error, but special control logic.
... ... @@ -230,6 +231,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define ERROR_RESPONSE_CODE 3064
#define ERROR_RESPONSE_DATA 3065
#define ERROR_REQUEST_DATA 3066
#define ERROR_TS_CONTEXT_NOT_READY 3067
///////////////////////////////////////////////////////
// HTTP/StreamCaster protocol error.
... ...
... ... @@ -199,6 +199,7 @@ ISrsTsHandler::~ISrsTsHandler()
SrsTsContext::SrsTsContext()
{
ready = false;
pure_audio = false;
vcodec = SrsCodecVideoReserved;
acodec = SrsCodecAudioReserved1;
... ... @@ -234,6 +235,7 @@ void SrsTsContext::on_pmt_parsed()
void SrsTsContext::reset()
{
ready = false;
vcodec = SrsCodecVideoReserved;
acodec = SrsCodecAudioReserved1;
}
... ... @@ -432,6 +434,9 @@ int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStrea
return ret;
}
}
// When PAT and PMT are writen, the context is ready now.
ready = true;
return ret;
}
... ... @@ -439,6 +444,13 @@ int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStrea
int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t pid, SrsTsStream sid, bool pure_audio)
{
int ret = ERROR_SUCCESS;
// Sometimes, the context is not ready(PAT/PMT write failed), error in this situation.
if (!ready) {
ret = ERROR_TS_CONTEXT_NOT_READY;
srs_error("TS: context not ready, ret=%d", ret);
return ret;
}
if (msg->payload->length() == 0) {
return ret;
... ... @@ -3027,6 +3039,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
video->payload->append((const char*)default_aud_nalu, 2);
}
bool is_sps_pps_appended = false;
// all sample use cont nalu header, except the sps-pps before IDR frame.
for (int i = 0; i < sample->nb_sample_units; i++) {
SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
... ... @@ -3044,7 +3057,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
// Insert sps/pps before IDR when there is no sps/pps in samples.
// The sps/pps is parsed from sequence header(generally the first flv packet).
if (nal_unit_type == SrsAvcNaluTypeIDR && !sample->has_sps_pps) {
if (nal_unit_type == SrsAvcNaluTypeIDR && !sample->has_sps_pps && !is_sps_pps_appended) {
if (codec->sequenceParameterSetLength > 0) {
srs_avc_insert_aud(video->payload, aud_inserted);
video->payload->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
... ... @@ -3053,6 +3066,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
srs_avc_insert_aud(video->payload, aud_inserted);
video->payload->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength);
}
is_sps_pps_appended = true;
}
// Insert the NALU to video in annexb.
... ...
... ... @@ -346,6 +346,11 @@ public:
*/
class SrsTsContext
{
private:
// Whether context is ready, failed if try to write data when not ready.
// When PAT and PMT writen, the context is ready.
// @see https://github.com/ossrs/srs/issues/834
bool ready;
// codec
private:
std::map<int, SrsTsChannel*> pids;
... ...
... ... @@ -160,9 +160,10 @@ int SrsFastBuffer::grow(ISrsBufferReader* reader, int required_size)
// reset when buffer is empty.
p = end = buffer;
srs_verbose("all consumed, reset fast buffer");
} else {
} else if (nb_exists_bytes < nb_buffer && p > buffer) {
// move the left bytes to start of buffer.
srs_assert(nb_exists_bytes < nb_buffer);
// @remark Only move memory when space is enough, or failed at next check.
// @see https://github.com/ossrs/srs/issues/848
buffer = (char*)memmove(buffer, p, nb_exists_bytes);
p = buffer;
end = p + nb_exists_bytes;
... ...
... ... @@ -1812,6 +1812,7 @@ string srs_client_type_string(SrsRtmpConnType type)
case SrsRtmpConnPlay: return "Play";
case SrsRtmpConnFlashPublish: return "flash-publish";
case SrsRtmpConnFMLEPublish: return "fmle-publish";
case SrsRtmpConnHaivisionPublish: return "haivision-publish";
default: return "Unknown";
}
}
... ... @@ -2714,6 +2715,14 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string&
}
return ret;
}
// For encoder of Haivision, it always send a _checkbw call message.
// @Remark the next message is createStream, so we continue to identify it.
// @see https://github.com/ossrs/srs/issues/844
if (call->command_name == "_checkbw") {
srs_info("Haivision encoder identified.");
continue;
}
continue;
}
... ... @@ -2989,6 +2998,60 @@ int SrsRtmpServer::start_fmle_publish(int stream_id)
return ret;
}
int SrsRtmpServer::start_haivision_publish(int stream_id)
{
int ret = ERROR_SUCCESS;
// publish
if (true) {
SrsCommonMessage* msg = NULL;
SrsPublishPacket* pkt = NULL;
if ((ret = expect_message<SrsPublishPacket>(&msg, &pkt)) != ERROR_SUCCESS) {
srs_error("recv publish message failed. ret=%d", ret);
return ret;
}
srs_info("recv publish request message success.");
SrsAutoFree(SrsCommonMessage, msg);
SrsAutoFree(SrsPublishPacket, pkt);
}
// publish response onFCPublish(NetStream.Publish.Start)
if (true) {
SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_PUBLISH;
pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart));
pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream."));
if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) {
srs_error("send onFCPublish(NetStream.Publish.Start) message failed. ret=%d", ret);
return ret;
}
srs_info("send onFCPublish(NetStream.Publish.Start) message success.");
}
// publish response onStatus(NetStream.Publish.Start)
if (true) {
SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus));
pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart));
pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream."));
pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID));
if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) {
srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret);
return ret;
}
srs_info("send onStatus(NetStream.Publish.Start) message success.");
}
srs_info("Haivision publish success.");
return ret;
}
int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid)
{
int ret = ERROR_SUCCESS;
... ... @@ -3123,6 +3186,10 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int
srs_info("identify client by create stream, play or flash publish.");
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration);
}
if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
srs_info("identify client by FCPublish, haivision publish.");
return identify_haivision_publish_client(dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);
}
srs_trace("identify_create_stream_client:ignore AMF0/AMF3 command message.");
}
... ... @@ -3150,6 +3217,26 @@ int SrsRtmpServer::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmp
return ret;
}
int SrsRtmpServer::identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, string& stream_name)
{
int ret = ERROR_SUCCESS;
type = SrsRtmpConnHaivisionPublish;
stream_name = req->stream_name;
// FCPublish response
if (true) {
SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id);
if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) {
srs_error("send FCPublish response message failed. ret=%d", ret);
return ret;
}
srs_info("send FCPublish response message success.");
}
return ret;
}
int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, string& stream_name)
{
int ret = ERROR_SUCCESS;
... ...
... ... @@ -69,6 +69,7 @@ class SrsCommonMessage;
class SrsPacket;
class SrsAmf0Object;
class IMergeReadHandler;
class SrsCallPacket;
/****************************************************************************
*****************************************************************************
... ... @@ -633,6 +634,7 @@ enum SrsRtmpConnType
SrsRtmpConnPlay,
SrsRtmpConnFMLEPublish,
SrsRtmpConnFlashPublish,
SrsRtmpConnHaivisionPublish,
};
std::string srs_client_type_string(SrsRtmpConnType type);
bool srs_client_type_is_publish(SrsRtmpConnType type);
... ... @@ -992,6 +994,11 @@ public:
*/
virtual int start_fmle_publish(int stream_id);
/**
* For encoder of Haivision, response the startup request.
* @see https://github.com/ossrs/srs/issues/844
*/
virtual int start_haivision_publish(int stream_id);
/**
* process the FMLE unpublish event.
* @unpublish_tid the unpublish request transaction id.
*/
... ... @@ -1027,6 +1034,7 @@ public:
private:
virtual int identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration);
virtual int identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
virtual int identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
virtual int identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name);
private:
virtual int identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, std::string& stream_name, double& duration);
... ... @@ -1295,7 +1303,7 @@ public:
};
/**
* FMLE start publish: ReleaseStream/PublishStream
* FMLE start publish: ReleaseStream/PublishStream/FCPublish/FCUnpublish
*/
class SrsFMLEStartPacket : public SrsPacket
{
... ...