胡斌

Merge branch '2.0release' into 2.0+

1 -#Simple-RTMP-Server 1 +# Simple-RTMP-Server
2 2
3 [![CircleCI](https://circleci.com/gh/ossrs/srs/tree/2.0release.svg?style=svg)](https://circleci.com/gh/ossrs/srs/tree/2.0release) 3 [![CircleCI](https://circleci.com/gh/ossrs/srs/tree/2.0release.svg?style=svg)](https://circleci.com/gh/ossrs/srs/tree/2.0release)
4 -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ossrs/srs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)  
5 [![Wechat](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat) 4 [![Wechat](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat)
  5 +[<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)
6 6
7 SRS/2.0, [ZhouGuowen][release2] 7 SRS/2.0, [ZhouGuowen][release2]
8 8
@@ -300,6 +300,8 @@ Remark: @@ -300,6 +300,8 @@ Remark:
300 300
301 ## Releases 301 ## Releases
302 302
  303 +* 2017-04-18, [Release v2.0-r1][r2.0r1], 2.0 release1, 2.0.239, 86515 lines.
  304 +* 2017-03-03, [Release v2.0-r0][r2.0r0], 2.0 release0, 2.0.234, 86373 lines.
303 * 2017-01-18, [Release v2.0-b4][r2.0b4], 2.0 beta4, 2.0.230, 86334 lines. 305 * 2017-01-18, [Release v2.0-b4][r2.0b4], 2.0 beta4, 2.0.230, 86334 lines.
304 * 2016-11-13, [Release v2.0-b3][r2.0b3], 2.0 beta3, 2.0.223, 86685 lines. 306 * 2016-11-13, [Release v2.0-b3][r2.0b3], 2.0 beta3, 2.0.223, 86685 lines.
305 * 2016-11-09, [Release v2.0-b2][r2.0b2], 2.0 beta2, 2.0.221, 86691 lines. 307 * 2016-11-09, [Release v2.0-b2][r2.0b2], 2.0 beta2, 2.0.221, 86691 lines.
@@ -335,6 +337,14 @@ Remark: @@ -335,6 +337,14 @@ Remark:
335 337
336 ## History 338 ## History
337 339
  340 +* v2.0, 2017-04-23, Fix [#851][bug #851], HTTP API support number of video frames for FPS. 2.0.240
  341 +* <strong>v2.0, 2017-04-18, [2.0 release1(2.0.239)][r2.0r1] released. 86515 lines.</strong>
  342 +* v2.0, 2017-04-18, Fix [#848][bug #848], crash at HTTP fast buffer grow. 2.0.239
  343 +* v2.0, 2017-04-15, Fix [#844][bug #844], support Haivision encoder. 2.0.238
  344 +* v2.0, 2017-04-15, Merge [#846][bug #846], fix fd leak for FLV stream caster. 2.0.237
  345 +* v2.0, 2017-04-15, Merge [#841][bug #841], avoid the duplicated sps/pps in ts. 2.0.236
  346 +* v2.0, 2017-04-09, Fix [#834][bug #834], crash for TS context corrupt. 2.0.235
  347 +* <strong>v2.0, 2017-03-03, [2.0 release0(2.0.234)][r2.0r0] released. 86373 lines.</strong>
338 * v2.0, 2017-02-25, for [#730][bug #730], remove the test code. 2.0.234 348 * v2.0, 2017-02-25, for [#730][bug #730], remove the test code. 2.0.234
339 * v2.0, 2017-02-09, fix [#503][bug #503] disable utilities when reload a source. 2.0.233 349 * v2.0, 2017-02-09, fix [#503][bug #503] disable utilities when reload a source. 2.0.233
340 * v2.0, 2017-01-22, for [#752][bug #752] release the io then free it for kbps. 2.0.232 350 * 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 @@ -1277,10 +1287,18 @@ Winlin
1277 [bug #750]: https://github.com/ossrs/srs/issues/750 1287 [bug #750]: https://github.com/ossrs/srs/issues/750
1278 [bug #752]: https://github.com/ossrs/srs/issues/752 1288 [bug #752]: https://github.com/ossrs/srs/issues/752
1279 [bug #503]: https://github.com/ossrs/srs/issues/503 1289 [bug #503]: https://github.com/ossrs/srs/issues/503
  1290 +[bug #834]: https://github.com/ossrs/srs/issues/834
  1291 +[bug #841]: https://github.com/ossrs/srs/issues/841
  1292 +[bug #846]: https://github.com/ossrs/srs/issues/846
  1293 +[bug #844]: https://github.com/ossrs/srs/issues/844
  1294 +[bug #848]: https://github.com/ossrs/srs/issues/848
  1295 +[bug #851]: https://github.com/ossrs/srs/issues/851
1280 [bug #xxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxx 1296 [bug #xxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxx
1281 1297
1282 [exo #828]: https://github.com/google/ExoPlayer/pull/828 1298 [exo #828]: https://github.com/google/ExoPlayer/pull/828
1283 1299
  1300 +[r2.0r1]: https://github.com/ossrs/srs/releases/tag/v2.0-r1
  1301 +[r2.0r0]: https://github.com/ossrs/srs/releases/tag/v2.0-r0
1284 [r2.0b4]: https://github.com/ossrs/srs/releases/tag/v2.0-b4 1302 [r2.0b4]: https://github.com/ossrs/srs/releases/tag/v2.0-b4
1285 [r2.0b3]: https://github.com/ossrs/srs/releases/tag/v2.0-b3 1303 [r2.0b3]: https://github.com/ossrs/srs/releases/tag/v2.0-b3
1286 [r2.0b2]: https://github.com/ossrs/srs/releases/tag/v2.0-b2 1304 [r2.0b2]: https://github.com/ossrs/srs/releases/tag/v2.0-b2
@@ -1324,6 +1342,6 @@ Winlin @@ -1324,6 +1342,6 @@ Winlin
1324 [branch2]: https://github.com/ossrs/srs/tree/2.0release 1342 [branch2]: https://github.com/ossrs/srs/tree/2.0release
1325 [release2]: https://github.com/ossrs/srs/wiki/v1_CN_Product#release20 1343 [release2]: https://github.com/ossrs/srs/wiki/v1_CN_Product#release20
1326 [release3]: https://github.com/ossrs/srs/wiki/v1_CN_Product#release30 1344 [release3]: https://github.com/ossrs/srs/wiki/v1_CN_Product#release30
1327 -[centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.230.zip  
1328 -[centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.230.zip 1345 +[centos0]: http://winlinvip.github.io/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.239.zip
  1346 +[centos1]: http://www.ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-2.0.239.zip
1329 1347
@@ -42,7 +42,7 @@ else @@ -42,7 +42,7 @@ else
42 echo "build fdk-aac-0.1.3" 42 echo "build fdk-aac-0.1.3"
43 cd $ff_current_dir && 43 cd $ff_current_dir &&
44 rm -rf fdk-aac-0.1.3 && unzip -q ${ff_src_dir}/fdk-aac-0.1.3.zip && 44 rm -rf fdk-aac-0.1.3 && unzip -q ${ff_src_dir}/fdk-aac-0.1.3.zip &&
45 - cd fdk-aac-0.1.3 && bash autogen.sh && ./configure --prefix=${ff_release_dir} --enable-static && make ${SRS_JOBS} && make install && 45 + cd fdk-aac-0.1.3 && bash autogen.sh && ./configure --prefix=${ff_release_dir} --enable-static && make ${SRS_JOBS} && make install
46 ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build fdk-aac-0.1.3 failed"; exit 1; fi 46 ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build fdk-aac-0.1.3 failed"; exit 1; fi
47 fi 47 fi
48 48
@@ -86,6 +86,11 @@ void SrsAppCasterFlv::remove(SrsConnection* c) @@ -86,6 +86,11 @@ void SrsAppCasterFlv::remove(SrsConnection* c)
86 if ((it = std::find(conns.begin(), conns.end(), c)) != conns.end()) { 86 if ((it = std::find(conns.begin(), conns.end(), c)) != conns.end()) {
87 conns.erase(it); 87 conns.erase(it);
88 } 88 }
  89 +
  90 + // fixbug: SrsHttpConn for CasterFlv is not freed, which could cause memory leak
  91 + // so, free conn which is not managed by SrsServer->conns;
  92 + // @see: https://github.com/ossrs/srs/issues/826
  93 + srs_freep(c);
89 } 94 }
90 95
91 int SrsAppCasterFlv::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) 96 int SrsAppCasterFlv::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
@@ -257,6 +257,7 @@ SrsPublishRecvThread::SrsPublishRecvThread( @@ -257,6 +257,7 @@ SrsPublishRecvThread::SrsPublishRecvThread(
257 257
258 recv_error_code = ERROR_SUCCESS; 258 recv_error_code = ERROR_SUCCESS;
259 _nb_msgs = 0; 259 _nb_msgs = 0;
  260 + video_frames = 0;
260 error = st_cond_new(); 261 error = st_cond_new();
261 ncid = cid = 0; 262 ncid = cid = 0;
262 263
@@ -298,6 +299,11 @@ int64_t SrsPublishRecvThread::nb_msgs() @@ -298,6 +299,11 @@ int64_t SrsPublishRecvThread::nb_msgs()
298 return _nb_msgs; 299 return _nb_msgs;
299 } 300 }
300 301
  302 +uint64_t SrsPublishRecvThread::nb_video_frames()
  303 +{
  304 + return video_frames;
  305 +}
  306 +
301 int SrsPublishRecvThread::error_code() 307 int SrsPublishRecvThread::error_code()
302 { 308 {
303 return recv_error_code; 309 return recv_error_code;
@@ -378,6 +384,10 @@ int SrsPublishRecvThread::handle(SrsCommonMessage* msg) @@ -378,6 +384,10 @@ int SrsPublishRecvThread::handle(SrsCommonMessage* msg)
378 384
379 _nb_msgs++; 385 _nb_msgs++;
380 386
  387 + if (msg->header.is_video()) {
  388 + video_frames++;
  389 + }
  390 +
381 // log to show the time of recv thread. 391 // log to show the time of recv thread.
382 srs_verbose("recv thread now=%"PRId64"us, got msg time=%"PRId64"ms, size=%d", 392 srs_verbose("recv thread now=%"PRId64"us, got msg time=%"PRId64"ms, size=%d",
383 srs_update_system_time_ms(), msg->header.timestamp, msg->size); 393 srs_update_system_time_ms(), msg->header.timestamp, msg->size);
@@ -154,6 +154,8 @@ private: @@ -154,6 +154,8 @@ private:
154 SrsRequest* req; 154 SrsRequest* req;
155 // the msgs already got. 155 // the msgs already got.
156 int64_t _nb_msgs; 156 int64_t _nb_msgs;
  157 + // The video frames we got.
  158 + uint64_t video_frames;
157 // for mr(merged read), 159 // for mr(merged read),
158 // @see https://github.com/ossrs/srs/issues/241 160 // @see https://github.com/ossrs/srs/issues/241
159 bool mr; 161 bool mr;
@@ -186,6 +188,7 @@ public: @@ -186,6 +188,7 @@ public:
186 */ 188 */
187 virtual int wait(int timeout_ms); 189 virtual int wait(int timeout_ms);
188 virtual int64_t nb_msgs(); 190 virtual int64_t nb_msgs();
  191 + virtual uint64_t nb_video_frames();
189 virtual int error_code(); 192 virtual int error_code();
190 virtual void set_cid(int v); 193 virtual void set_cid(int v);
191 virtual int get_cid(); 194 virtual int get_cid();
@@ -482,6 +482,14 @@ int SrsRtmpConn::stream_service_cycle() @@ -482,6 +482,14 @@ int SrsRtmpConn::stream_service_cycle()
482 } 482 }
483 srs_info("security check ok"); 483 srs_info("security check ok");
484 484
  485 + // Never allow the empty stream name, for HLS may write to a file with empty name.
  486 + // @see https://github.com/ossrs/srs/issues/834
  487 + if (req->stream.empty()) {
  488 + ret = ERROR_RTMP_STREAM_NAME_EMPTY;
  489 + srs_error("RTMP: Empty stream name not allowed, ret=%d", ret);
  490 + return ret;
  491 + }
  492 +
485 // client is identified, set the timeout to service timeout. 493 // client is identified, set the timeout to service timeout.
486 rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US); 494 rtmp->set_recv_timeout(SRS_CONSTS_RTMP_RECV_TIMEOUT_US);
487 rtmp->set_send_timeout(SRS_CONSTS_RTMP_SEND_TIMEOUT_US); 495 rtmp->set_send_timeout(SRS_CONSTS_RTMP_SEND_TIMEOUT_US);
@@ -538,6 +546,16 @@ int SrsRtmpConn::stream_service_cycle() @@ -538,6 +546,16 @@ int SrsRtmpConn::stream_service_cycle()
538 546
539 return publishing(source); 547 return publishing(source);
540 } 548 }
  549 + case SrsRtmpConnHaivisionPublish: {
  550 + srs_verbose("Haivision start to publish stream %s.", req->stream.c_str());
  551 +
  552 + if ((ret = rtmp->start_haivision_publish(res->stream_id)) != ERROR_SUCCESS) {
  553 + srs_error("start to publish stream failed. ret=%d", ret);
  554 + return ret;
  555 + }
  556 +
  557 + return publishing(source);
  558 + }
541 case SrsRtmpConnFlashPublish: { 559 case SrsRtmpConnFlashPublish: {
542 srs_verbose("flash start to publish stream %s.", req->stream.c_str()); 560 srs_verbose("flash start to publish stream %s.", req->stream.c_str());
543 561
@@ -831,7 +849,7 @@ int SrsRtmpConn::publishing(SrsSource* source) @@ -831,7 +849,7 @@ int SrsRtmpConn::publishing(SrsSource* source)
831 // @see: https://github.com/ossrs/srs/issues/237 849 // @see: https://github.com/ossrs/srs/issues/237
832 SrsPublishRecvThread trd(rtmp, req, 850 SrsPublishRecvThread trd(rtmp, req,
833 st_netfd_fileno(stfd), 0, this, source, 851 st_netfd_fileno(stfd), 0, this, source,
834 - client_type == SrsRtmpConnFMLEPublish, 852 + client_type != SrsRtmpConnFlashPublish,
835 vhost_is_edge); 853 vhost_is_edge);
836 854
837 srs_info("start to publish stream %s success", req->stream.c_str()); 855 srs_info("start to publish stream %s success", req->stream.c_str());
@@ -888,6 +906,7 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd) @@ -888,6 +906,7 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd)
888 } 906 }
889 907
890 int64_t nb_msgs = 0; 908 int64_t nb_msgs = 0;
  909 + uint64_t nb_frames = 0;
891 while (!disposed) { 910 while (!disposed) {
892 pprint->elapse(); 911 pprint->elapse();
893 912
@@ -924,6 +943,14 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd) @@ -924,6 +943,14 @@ int SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* trd)
924 } 943 }
925 nb_msgs = trd->nb_msgs(); 944 nb_msgs = trd->nb_msgs();
926 945
  946 + // Update the stat for video fps.
  947 + // @remark https://github.com/ossrs/srs/issues/851
  948 + SrsStatistic* stat = SrsStatistic::instance();
  949 + if ((ret = stat->on_video_frames(req, (int)(trd->nb_video_frames() - nb_frames))) != ERROR_SUCCESS) {
  950 + return ret;
  951 + }
  952 + nb_frames = trd->nb_video_frames();
  953 +
927 // reportable 954 // reportable
928 if (pprint->can_print()) { 955 if (pprint->can_print()) {
929 kbps->sample(); 956 kbps->sample();
@@ -90,6 +90,7 @@ int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std: @@ -90,6 +90,7 @@ int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std:
90 break; 90 break;
91 case SrsRtmpConnFMLEPublish: 91 case SrsRtmpConnFMLEPublish:
92 case SrsRtmpConnFlashPublish: 92 case SrsRtmpConnFlashPublish:
  93 + case SrsRtmpConnHaivisionPublish:
93 if (rule->arg0() != "publish") { 94 if (rule->arg0() != "publish") {
94 break; 95 break;
95 } 96 }
@@ -135,6 +136,7 @@ int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std:: @@ -135,6 +136,7 @@ int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std::
135 break; 136 break;
136 case SrsRtmpConnFMLEPublish: 137 case SrsRtmpConnFMLEPublish:
137 case SrsRtmpConnFlashPublish: 138 case SrsRtmpConnFlashPublish:
  139 + case SrsRtmpConnHaivisionPublish:
138 if (rule->arg0() != "publish") { 140 if (rule->arg0() != "publish") {
139 break; 141 break;
140 } 142 }
@@ -111,6 +111,7 @@ SrsStatisticStream::SrsStatisticStream() @@ -111,6 +111,7 @@ SrsStatisticStream::SrsStatisticStream()
111 kbps->set_io(NULL, NULL); 111 kbps->set_io(NULL, NULL);
112 112
113 nb_clients = 0; 113 nb_clients = 0;
  114 + nb_frames = 0;
114 } 115 }
115 116
116 SrsStatisticStream::~SrsStatisticStream() 117 SrsStatisticStream::~SrsStatisticStream()
@@ -129,6 +130,7 @@ int SrsStatisticStream::dumps(stringstream& ss) @@ -129,6 +130,7 @@ int SrsStatisticStream::dumps(stringstream& ss)
129 << SRS_JFIELD_STR("app", app) << SRS_JFIELD_CONT 130 << SRS_JFIELD_STR("app", app) << SRS_JFIELD_CONT
130 << SRS_JFIELD_ORG("live_ms", srs_get_system_time_ms()) << SRS_JFIELD_CONT 131 << SRS_JFIELD_ORG("live_ms", srs_get_system_time_ms()) << SRS_JFIELD_CONT
131 << SRS_JFIELD_ORG("clients", nb_clients) << SRS_JFIELD_CONT 132 << SRS_JFIELD_ORG("clients", nb_clients) << SRS_JFIELD_CONT
  133 + << SRS_JFIELD_ORG("frames", nb_frames) << SRS_JFIELD_CONT
132 << SRS_JFIELD_ORG("send_bytes", kbps->get_send_bytes()) << SRS_JFIELD_CONT 134 << SRS_JFIELD_ORG("send_bytes", kbps->get_send_bytes()) << SRS_JFIELD_CONT
133 << SRS_JFIELD_ORG("recv_bytes", kbps->get_recv_bytes()) << SRS_JFIELD_CONT 135 << SRS_JFIELD_ORG("recv_bytes", kbps->get_recv_bytes()) << SRS_JFIELD_CONT
134 << SRS_JFIELD_OBJ("kbps") 136 << SRS_JFIELD_OBJ("kbps")
@@ -327,6 +329,18 @@ int SrsStatistic::on_audio_info(SrsRequest* req, @@ -327,6 +329,18 @@ int SrsStatistic::on_audio_info(SrsRequest* req,
327 return ret; 329 return ret;
328 } 330 }
329 331
  332 +int SrsStatistic::on_video_frames(SrsRequest* req, int nb_frames)
  333 +{
  334 + int ret = ERROR_SUCCESS;
  335 +
  336 + SrsStatisticVhost* vhost = create_vhost(req);
  337 + SrsStatisticStream* stream = create_stream(vhost, req);
  338 +
  339 + stream->nb_frames += nb_frames;
  340 +
  341 + return ret;
  342 +}
  343 +
330 void SrsStatistic::on_stream_publish(SrsRequest* req, int cid) 344 void SrsStatistic::on_stream_publish(SrsRequest* req, int cid)
331 { 345 {
332 SrsStatisticVhost* vhost = create_vhost(req); 346 SrsStatisticVhost* vhost = create_vhost(req);
@@ -70,6 +70,7 @@ public: @@ -70,6 +70,7 @@ public:
70 bool active; 70 bool active;
71 int connection_cid; 71 int connection_cid;
72 int nb_clients; 72 int nb_clients;
  73 + uint64_t nb_frames;
73 public: 74 public:
74 /** 75 /**
75 * stream total kbps. 76 * stream total kbps.
@@ -173,6 +174,11 @@ public: @@ -173,6 +174,11 @@ public:
173 SrsAacObjectType aac_object 174 SrsAacObjectType aac_object
174 ); 175 );
175 /** 176 /**
  177 + * When got videos, update the frames.
  178 + * We only stat the total number of video frames.
  179 + */
  180 + virtual int on_video_frames(SrsRequest* req, int nb_frames);
  181 + /**
176 * when publish stream. 182 * when publish stream.
177 * @param req the request object of publish connection. 183 * @param req the request object of publish connection.
178 * @param cid the cid of publish connection. 184 * @param cid the cid of publish connection.
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 234 34 +#define VERSION_REVISION 240
35 35
36 // generated by configure, only macros. 36 // generated by configure, only macros.
37 #include <srs_auto_headers.hpp> 37 #include <srs_auto_headers.hpp>
@@ -152,6 +152,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -152,6 +152,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
152 #define ERROR_RTSP_AUDIO_CONFIG 2047 152 #define ERROR_RTSP_AUDIO_CONFIG 2047
153 #define ERROR_RTMP_STREAM_NOT_FOUND 2048 153 #define ERROR_RTMP_STREAM_NOT_FOUND 2048
154 #define ERROR_RTMP_CLIENT_NOT_FOUND 2049 154 #define ERROR_RTMP_CLIENT_NOT_FOUND 2049
  155 +#define ERROR_RTMP_STREAM_NAME_EMPTY 2050
155 // 156 //
156 // system control message, 157 // system control message,
157 // not an error, but special control logic. 158 // not an error, but special control logic.
@@ -230,6 +231,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -230,6 +231,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
230 #define ERROR_RESPONSE_CODE 3064 231 #define ERROR_RESPONSE_CODE 3064
231 #define ERROR_RESPONSE_DATA 3065 232 #define ERROR_RESPONSE_DATA 3065
232 #define ERROR_REQUEST_DATA 3066 233 #define ERROR_REQUEST_DATA 3066
  234 +#define ERROR_TS_CONTEXT_NOT_READY 3067
233 235
234 /////////////////////////////////////////////////////// 236 ///////////////////////////////////////////////////////
235 // HTTP/StreamCaster protocol error. 237 // HTTP/StreamCaster protocol error.
@@ -199,6 +199,7 @@ ISrsTsHandler::~ISrsTsHandler() @@ -199,6 +199,7 @@ ISrsTsHandler::~ISrsTsHandler()
199 199
200 SrsTsContext::SrsTsContext() 200 SrsTsContext::SrsTsContext()
201 { 201 {
  202 + ready = false;
202 pure_audio = false; 203 pure_audio = false;
203 vcodec = SrsCodecVideoReserved; 204 vcodec = SrsCodecVideoReserved;
204 acodec = SrsCodecAudioReserved1; 205 acodec = SrsCodecAudioReserved1;
@@ -234,6 +235,7 @@ void SrsTsContext::on_pmt_parsed() @@ -234,6 +235,7 @@ void SrsTsContext::on_pmt_parsed()
234 235
235 void SrsTsContext::reset() 236 void SrsTsContext::reset()
236 { 237 {
  238 + ready = false;
237 vcodec = SrsCodecVideoReserved; 239 vcodec = SrsCodecVideoReserved;
238 acodec = SrsCodecAudioReserved1; 240 acodec = SrsCodecAudioReserved1;
239 } 241 }
@@ -433,6 +435,9 @@ int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStrea @@ -433,6 +435,9 @@ int SrsTsContext::encode_pat_pmt(SrsFileWriter* writer, int16_t vpid, SrsTsStrea
433 } 435 }
434 } 436 }
435 437
  438 + // When PAT and PMT are writen, the context is ready now.
  439 + ready = true;
  440 +
436 return ret; 441 return ret;
437 } 442 }
438 443
@@ -440,6 +445,13 @@ int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t p @@ -440,6 +445,13 @@ int SrsTsContext::encode_pes(SrsFileWriter* writer, SrsTsMessage* msg, int16_t p
440 { 445 {
441 int ret = ERROR_SUCCESS; 446 int ret = ERROR_SUCCESS;
442 447
  448 + // Sometimes, the context is not ready(PAT/PMT write failed), error in this situation.
  449 + if (!ready) {
  450 + ret = ERROR_TS_CONTEXT_NOT_READY;
  451 + srs_error("TS: context not ready, ret=%d", ret);
  452 + return ret;
  453 + }
  454 +
443 if (msg->payload->length() == 0) { 455 if (msg->payload->length() == 0) {
444 return ret; 456 return ret;
445 } 457 }
@@ -3027,6 +3039,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample) @@ -3027,6 +3039,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
3027 video->payload->append((const char*)default_aud_nalu, 2); 3039 video->payload->append((const char*)default_aud_nalu, 2);
3028 } 3040 }
3029 3041
  3042 + bool is_sps_pps_appended = false;
3030 // all sample use cont nalu header, except the sps-pps before IDR frame. 3043 // all sample use cont nalu header, except the sps-pps before IDR frame.
3031 for (int i = 0; i < sample->nb_sample_units; i++) { 3044 for (int i = 0; i < sample->nb_sample_units; i++) {
3032 SrsCodecSampleUnit* sample_unit = &sample->sample_units[i]; 3045 SrsCodecSampleUnit* sample_unit = &sample->sample_units[i];
@@ -3044,7 +3057,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample) @@ -3044,7 +3057,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
3044 3057
3045 // Insert sps/pps before IDR when there is no sps/pps in samples. 3058 // Insert sps/pps before IDR when there is no sps/pps in samples.
3046 // The sps/pps is parsed from sequence header(generally the first flv packet). 3059 // The sps/pps is parsed from sequence header(generally the first flv packet).
3047 - if (nal_unit_type == SrsAvcNaluTypeIDR && !sample->has_sps_pps) { 3060 + if (nal_unit_type == SrsAvcNaluTypeIDR && !sample->has_sps_pps && !is_sps_pps_appended) {
3048 if (codec->sequenceParameterSetLength > 0) { 3061 if (codec->sequenceParameterSetLength > 0) {
3049 srs_avc_insert_aud(video->payload, aud_inserted); 3062 srs_avc_insert_aud(video->payload, aud_inserted);
3050 video->payload->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength); 3063 video->payload->append(codec->sequenceParameterSetNALUnit, codec->sequenceParameterSetLength);
@@ -3053,6 +3066,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample) @@ -3053,6 +3066,7 @@ int SrsTsCache::do_cache_avc(SrsAvcAacCodec* codec, SrsCodecSample* sample)
3053 srs_avc_insert_aud(video->payload, aud_inserted); 3066 srs_avc_insert_aud(video->payload, aud_inserted);
3054 video->payload->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength); 3067 video->payload->append(codec->pictureParameterSetNALUnit, codec->pictureParameterSetLength);
3055 } 3068 }
  3069 + is_sps_pps_appended = true;
3056 } 3070 }
3057 3071
3058 // Insert the NALU to video in annexb. 3072 // Insert the NALU to video in annexb.
@@ -346,6 +346,11 @@ public: @@ -346,6 +346,11 @@ public:
346 */ 346 */
347 class SrsTsContext 347 class SrsTsContext
348 { 348 {
  349 +private:
  350 + // Whether context is ready, failed if try to write data when not ready.
  351 + // When PAT and PMT writen, the context is ready.
  352 + // @see https://github.com/ossrs/srs/issues/834
  353 + bool ready;
349 // codec 354 // codec
350 private: 355 private:
351 std::map<int, SrsTsChannel*> pids; 356 std::map<int, SrsTsChannel*> pids;
@@ -160,9 +160,10 @@ int SrsFastBuffer::grow(ISrsBufferReader* reader, int required_size) @@ -160,9 +160,10 @@ int SrsFastBuffer::grow(ISrsBufferReader* reader, int required_size)
160 // reset when buffer is empty. 160 // reset when buffer is empty.
161 p = end = buffer; 161 p = end = buffer;
162 srs_verbose("all consumed, reset fast buffer"); 162 srs_verbose("all consumed, reset fast buffer");
163 - } else { 163 + } else if (nb_exists_bytes < nb_buffer && p > buffer) {
164 // move the left bytes to start of buffer. 164 // move the left bytes to start of buffer.
165 - srs_assert(nb_exists_bytes < nb_buffer); 165 + // @remark Only move memory when space is enough, or failed at next check.
  166 + // @see https://github.com/ossrs/srs/issues/848
166 buffer = (char*)memmove(buffer, p, nb_exists_bytes); 167 buffer = (char*)memmove(buffer, p, nb_exists_bytes);
167 p = buffer; 168 p = buffer;
168 end = p + nb_exists_bytes; 169 end = p + nb_exists_bytes;
@@ -1812,6 +1812,7 @@ string srs_client_type_string(SrsRtmpConnType type) @@ -1812,6 +1812,7 @@ string srs_client_type_string(SrsRtmpConnType type)
1812 case SrsRtmpConnPlay: return "Play"; 1812 case SrsRtmpConnPlay: return "Play";
1813 case SrsRtmpConnFlashPublish: return "flash-publish"; 1813 case SrsRtmpConnFlashPublish: return "flash-publish";
1814 case SrsRtmpConnFMLEPublish: return "fmle-publish"; 1814 case SrsRtmpConnFMLEPublish: return "fmle-publish";
  1815 + case SrsRtmpConnHaivisionPublish: return "haivision-publish";
1815 default: return "Unknown"; 1816 default: return "Unknown";
1816 } 1817 }
1817 } 1818 }
@@ -2714,6 +2715,14 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& @@ -2714,6 +2715,14 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string&
2714 } 2715 }
2715 return ret; 2716 return ret;
2716 } 2717 }
  2718 +
  2719 + // For encoder of Haivision, it always send a _checkbw call message.
  2720 + // @Remark the next message is createStream, so we continue to identify it.
  2721 + // @see https://github.com/ossrs/srs/issues/844
  2722 + if (call->command_name == "_checkbw") {
  2723 + srs_info("Haivision encoder identified.");
  2724 + continue;
  2725 + }
2717 continue; 2726 continue;
2718 } 2727 }
2719 2728
@@ -2989,6 +2998,60 @@ int SrsRtmpServer::start_fmle_publish(int stream_id) @@ -2989,6 +2998,60 @@ int SrsRtmpServer::start_fmle_publish(int stream_id)
2989 return ret; 2998 return ret;
2990 } 2999 }
2991 3000
  3001 +int SrsRtmpServer::start_haivision_publish(int stream_id)
  3002 +{
  3003 + int ret = ERROR_SUCCESS;
  3004 +
  3005 + // publish
  3006 + if (true) {
  3007 + SrsCommonMessage* msg = NULL;
  3008 + SrsPublishPacket* pkt = NULL;
  3009 + if ((ret = expect_message<SrsPublishPacket>(&msg, &pkt)) != ERROR_SUCCESS) {
  3010 + srs_error("recv publish message failed. ret=%d", ret);
  3011 + return ret;
  3012 + }
  3013 + srs_info("recv publish request message success.");
  3014 +
  3015 + SrsAutoFree(SrsCommonMessage, msg);
  3016 + SrsAutoFree(SrsPublishPacket, pkt);
  3017 + }
  3018 +
  3019 + // publish response onFCPublish(NetStream.Publish.Start)
  3020 + if (true) {
  3021 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  3022 +
  3023 + pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_PUBLISH;
  3024 + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart));
  3025 + pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream."));
  3026 +
  3027 + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) {
  3028 + srs_error("send onFCPublish(NetStream.Publish.Start) message failed. ret=%d", ret);
  3029 + return ret;
  3030 + }
  3031 + srs_info("send onFCPublish(NetStream.Publish.Start) message success.");
  3032 + }
  3033 +
  3034 + // publish response onStatus(NetStream.Publish.Start)
  3035 + if (true) {
  3036 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  3037 +
  3038 + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus));
  3039 + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart));
  3040 + pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream."));
  3041 + pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID));
  3042 +
  3043 + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) {
  3044 + srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret);
  3045 + return ret;
  3046 + }
  3047 + srs_info("send onStatus(NetStream.Publish.Start) message success.");
  3048 + }
  3049 +
  3050 + srs_info("Haivision publish success.");
  3051 +
  3052 + return ret;
  3053 +}
  3054 +
2992 int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) 3055 int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid)
2993 { 3056 {
2994 int ret = ERROR_SUCCESS; 3057 int ret = ERROR_SUCCESS;
@@ -3123,6 +3186,10 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int @@ -3123,6 +3186,10 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int
3123 srs_info("identify client by create stream, play or flash publish."); 3186 srs_info("identify client by create stream, play or flash publish.");
3124 return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration); 3187 return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration);
3125 } 3188 }
  3189 + if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
  3190 + srs_info("identify client by FCPublish, haivision publish.");
  3191 + return identify_haivision_publish_client(dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);
  3192 + }
3126 3193
3127 srs_trace("identify_create_stream_client:ignore AMF0/AMF3 command message."); 3194 srs_trace("identify_create_stream_client:ignore AMF0/AMF3 command message.");
3128 } 3195 }
@@ -3150,6 +3217,26 @@ int SrsRtmpServer::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmp @@ -3150,6 +3217,26 @@ int SrsRtmpServer::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmp
3150 return ret; 3217 return ret;
3151 } 3218 }
3152 3219
  3220 +int SrsRtmpServer::identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, string& stream_name)
  3221 +{
  3222 + int ret = ERROR_SUCCESS;
  3223 +
  3224 + type = SrsRtmpConnHaivisionPublish;
  3225 + stream_name = req->stream_name;
  3226 +
  3227 + // FCPublish response
  3228 + if (true) {
  3229 + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id);
  3230 + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) {
  3231 + srs_error("send FCPublish response message failed. ret=%d", ret);
  3232 + return ret;
  3233 + }
  3234 + srs_info("send FCPublish response message success.");
  3235 + }
  3236 +
  3237 + return ret;
  3238 +}
  3239 +
3153 int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, string& stream_name) 3240 int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, string& stream_name)
3154 { 3241 {
3155 int ret = ERROR_SUCCESS; 3242 int ret = ERROR_SUCCESS;
@@ -69,6 +69,7 @@ class SrsCommonMessage; @@ -69,6 +69,7 @@ class SrsCommonMessage;
69 class SrsPacket; 69 class SrsPacket;
70 class SrsAmf0Object; 70 class SrsAmf0Object;
71 class IMergeReadHandler; 71 class IMergeReadHandler;
  72 +class SrsCallPacket;
72 73
73 /**************************************************************************** 74 /****************************************************************************
74 ***************************************************************************** 75 *****************************************************************************
@@ -633,6 +634,7 @@ enum SrsRtmpConnType @@ -633,6 +634,7 @@ enum SrsRtmpConnType
633 SrsRtmpConnPlay, 634 SrsRtmpConnPlay,
634 SrsRtmpConnFMLEPublish, 635 SrsRtmpConnFMLEPublish,
635 SrsRtmpConnFlashPublish, 636 SrsRtmpConnFlashPublish,
  637 + SrsRtmpConnHaivisionPublish,
636 }; 638 };
637 std::string srs_client_type_string(SrsRtmpConnType type); 639 std::string srs_client_type_string(SrsRtmpConnType type);
638 bool srs_client_type_is_publish(SrsRtmpConnType type); 640 bool srs_client_type_is_publish(SrsRtmpConnType type);
@@ -992,6 +994,11 @@ public: @@ -992,6 +994,11 @@ public:
992 */ 994 */
993 virtual int start_fmle_publish(int stream_id); 995 virtual int start_fmle_publish(int stream_id);
994 /** 996 /**
  997 + * For encoder of Haivision, response the startup request.
  998 + * @see https://github.com/ossrs/srs/issues/844
  999 + */
  1000 + virtual int start_haivision_publish(int stream_id);
  1001 + /**
995 * process the FMLE unpublish event. 1002 * process the FMLE unpublish event.
996 * @unpublish_tid the unpublish request transaction id. 1003 * @unpublish_tid the unpublish request transaction id.
997 */ 1004 */
@@ -1027,6 +1034,7 @@ public: @@ -1027,6 +1034,7 @@ public:
1027 private: 1034 private:
1028 virtual int identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration); 1035 virtual int identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration);
1029 virtual int identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name); 1036 virtual int identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
  1037 + virtual int identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
1030 virtual int identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name); 1038 virtual int identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name);
1031 private: 1039 private:
1032 virtual int identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, std::string& stream_name, double& duration); 1040 virtual int identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, std::string& stream_name, double& duration);
@@ -1295,7 +1303,7 @@ public: @@ -1295,7 +1303,7 @@ public:
1295 }; 1303 };
1296 1304
1297 /** 1305 /**
1298 -* FMLE start publish: ReleaseStream/PublishStream 1306 +* FMLE start publish: ReleaseStream/PublishStream/FCPublish/FCUnpublish
1299 */ 1307 */
1300 class SrsFMLEStartPacket : public SrsPacket 1308 class SrsFMLEStartPacket : public SrsPacket
1301 { 1309 {