1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

Merge 3.0relase.

This commit is contained in:
winlin 2019-12-13 11:20:26 +08:00
commit c31c5eb05b
36 changed files with 2284 additions and 195 deletions

View file

@ -18,4 +18,3 @@ workflows:
jobs:
- build
- test

View file

@ -1,21 +0,0 @@
---
name: 提功能
about: 提功能需求,支持新的特性。
title: ''
labels: ''
assignees: ''
---
**你的功能是解决某个问题?**
请详细描述你的问题,例如在使用现有功能时碰到了困难。
**描述你期望的解决方案**
请详细描述你期望发生什么事情。
**请描述你考虑过的实现方法**
请描述你考虑过的实现方法。
**环境**
1. SRS的版本'...'
1. 操作系统:'...'

2
.gitignore vendored
View file

@ -31,3 +31,5 @@
.AppleDouble
.idea
.DS_Store

View file

@ -1,6 +1,6 @@
# SRS
![](http://ossrs.net:8000/gif/v1/sls.gif?site=github.com&path=/srs/develop)
![](http://ossrs.net/gif/v1/sls.gif?site=github.com&path=/srs/develop)
[![](https://circleci.com/gh/ossrs/srs/tree/develop.svg?style=svg&circle-token=1ef1d5b5b0cde6c8c282ed856a18199f9e8f85a9)](https://circleci.com/gh/ossrs/srs/tree/develop)
[![](https://codecov.io/gh/ossrs/srs/branch/develop/graph/badge.svg)](https://codecov.io/gh/ossrs/srs/branch/develop)
[![](https://cloud.githubusercontent.com/assets/2777660/22814959/c51cbe72-ef92-11e6-81cc-32b657b285d5.png)](https://github.com/ossrs/srs/wiki/v1_CN_Contact#wechat)
@ -147,7 +147,16 @@ For previous versions, please read:
## V3 changes
* <strong>v3.0, 2019-11-30, [3.0 alpha2(3.0.67)][r3.0a3] released. 110864 lines.</strong>
* <strong>v3.0, 2019-12-13, [3.0 alpha4(3.0.71)][r3.0a4] released. 112928 lines.</strong>
* v3.0, 2019-12-12, For [#547][bug #547], [#1506][bug #1506], default hls_dts_directly to on. 3.0.71
* v3.0, 2019-12-12, SrsPacket supports converting to message, so can be sent by one API.
* v3.0, 2019-12-11, For [#1042][bug #1042], cover RTMP client/server protocol.
* v3.0, 2019-12-11, Fix [#1445][bug #1445], limit the createStream recursive depth. 3.0.70
* v3.0, 2019-12-11, For [#1042][bug #1042], cover RTMP handshake protocol.
* v3.0, 2019-12-11, Fix [#1229][bug #1229], fix the security risk in logger. 3.0.69
* v3.0, 2019-12-11, For [#1229][bug #1229], fix the security risk in HDS. 3.0.69
* v3.0, 2019-12-05, Fix [#1506][bug #1506], support directly turn FLV timestamp to TS DTS. 3.0.68
* <strong>v3.0, 2019-11-30, [3.0 alpha3(3.0.67)][r3.0a3] released. 110864 lines.</strong>
* v3.0, 2019-12-01, Fix [#1501][bug #1501], use request coworker for origin cluster. 3.0.67
* <strong>v3.0, 2019-11-30, [3.0 alpha2(3.0.66)][r3.0a2] released. 110831 lines.</strong>
* v3.0, 2019-11-30, Fix [#1501][bug #1501], use request coworker for origin cluster. 3.0.66
@ -155,7 +164,7 @@ For previous versions, please read:
* v3.0, 2019-11-30, Refine debug info for edge. 3.0.64
* v3.0, 2019-10-30, Cover protocol stack RTMP. 3.0.63
* v3.0, 2019-10-23, Cover JSON codec. 3.0.62
* v3.0, 2019-10-13, Use http://ossrs.net:8000 as homepage.
* v3.0, 2019-10-13, Use http://ossrs.net as homepage.
* v3.0, 2019-10-10, Cover AMF0 codec. 3.0.61
* <strong>v3.0, 2019-10-07, [3.0 alpha1(3.0.60)][r3.0a1] released. 107962 lines.</strong>
* v3.0, 2019-10-06, Support log rotate by init.d command. 3.0.60
@ -224,6 +233,7 @@ For previous versions, please read:
## V2 changes
* v2.0, 2019-12-13, Support openssl versions greater than 1.1.0. 2.0.266
* <strong>v2.0, 2019-11-29, [2.0 release7(2.0.265)][r2.0r7] released. 86994 lines.</strong>
* v2.0, 2019-11-29, For [srs-docker](https://github.com/ossrs/srs-docker/tree/master/2.0), install Cherrypy without sudo. 2.0.265
* v2.0, 2019-04-06, For [#1304][bug #1304], Default HSTRS to on. 2.0.264
@ -521,7 +531,7 @@ For previous versions, please read:
* v1.0, 2014-05-27, fix [#84][bug #84], unpublish when edge disconnect. 0.9.119
* v1.0, 2014-05-27, fix [#89][bug #89], config to /dev/null to disable ffmpeg log. 0.9.117
* v1.0, 2014-05-25, fix [#76][bug #76], allow edge vhost to add or remove. 0.9.114
* v1.0, 2014-05-24, Johnny contribute [ossrs.net](http://ossrs.net:8000). karthikeyan start to translate wiki to English.
* v1.0, 2014-05-24, Johnny contribute [ossrs.net](http://ossrs.net). karthikeyan start to translate wiki to English.
* v1.0, 2014-05-22, fix [#78][bug #78], st joinable thread must be stop by other threads, 0.9.113
* v1.0, 2014-05-22, support amf0 StrictArray(0x0a). 0.9.111.
* v1.0, 2014-05-22, support flv parser, add amf0 to librtmp. 0.9.110
@ -655,7 +665,8 @@ For previous versions, please read:
## Releases
* 2019-11-30, [Release v3.0-a2][r3.0a3], 3.0 alpha2, 3.0.67, 110864 lines.
* 2019-12-13, [Release v3.0-a4][r3.0a4], 3.0 alpha4, 3.0.71, 112928 lines.
* 2019-11-30, [Release v3.0-a3][r3.0a3], 3.0 alpha3, 3.0.67, 110864 lines.
* 2019-11-30, [Release v3.0-a2][r3.0a2], 3.0 alpha2, 3.0.66, 110831 lines.
* 2019-10-07, [Release v3.0-a1][r3.0a1], 3.0 alpha1, 3.0.60, 107962 lines.
* 2019-10-04, [Release v3.0-a0][r3.0a0], 3.0 alpha0, 3.0.56, 107946 lines.
@ -1088,7 +1099,7 @@ Winlin
[srs-librtmp]: https://github.com/ossrs/srs-librtmp
[gitlab]: https://gitlab.com/winlinvip/srs-gitlab
[console]: http://ossrs.net:1985/console
[player]: http://ossrs.net:8000/players/srs_player.html
[player]: http://ossrs.net/players/srs_player.html
[modules]: https://github.com/ossrs/srs/blob/develop/trunk/modules/readme.txt
[docker-srs3]: https://github.com/ossrs/srs-docker#srs3
[docker-dev]: https://github.com/ossrs/srs-docker/tree/dev#usage
@ -1140,8 +1151,8 @@ Winlin
[v3_CN_Home]: https://github.com/ossrs/srs/wiki/v3_CN_Home
[v3_EN_Home]: https://github.com/ossrs/srs/wiki/v3_EN_Home
[donation0]: http://winlinvip.github.io/srs.release/donation/index.html
[donation1]: http://ossrs.net:8000/srs.release/donation/index.html
[donation2]: http://ossrs.net:8000/srs.release/donation/paypal.html
[donation1]: http://ossrs.net/srs.release/donation/index.html
[donation2]: http://ossrs.net/srs.release/donation/paypal.html
[donations]: https://github.com/ossrs/srs/blob/develop/DONATIONS.txt
[v1_CN_Compare]: https://github.com/ossrs/srs/wiki/v1_CN_Compare
@ -1511,6 +1522,10 @@ Winlin
[bug #1051]: https://github.com/ossrs/srs/issues/1051
[bug #1093]: https://github.com/ossrs/srs/issues/1093
[bug #1501]: https://github.com/ossrs/srs/issues/1501
[bug #1229]: https://github.com/ossrs/srs/issues/1229
[bug #1042]: https://github.com/ossrs/srs/issues/1042
[bug #1445]: https://github.com/ossrs/srs/issues/1445
[bug #1506]: https://github.com/ossrs/srs/issues/1506
[bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx
[bug #1111]: https://github.com/ossrs/srs/issues/1111
@ -1519,6 +1534,7 @@ Winlin
[exo #828]: https://github.com/google/ExoPlayer/pull/828
[r3.0a4]: https://github.com/ossrs/srs/releases/tag/v3.0-a4
[r3.0a3]: https://github.com/ossrs/srs/releases/tag/v3.0-a3
[r3.0a2]: https://github.com/ossrs/srs/releases/tag/v3.0-a2
[r3.0a1]: https://github.com/ossrs/srs/releases/tag/v3.0-a1
@ -1568,7 +1584,7 @@ Winlin
[v1_CN_Contact]: https://github.com/ossrs/srs/wiki/v1_CN_Contact
[v1_EN_Contact]: https://github.com/ossrs/srs/wiki/v1_EN_Contact
[more0]: http://winlinvip.github.io/srs.release/releases/
[more1]: http://ossrs.net:8000/srs.release/releases/
[more1]: http://ossrs.net/srs.release/releases/
[LICENSE]: https://github.com/ossrs/srs/blob/develop/LICENSE
[LicenseMixing]: https://github.com/ossrs/srs/wiki/LicenseMixing
@ -1580,5 +1596,5 @@ Winlin
[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-3.0.56.zip
[centos1]: http://ossrs.net:8000/srs.release/releases/files/SRS-CentOS6-x86_64-3.0.56.zip
[centos1]: http://ossrs.net/srs.release/releases/files/SRS-CentOS6-x86_64-3.0.56.zip

1
trunk/.gitignore vendored
View file

@ -2,6 +2,7 @@
/*.conf
/*.txt
/*.flv
/*.mp4
/doc/frozen*.flv
/doc/kungfupanda*.flv
/doc/time*.flv

View file

@ -1,25 +1,45 @@
#!/bin/bash
# In .circleci/config.yml, generate *.gcno with
# ./configure --gcov --without-research --without-librtmp
# ./configure --gcov --without-research --without-librtmp && make
# and generate *.gcda by
# ./objs/srs_utest
# Workdir is objs/cover.
workdir=`pwd`/objs/cover
# Tool git is required to map the right path.
git --version >/dev/null 2>&1
ret=$?; if [[ $ret -ne 0 ]]; then echo "Tool git is required, ret=$ret"; exit $ret; fi
# Create trunk under workdir.
mkdir -p $workdir && cd $workdir
ret=$?; if [[ $ret -ne 0 ]]; then echo "Enter workdir failed, ret=$ret"; exit $ret; fi
# Collect all *.gcno and *.gcda to objs/cover.
(mkdir -p objs/cover && cd objs/cover &&
cp -R ../../src . &&
for file in `find ../src -name "*.gcno"`; do cp $file .; done &&
for file in `find ../src -name "*.gcda"`; do cp $file .; done)
cd $workdir && (rm -rf src && cp -R ../../src . && cp -R ../src .)
ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect *.gcno and *.gcda failed, ret=$ret"; exit $ret; fi
# Generate *.gcov to objs/cover
for file in `find src -name "*.cpp"`; do
(mkdir -p objs/cover && cd objs/cover && gcov ../../$file -o .)
# Generate *.gcov for coverage.
cd $workdir &&
for file in `find src -name "*.cpp"|grep -v utest`; do
gcov $file -o `dirname $file`
ret=$?; if [[ $ret -ne 0 ]]; then echo "Collect $file failed, ret=$ret"; exit $ret; fi
done
# Cook the gcov files.
cd $workdir &&
find . -name "*.gcov"|grep -v srs|xargs rm -f
ret=$?; if [[ $ret -ne 0 ]]; then echo "Cook gcov files failed, ret=$ret"; exit $ret; fi
# Upload report with *.gcov
# Remark: The file codecov.yml is not neccessary. It literally depends on git.
# Note: The right path is like:
# https://codecov.io/gh/ossrs/srs/src/3.0release/trunk/src/protocol/srs_rtmp_stack.cpp
# https://codecov.io/gh/ossrs/srs/src/20fbb4466fdc8ba5d810b8570df6004063212838/trunk/src/protocol/srs_rtmp_stack.cpp
# Remark: It takes a few minutes to sync with github, so it might not available when CircleCI is done.
# https://circleci.com/gh/ossrs/srs/tree/3.0release
cd $workdir &&
export CODECOV_TOKEN="493bba46-c468-4e73-8b45-8cdd8ff62d96" &&
mkdir -p objs/cover && cd objs/cover &&
bash <(curl -s https://codecov.io/bash)
exit 0
bash <(curl -s https://codecov.io/bash) &&
echo "Done" && exit 0

View file

@ -1084,9 +1084,8 @@ vhost hls.srs.com {
# whether cleanup the old expired ts files.
# default: on
hls_cleanup on;
# the timeout in seconds to dispose the hls,
# dispose is to remove all hls files, m3u8 and ts files.
# when publisher timeout dispose hls.
# If there is no incoming packets, dispose HLS in this timeout in seconds,
# which removes all HLS files including m3u8 and ts files.
# @remark 0 to disable dispose for publisher.
# @remark apply for publisher timeout only, while "etc/init.d/srs stop" always dispose hls.
# default: 0
@ -1123,6 +1122,15 @@ vhost hls.srs.com {
# @remark It's optional.
hls_key_url https://localhost:8080;
# Special control controls.
###########################################
# Whether calculate the DTS of audio frame directly.
# If on, guess the specific DTS by AAC samples, please read https://github.com/ossrs/srs/issues/547#issuecomment-294350544
# If off, directly turn the FLV timestamp to DTS, which might cause corrupt audio stream.
# @remark Recommend to set to off, unless your audio stream sample-rate and timestamp is not correct.
# Default: on
hls_dts_directly on;
# on_hls, never config in here, should config in http_hooks.
# for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com
# @read https://github.com/ossrs/srs/wiki/v2_CN_DeliveryHLS#http-callback

View file

@ -94,7 +94,7 @@
</script>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/jwplayer'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/jwplayer'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -15,7 +15,7 @@
</style>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/osmf'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/osmf'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -15,7 +15,7 @@
</style>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/bwt'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/bwt'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -14,7 +14,7 @@
</style>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/chat'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/chat'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -25,7 +25,7 @@
</style>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/srsplayer'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/srsplayer'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -11,7 +11,7 @@
</style>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/srspublisher'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/srspublisher'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -11,7 +11,7 @@
</style>
</head>
<body>
<img src='https://srs.cn-beijing.log.aliyuncs.com/logstores/ossrs-net/track_ua.gif?APIVersion=0.6.0&site=ossrs.net&path=/player/vlc'/>
<img src='https://ossrs.net:8443/gif/v1/sls.gif?site=ossrs.net&path=/player/vlc'/>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">

View file

@ -2589,6 +2589,8 @@ srs_error_t SrsConfig::vhost_to_json(SrsConfDirective* vhost, SrsJsonObject* obj
hls->set("hls_dispose", sdir->dumps_arg0_to_number());
} else if (sdir->name == "hls_nb_notify") {
hls->set("hls_nb_notify", sdir->dumps_arg0_to_integer());
} else if (sdir->name == "hls_dts_directly") {
hls->set("hls_dts_directly", sdir->dumps_arg0_to_boolean());
} else if (sdir->name == "hls_wait_keyframe") {
hls->set("hls_wait_keyframe", sdir->dumps_arg0_to_boolean());
} else if (sdir->name == "hls_keys") {
@ -3751,7 +3753,7 @@ srs_error_t SrsConfig::check_normal_config()
&& m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
&& m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
&& m != "hls_wait_keyframe" && m != "hls_dispose" && m != "hls_keys" && m != "hls_fragments_per_key" && m != "hls_key_file"
&& m != "hls_key_file_path" && m != "hls_key_url") {
&& m != "hls_key_file_path" && m != "hls_key_url" && m != "hls_dts_directly") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.hls.%s of %s", m.c_str(), vhost->arg0().c_str());
}
@ -6148,6 +6150,23 @@ int SrsConfig::get_vhost_hls_nb_notify(string vhost)
return ::atoi(conf->arg0().c_str());
}
bool SrsConfig::get_vhost_hls_dts_directly(string vhost)
{
static bool DEFAULT = true;
SrsConfDirective* conf = get_hls(vhost);
if (!conf) {
return DEFAULT;
}
conf = conf->get("hls_dts_directly");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
bool SrsConfig::get_hls_cleanup(string vhost)
{
static bool DEFAULT = true;

View file

@ -825,6 +825,8 @@ public:
// Get the size of bytes to read from cdn network, for the on_hls_notify callback,
// that is, to read max bytes of the bytes from the callback, or timeout or error.
virtual int get_vhost_hls_nb_notify(std::string vhost);
// Whether turn the FLV timestamp to TS DTS.
virtual bool get_vhost_hls_dts_directly(std::string vhost);
// hds section
private:
// Get the hds directive of vhost.

View file

@ -200,7 +200,7 @@ public:
inline void set_index(int idx)
{
char file_path[1024] = {0};
sprintf(file_path, "%s/%s/%sSeg1-Frag%d", _srs_config->get_hds_path(req->vhost).c_str()
snprintf(file_path, 1024, "%s/%s/%sSeg1-Frag%d", _srs_config->get_hds_path(req->vhost).c_str()
, req->app.c_str(), req->stream.c_str(), idx);
path = file_path;
@ -428,7 +428,7 @@ srs_error_t SrsHds::flush_mainfest()
srs_error_t err = srs_success;
char buf[1024] = {0};
sprintf(buf, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
snprintf(buf, 1024, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
"<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n\t"
"<id>%s.f4m</id>\n\t"
"<streamType>live</streamType>\n\t"

View file

@ -910,9 +910,13 @@ srs_error_t SrsHlsController::on_publish(SrsRequest* req)
if ((err = muxer->segment_open()) != srs_success) {
return srs_error_wrap(err, "hls: segment open");
}
srs_trace("hls: win=%dms, frag=%dms, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d, clean=%d, waitk=%d, dispose=%dms",
srsu2msi(hls_window), srsu2msi(hls_fragment), entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(),
ts_file.c_str(), hls_aof_ratio, ts_floor, cleanup, wait_keyframe, srsu2msi(hls_dispose));
// This config item is used in SrsHls, we just log its value here.
bool hls_dts_directly = _srs_config->get_vhost_hls_dts_directly(req->vhost);
srs_trace("hls: win=%dms, frag=%dms, prefix=%s, path=%s, m3u8=%s, ts=%s, aof=%.2f, floor=%d, clean=%d, waitk=%d, dispose=%dms, dts_directly=%d",
srsu2msi(hls_window), srsu2msi(hls_fragment), entry_prefix.c_str(), path.c_str(), m3u8_file.c_str(), ts_file.c_str(),
hls_aof_ratio, ts_floor, cleanup, wait_keyframe, srsu2msi(hls_dispose), hls_dts_directly);
return err;
}
@ -1062,6 +1066,7 @@ SrsHls::SrsHls()
enabled = false;
disposable = false;
last_update_time = 0;
hls_dts_directly = false;
previous_audio_dts = 0;
aac_samples = 0;
@ -1160,6 +1165,10 @@ srs_error_t SrsHls::on_publish()
if ((err = controller->on_publish(req)) != srs_success) {
return srs_error_wrap(err, "hls: on publish");
}
// If enabled, directly turn FLV timestamp to TS DTS.
// @remark It'll be reloaded automatically, because the origin hub will republish while reloading.
hls_dts_directly = _srs_config->get_vhost_hls_dts_directly(req->vhost);
// if enabled, open the muxer.
enabled = true;
@ -1194,6 +1203,12 @@ srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
if (!enabled) {
return err;
}
// Ignore if no format->acodec, it means the codec is not parsed, or unknown codec.
// @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474
if (!format->acodec) {
return err;
}
// update the hls time, for hls_dispose.
last_update_time = srs_get_system_time();
@ -1202,7 +1217,6 @@ srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
SrsAutoFree(SrsSharedPtrMessage, audio);
// ts support audio codec: aac/mp3
srs_assert(format->acodec);
SrsAudioCodecId acodec = format->acodec->id;
if (acodec != SrsAudioCodecIdAAC && acodec != SrsAudioCodecIdMP3) {
return err;
@ -1224,18 +1238,38 @@ srs_error_t SrsHls::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* forma
previous_audio_dts = audio->timestamp;
aac_samples = 0;
}
// Use the diff to guess whether the samples is 1024 or 960.
int nb_samples_per_frame = 1024;
int diff = ::abs((int)(audio->timestamp - previous_audio_dts)) * srs_flv_srates[format->acodec->sound_rate];
// The diff duration in ms between two FLV audio packets.
int diff = ::abs((int)(audio->timestamp - previous_audio_dts));
previous_audio_dts = audio->timestamp;
if (diff > 100 && diff < 950) {
nb_samples_per_frame = 960;
// Guess the number of samples for each AAC frame.
// If samples is 1024, the sample-rate is 8000HZ, the diff should be 1024/8000s=128ms.
// If samples is 1024, the sample-rate is 44100HZ, the diff should be 1024/44100s=23ms.
// If samples is 2048, the sample-rate is 44100HZ, the diff should be 2048/44100s=46ms.
int nb_samples_per_frame = 0;
int guessNumberOfSamples = diff * srs_flv_srates[format->acodec->sound_rate] / 1000;
if (guessNumberOfSamples > 0) {
if (guessNumberOfSamples < 960) {
nb_samples_per_frame = 960;
} else if (guessNumberOfSamples < 1536) {
nb_samples_per_frame = 1024;
} else if (guessNumberOfSamples < 3072) {
nb_samples_per_frame = 2048;
} else {
nb_samples_per_frame = 4096;
}
}
// Recalc the DTS by the samples of AAC.
int64_t dts = 90000 * aac_samples / srs_flv_srates[format->acodec->sound_rate];
aac_samples += nb_samples_per_frame;
int64_t dts = 90000 * aac_samples / srs_flv_srates[format->acodec->sound_rate];
// If directly turn FLV timestamp, overwrite the guessed DTS.
// @doc https://github.com/ossrs/srs/issues/1506#issuecomment-562063095
if (hls_dts_directly) {
dts = audio->timestamp * 90;
}
if ((err = controller->write_audio(format->audio, dts)) != srs_success) {
return srs_error_wrap(err, "hls: write audio");
@ -1251,7 +1285,13 @@ srs_error_t SrsHls::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* forma
if (!enabled) {
return err;
}
// Ignore if no format->vcodec, it means the codec is not parsed, or unknown codec.
// @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474
if (!format->vcodec) {
return err;
}
// update the hls time, for hls_dispose.
last_update_time = srs_get_system_time();

View file

@ -288,6 +288,8 @@ private:
int64_t previous_audio_dts;
// The total aac samples.
uint64_t aac_samples;
// Whether directly turn FLV timestamp to TS DTS.
bool hls_dts_directly;
private:
SrsOriginHub* hub;
SrsRtmpJitter* jitter;

View file

@ -192,7 +192,8 @@ void SrsFastLog::error(const char* tag, int context_id, const char* fmt, ...)
va_end(ap);
// add strerror() to error msg.
if (errno != 0) {
// Check size to avoid security issue https://github.com/ossrs/srs/issues/1229
if (errno != 0 && size < LOG_MAX_SIZE) {
size += snprintf(log_data + size, LOG_MAX_SIZE - size, "(%s)", strerror(errno));
}

View file

@ -27,7 +27,7 @@
// The version config.
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
#define VERSION_REVISION 67
#define VERSION_REVISION 71
// The macros generated by configure script.
#include <srs_auto_headers.hpp>

View file

@ -95,6 +95,8 @@ private:
int nb_bytes;
public:
SrsBuffer();
// Initialize buffer with data b and size nb_b.
// @remark User must free the data b.
SrsBuffer(char* b, int nb_b);
virtual ~SrsBuffer();
// get the status of stream

View file

@ -177,7 +177,8 @@
#define ERROR_HTTP_HIJACK 2052
#define ERROR_RTMP_MESSAGE_CREATE 2053
#define ERROR_RTMP_PROXY_EXCEED 2054
//
#define ERROR_RTMP_CREATE_STREAM_DEPTH 2055
//
// The system control message,
// It's not an error, but special control logic.
//

View file

@ -37,6 +37,7 @@ class SrsBuffer;
class ISrsWriter;
class ISrsReader;
class SrsFileReader;
class SrsPacket;
#define SRS_FLV_TAG_HEADER_SIZE 11
#define SRS_FLV_PREVIOUS_TAG_SIZE 4
@ -231,8 +232,9 @@ public:
// The message header for shared ptr message.
// only the message for all msgs are same.
struct SrsSharedMessageHeader
class SrsSharedMessageHeader
{
public:
// 3bytes.
// Three-byte field that represents the size of the payload in bytes.
// It is set in big-endian format.
@ -245,7 +247,7 @@ struct SrsSharedMessageHeader
// set at decoding, and canbe used for directly send message,
// For example, dispatch to all connections.
int perfer_cid;
public:
SrsSharedMessageHeader();
virtual ~SrsSharedMessageHeader();
};
@ -309,6 +311,7 @@ public:
// copy header, manage the payload of msg,
// set the payload to NULL to prevent double free.
// @remark payload of msg set to NULL if success.
// @remark User should free the msg.
virtual srs_error_t create(SrsCommonMessage* msg);
// Create shared ptr message,
// from the header and payload.

View file

@ -64,9 +64,9 @@ void SrsSimpleStream::erase(int size)
void SrsSimpleStream::append(const char* bytes, int size)
{
srs_assert(size > 0);
data.insert(data.end(), bytes, bytes + size);
if (size > 0) {
data.insert(data.end(), bytes, bytes + size);
}
}
void SrsSimpleStream::append(SrsSimpleStream* src)

View file

@ -200,9 +200,9 @@ string srs_generate_stream_with_query(string host, string vhost, string stream,
// Remove the start & when param is empty.
srs_string_trim_start(query, "&");
// Prefix query with ?.
if (!srs_string_starts_with(query, "?")) {
if (!query.empty() && !srs_string_starts_with(query, "?")) {
url += "?";
}

View file

@ -137,7 +137,7 @@ namespace _srs_internal
0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB,
0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
}; // 62
srs_error_t do_openssl_HMACsha256(HMAC_CTX* ctx, const void* data, int data_size, void* digest, unsigned int* digest_size)
{
srs_error_t err = srs_success;
@ -152,6 +152,7 @@ namespace _srs_internal
return err;
}
/**
* sha256 digest algorithm.
* @param key the sha256 key, NULL to use EVP_Digest, for instance,
@ -201,24 +202,24 @@ namespace _srs_internal
return err;
}
#define RFC2409_PRIME_1024 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
"FFFFFFFFFFFFFFFF"
#define RFC2409_PRIME_1024 \
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
"FFFFFFFFFFFFFFFF"
SrsDH::SrsDH()
{
pdh = NULL;
}
SrsDH::~SrsDH()
{
close();
}
void SrsDH::close()
{
if (pdh != NULL) {

View file

@ -137,6 +137,36 @@ SrsPacket::~SrsPacket()
{
}
srs_error_t SrsPacket::to_msg(SrsCommonMessage* msg, int stream_id)
{
srs_error_t err = srs_success;
int size = 0;
char* payload = NULL;
if ((err = encode(size, payload)) != srs_success) {
return srs_error_wrap(err, "encode packet");
}
// encode packet to payload and size.
if (size <= 0 || payload == NULL) {
srs_warn("packet is empty, ignore empty message.");
return err;
}
// to message
SrsMessageHeader header;
header.payload_length = size;
header.message_type = get_message_type();
header.stream_id = stream_id;
header.perfer_cid = get_prefer_cid();
if ((err = msg->create(&header, payload, size)) != srs_success) {
return srs_error_wrap(err, "create %dB message", size);
}
return err;
}
srs_error_t SrsPacket::encode(int& psize, char*& ppayload)
{
srs_error_t err = srs_success;
@ -570,70 +600,26 @@ srs_error_t SrsProtocol::do_send_and_free_packet(SrsPacket* packet, int stream_i
srs_assert(packet);
SrsAutoFree(SrsPacket, packet);
int size = 0;
char* payload = NULL;
if ((err = packet->encode(size, payload)) != srs_success) {
return srs_error_wrap(err, "encode packet");
}
// encode packet to payload and size.
if (size <= 0 || payload == NULL) {
srs_warn("packet is empty, ignore empty message.");
return err;
}
// to message
SrsMessageHeader header;
header.payload_length = size;
header.message_type = packet->get_message_type();
header.stream_id = stream_id;
header.perfer_cid = packet->get_prefer_cid();
err = do_simple_send(&header, payload, size);
srs_freepa(payload);
if (err != srs_success) {
return srs_error_wrap(err, "simple send");
}
if ((err = on_send_packet(&header, packet)) != srs_success) {
return srs_error_wrap(err, "on send packet");
}
return err;
}
srs_error_t SrsProtocol::do_simple_send(SrsMessageHeader* mh, char* payload, int size)
{
srs_error_t err = srs_success;
SrsCommonMessage* msg = new SrsCommonMessage();
SrsAutoFree(SrsCommonMessage, msg);
if ((err = packet->to_msg(msg, stream_id)) != srs_success) {
return srs_error_wrap(err, "to message");
}
SrsSharedPtrMessage* shared_msg = new SrsSharedPtrMessage();
if ((err = shared_msg->create(msg)) != srs_success) {
srs_freep(shared_msg);
return srs_error_wrap(err, "create message");
}
if ((err = send_and_free_message(shared_msg, stream_id)) != srs_success) {
return srs_error_wrap(err, "send packet");
}
// we directly send out the packet,
// use very simple algorithm, not very fast,
// but it's ok.
char* p = payload;
char* end = p + size;
char c0c3[SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE];
while (p < end) {
int nbh = 0;
if (p == payload) {
nbh = srs_chunk_header_c0(mh->perfer_cid, (uint32_t)mh->timestamp, mh->payload_length, mh->message_type, mh->stream_id, c0c3, sizeof(c0c3));
} else {
nbh = srs_chunk_header_c3(mh->perfer_cid, (uint32_t)mh->timestamp, c0c3, sizeof(c0c3));
}
srs_assert(nbh > 0);;
iovec iovs[2];
iovs[0].iov_base = c0c3;
iovs[0].iov_len = nbh;
int payload_size = srs_min((int)(end - p), out_chunk_size);
iovs[1].iov_base = p;
iovs[1].iov_len = payload_size;
p += payload_size;
if ((err = skt->writev(iovs, 2, NULL)) != srs_success) {
return srs_error_wrap(err, "writev packet");
}
if ((err = on_send_packet(&msg->header, packet)) != srs_success) {
return srs_error_wrap(err, "on send packet");
}
return err;
@ -788,6 +774,9 @@ srs_error_t SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsBuffer*
} else if (header.is_window_ackledgement_size()) {
*ppacket = packet = new SrsSetWindowAckSizePacket();
return packet->decode(stream);
} else if (header.is_ackledgement()) {
*ppacket = packet = new SrsAcknowledgementPacket();
return packet->decode(stream);
} else if (header.is_set_chunk_size()) {
*ppacket = packet = new SrsSetChunkSizePacket();
return packet->decode(stream);
@ -1671,7 +1660,7 @@ void SrsHandshakeBytes::dispose()
srs_freepa(c2);
}
srs_error_t SrsHandshakeBytes::read_c0c1(ISrsProtocolReadWriter* io)
srs_error_t SrsHandshakeBytes::read_c0c1(ISrsProtocolReader* io)
{
srs_error_t err = srs_success;
@ -1709,7 +1698,7 @@ srs_error_t SrsHandshakeBytes::read_c0c1(ISrsProtocolReadWriter* io)
return err;
}
srs_error_t SrsHandshakeBytes::read_s0s1s2(ISrsProtocolReadWriter* io)
srs_error_t SrsHandshakeBytes::read_s0s1s2(ISrsProtocolReader* io)
{
srs_error_t err = srs_success;
@ -1727,7 +1716,7 @@ srs_error_t SrsHandshakeBytes::read_s0s1s2(ISrsProtocolReadWriter* io)
return err;
}
srs_error_t SrsHandshakeBytes::read_c2(ISrsProtocolReadWriter* io)
srs_error_t SrsHandshakeBytes::read_c2(ISrsProtocolReader* io)
{
srs_error_t err = srs_success;
@ -2538,7 +2527,7 @@ srs_error_t SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type,
SrsAutoFree(SrsPacket, pkt);
if (dynamic_cast<SrsCreateStreamPacket*>(pkt)) {
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration);
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, 3, type, stream_name, duration);
}
if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
return identify_fmle_publish_client(dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);
@ -2546,6 +2535,7 @@ srs_error_t SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type,
if (dynamic_cast<SrsPlayPacket*>(pkt)) {
return identify_play_client(dynamic_cast<SrsPlayPacket*>(pkt), type, stream_name, duration);
}
// call msg,
// support response null first,
// @see https://github.com/ossrs/srs/issues/106
@ -2698,7 +2688,7 @@ srs_error_t SrsRtmpServer::on_play_client_pause(int stream_id, bool is_pause)
return srs_error_wrap(err, "send NetStream.Unpause.Notify");
}
}
// StreanBegin
// StreamBegin
if (true) {
SrsUserControlPacket* pkt = new SrsUserControlPacket();
@ -2909,9 +2899,13 @@ srs_error_t SrsRtmpServer::start_flash_publish(int stream_id)
return err;
}
srs_error_t SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, string& stream_name, srs_utime_t& duration)
srs_error_t SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, int depth, SrsRtmpConnType& type, string& stream_name, srs_utime_t& duration)
{
srs_error_t err = srs_success;
if (depth <= 0) {
return srs_error_new(ERROR_RTMP_CREATE_STREAM_DEPTH, "create stream recursive depth");
}
if (true) {
SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(req->transaction_id, stream_id);
@ -2952,7 +2946,7 @@ srs_error_t SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket*
return identify_flash_publish_client(dynamic_cast<SrsPublishPacket*>(pkt), type, stream_name);
}
if (dynamic_cast<SrsCreateStreamPacket*>(pkt)) {
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration);
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, depth-1, type, stream_name, duration);
}
if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
return identify_haivision_publish_client(dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);

View file

@ -49,6 +49,7 @@ class SrsChunkStream;
class SrsSharedPtrMessage;
class SrsProtocol;
class ISrsProtocolReader;
class ISrsProtocolReadWriter;
class SrsCreateStreamPacket;
class SrsFMLEStartPacket;
@ -114,6 +115,9 @@ class SrsPacket
public:
SrsPacket();
virtual ~SrsPacket();
public:
// Covert packet to common message.
virtual srs_error_t to_msg(SrsCommonMessage* msg, int stream_id);
public:
// The subpacket can override this encode,
// For example, video and audio will directly set the payload withou memory copy,
@ -355,9 +359,6 @@ private:
virtual srs_error_t do_iovs_send(iovec* iovs, int size);
// The underlayer api for send and free packet.
virtual srs_error_t do_send_and_free_packet(SrsPacket* packet, int stream_id);
// Use simple algorithm to send the header and bytes.
// @remark, for do_send_and_free_packet to send.
virtual srs_error_t do_simple_send(SrsMessageHeader* mh, char* payload, int size);
// The imp for decode_message
virtual srs_error_t do_decode_message(SrsMessageHeader& header, SrsBuffer* stream, SrsPacket** ppacket);
// Recv bytes oriented RTMP message from protocol stack.
@ -514,9 +515,9 @@ public:
public:
virtual void dispose();
public:
virtual srs_error_t read_c0c1(ISrsProtocolReadWriter* io);
virtual srs_error_t read_s0s1s2(ISrsProtocolReadWriter* io);
virtual srs_error_t read_c2(ISrsProtocolReadWriter* io);
virtual srs_error_t read_c0c1(ISrsProtocolReader* io);
virtual srs_error_t read_s0s1s2(ISrsProtocolReader* io);
virtual srs_error_t read_c2(ISrsProtocolReader* io);
virtual srs_error_t create_c0c1();
virtual srs_error_t create_s0s1s2(const char* c1 = NULL);
virtual srs_error_t create_c2();
@ -774,7 +775,7 @@ public:
return protocol->expect_message<T>(pmsg, ppacket);
}
private:
virtual srs_error_t identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, srs_utime_t& duration);
virtual srs_error_t identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, int depth, SrsRtmpConnType& type, std::string& stream_name, srs_utime_t& duration);
virtual srs_error_t identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
virtual srs_error_t identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
virtual srs_error_t identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name);

View file

@ -255,6 +255,12 @@ bool srs_log_header(char* buffer, int size, bool utc, bool dangerous, const char
level, getpid(), cid);
}
}
// Exceed the size, ignore this log.
// Check size to avoid security issue https://github.com/ossrs/srs/issues/1229
if (written >= size) {
return false;
}
if (written == -1) {
return false;

View file

@ -52,6 +52,15 @@ extern srs_utime_t _srs_tmp_timeout;
#define HELPER_EXPECT_SUCCESS(x) EXPECT_TRUE(srs_success == (err = x)); srs_freep(err)
#define HELPER_EXPECT_FAILED(x) EXPECT_TRUE(srs_success != (err = x)); srs_freep(err)
// For errors, assert.
// @remark The err is leak when error, but it's ok in utest.
#define HELPER_ASSERT_SUCCESS(x) ASSERT_TRUE(srs_success == (err = x)); srs_freep(err)
#define HELPER_ASSERT_FAILED(x) ASSERT_TRUE(srs_success != (err = x)); srs_freep(err)
// For init array data.
#define HELPER_ARRAY_INIT(buf, sz, val) \
for (int i = 0; i < (int)sz; i++) (buf)[i]=val
// the asserts of gtest:
// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2

View file

@ -64,3 +64,30 @@ VOID TEST(CoreMacroseTest, Check)
#endif
}
VOID TEST(CoreLogger, CheckVsnprintf)
{
if (true) {
char buf[1024];
HELPER_ARRAY_INIT(buf, sizeof(buf), 0xf);
// Return the number of characters printed.
EXPECT_EQ(6, sprintf(buf, "%s", "Hello!"));
EXPECT_EQ('H', buf[0]);
EXPECT_EQ('!', buf[5]);
EXPECT_EQ(0x0, buf[6]);
EXPECT_EQ(0xf, buf[7]);
}
if (true) {
char buf[1024];
HELPER_ARRAY_INIT(buf, sizeof(buf), 0xf);
// Return the number of characters that would have been printed if the size were unlimited.
EXPECT_EQ(6, snprintf(buf, 3, "%s", "Hello!"));
EXPECT_EQ('H', buf[0]);
EXPECT_EQ('e', buf[1]);
EXPECT_EQ(0, buf[2]);
EXPECT_EQ(0xf, buf[3]);
}
}

File diff suppressed because one or more lines are too long

View file

@ -87,7 +87,15 @@ public:
MockBufferIO();
virtual ~MockBufferIO();
public:
virtual int length();
virtual MockBufferIO* append(std::string data);
virtual MockBufferIO* append(MockBufferIO* data);
virtual MockBufferIO* append(uint8_t* data, int size);
public:
virtual int out_length();
virtual MockBufferIO* out_append(std::string data);
virtual MockBufferIO* out_append(MockBufferIO* data);
virtual MockBufferIO* out_append(uint8_t* data, int size);
// for handshake.
public:
virtual srs_error_t read_fully(void* buf, size_t size, ssize_t* nread);

File diff suppressed because one or more lines are too long