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

Merge branch 'master' of github.com:winlinvip/simple-rtmp-server

This commit is contained in:
winlin 2014-03-20 09:41:13 +08:00
commit c63ad48893
11 changed files with 1170 additions and 1020 deletions

View file

@ -167,6 +167,8 @@ See also: [Performance Test Guide](https://github.com/winlinvip/simple-rtmp-serv
* nginx v1.5.0: 139524 lines <br/> * nginx v1.5.0: 139524 lines <br/>
### History ### History
* v1.0, 2014-03-19, add vn/an for FFMPEG to drop video/audio for radio stream.
* v1.0, 2014-03-19, refine handshake, client support coplex handshake, add utest.
* v1.0, 2014-03-16, support ARM([debian armhf, v7cpu](https://github.com/winlinvip/simple-rtmp-server/wiki/SrsLinuxArm)) with rtmp/ssl/hls/librtmp. * v1.0, 2014-03-16, support ARM([debian armhf, v7cpu](https://github.com/winlinvip/simple-rtmp-server/wiki/SrsLinuxArm)) with rtmp/ssl/hls/librtmp.
* v1.0, 2014-03-12, finish utest for amf0 codec. * v1.0, 2014-03-12, finish utest for amf0 codec.
* v1.0, 2014-03-06, add gperftools for mem leak detect, mem/cpu profile. * v1.0, 2014-03-06, add gperftools for mem leak detect, mem/cpu profile.

21
trunk/conf/full.conf Normal file → Executable file
View file

@ -291,6 +291,25 @@ vhost audio.transcode.vhost.com {
} }
} }
} }
# disable video, transcode/copy audio.
# for example, publish pure audio stream.
vhost vn.transcode.vhost.com {
transcode {
enabled on;
ffmpeg ./objs/ffmpeg/bin/ffmpeg;
engine vn {
enabled on;
vcodec vn;
acodec libaacplus;
abitrate 45;
asample_rate 44100;
achannels 2;
aparams {
}
output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine];
}
}
}
# ffmpeg-copy(forward implements by ffmpeg). # ffmpeg-copy(forward implements by ffmpeg).
# copy the video and audio to a new stream. # copy the video and audio to a new stream.
vhost copy.transcode.vhost.com { vhost copy.transcode.vhost.com {
@ -333,6 +352,7 @@ vhost all.transcode.vhost.com {
# video encoder name. can be: # video encoder name. can be:
# libx264: use h.264(libx264) video encoder. # libx264: use h.264(libx264) video encoder.
# copy: donot encoder the video stream, copy it. # copy: donot encoder the video stream, copy it.
# vn: disable video output.
vcodec libx264; vcodec libx264;
# video bitrate, in kbps # video bitrate, in kbps
vbitrate 1500; vbitrate 1500;
@ -364,6 +384,7 @@ vhost all.transcode.vhost.com {
# audio encoder name. can be: # audio encoder name. can be:
# libaacplus: use aac(libaacplus) audio encoder. # libaacplus: use aac(libaacplus) audio encoder.
# copy: donot encoder the audio stream, copy it. # copy: donot encoder the audio stream, copy it.
# an: disable audio output.
acodec libaacplus; acodec libaacplus;
# audio bitrate, in kbps. [16, 72] for libaacplus. # audio bitrate, in kbps. [16, 72] for libaacplus.
abitrate 70; abitrate 70;

0
trunk/conf/srs.conf Normal file → Executable file
View file

View file

@ -42,6 +42,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifdef SRS_FFMPEG #ifdef SRS_FFMPEG
#define SRS_ENCODER_COPY "copy" #define SRS_ENCODER_COPY "copy"
#define SRS_ENCODER_NO_VIDEO "vn"
#define SRS_ENCODER_NO_AUDIO "an"
#define SRS_ENCODER_VCODEC "libx264" #define SRS_ENCODER_VCODEC "libx264"
#define SRS_ENCODER_ACODEC "libaacplus" #define SRS_ENCODER_ACODEC "libaacplus"
@ -138,7 +140,13 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine)
} }
_transcoded_url.push_back(output); _transcoded_url.push_back(output);
if (vcodec != SRS_ENCODER_COPY) { if (vcodec == SRS_ENCODER_NO_VIDEO && acodec == SRS_ENCODER_NO_AUDIO) {
ret = ERROR_ENCODER_VCODEC;
srs_warn("video and audio disabled. ret=%d", ret);
return ret;
}
if (vcodec != SRS_ENCODER_COPY && vcodec != SRS_ENCODER_NO_VIDEO) {
if (vcodec != SRS_ENCODER_VCODEC) { if (vcodec != SRS_ENCODER_VCODEC) {
ret = ERROR_ENCODER_VCODEC; ret = ERROR_ENCODER_VCODEC;
srs_error("invalid vcodec, must be %s, actual %s, ret=%d", srs_error("invalid vcodec, must be %s, actual %s, ret=%d",
@ -182,7 +190,7 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine)
} }
} }
if (acodec != SRS_ENCODER_COPY) { if (acodec != SRS_ENCODER_COPY && acodec != SRS_ENCODER_NO_AUDIO) {
if (acodec != SRS_ENCODER_ACODEC) { if (acodec != SRS_ENCODER_ACODEC) {
ret = ERROR_ENCODER_ACODEC; ret = ERROR_ENCODER_ACODEC;
srs_error("invalid acodec, must be %s, actual %s, ret=%d", srs_error("invalid acodec, must be %s, actual %s, ret=%d",
@ -254,11 +262,15 @@ int SrsFFMPEG::start()
} }
// video specified. // video specified.
params.push_back("-vcodec"); if (vcodec != SRS_ENCODER_NO_VIDEO) {
params.push_back(vcodec); params.push_back("-vcodec");
params.push_back(vcodec);
} else {
params.push_back("-vn");
}
// the codec params is disabled when copy // the codec params is disabled when copy
if (vcodec != SRS_ENCODER_COPY) { if (vcodec != SRS_ENCODER_COPY && vcodec != SRS_ENCODER_NO_VIDEO) {
params.push_back("-b:v"); params.push_back("-b:v");
snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000); snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000);
params.push_back(tmp); params.push_back(tmp);
@ -299,11 +311,15 @@ int SrsFFMPEG::start()
} }
// audio specified. // audio specified.
params.push_back("-acodec"); if (acodec != SRS_ENCODER_NO_AUDIO) {
params.push_back(acodec); params.push_back("-acodec");
params.push_back(acodec);
} else {
params.push_back("-an");
}
// the codec params is disabled when copy // the codec params is disabled when copy
if (acodec != SRS_ENCODER_COPY) { if (acodec != SRS_ENCODER_COPY && acodec != SRS_ENCODER_NO_AUDIO) {
params.push_back("-b:a"); params.push_back("-b:a");
snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000); snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000);
params.push_back(tmp); params.push_back(tmp);

View file

@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// current release version // current release version
#define VERSION_MAJOR "0" #define VERSION_MAJOR "0"
#define VERSION_MINOR "9" #define VERSION_MINOR "9"
#define VERSION_REVISION "21" #define VERSION_REVISION "22"
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
// server info. // server info.
#define RTMP_SIG_SRS_KEY "srs" #define RTMP_SIG_SRS_KEY "srs"

File diff suppressed because it is too large Load diff

View file

@ -97,6 +97,78 @@ namespace srs
int random1_size; int random1_size;
}; };
// the digest key generate size.
#define OpensslHashSize 512
extern u_int8_t SrsGenuineFMSKey[];
extern u_int8_t SrsGenuineFPKey[];
int openssl_HMACsha256(const void* data, int data_size, const void* key, int key_size, void* digest);
int openssl_generate_key(char* _private_key, char* _public_key, int32_t size);
// calc the offset of key,
// the key->offset cannot be used as the offset of key.
int srs_key_block_get_offset(key_block* key);
// create new key block data.
// if created, user must free it by srs_key_block_free
void srs_key_block_init(key_block* key);
// parse key block from c1s1.
// if created, user must free it by srs_key_block_free
// @c1s1_key_bytes the key start bytes, maybe c1s1 or c1s1+764
int srs_key_block_parse(key_block* key, char* c1s1_key_bytes);
// free the block data create by
// srs_key_block_init or srs_key_block_parse
void srs_key_block_free(key_block* key);
// calc the offset of digest,
// the key->offset cannot be used as the offset of digest.
int srs_digest_block_get_offset(digest_block* digest);
// create new digest block data.
// if created, user must free it by srs_digest_block_free
void srs_digest_block_init(digest_block* digest);
// parse digest block from c1s1.
// if created, user must free it by srs_digest_block_free
// @c1s1_digest_bytes the digest start bytes, maybe c1s1 or c1s1+764
int srs_digest_block_parse(digest_block* digest, char* c1s1_digest_bytes);
// free the block data create by
// srs_digest_block_init or srs_digest_block_parse
void srs_digest_block_free(digest_block* digest);
/**
* copy whole c1s1 to bytes.
*/
void srs_schema0_copy_to(char* bytes, bool with_digest,
int32_t time, int32_t version, key_block* key, digest_block* digest);
void srs_schema1_copy_to(char* bytes, bool with_digest,
int32_t time, int32_t version, digest_block* digest, key_block* key);
/**
* c1s1 is splited by digest:
* c1s1-part1: n bytes (time, version, key and digest-part1).
* digest-data: 32bytes
* c1s1-part2: (1536-n-32)bytes (digest-part2)
* @return a new allocated bytes, user must free it.
*/
char* srs_bytes_join_schema0(int32_t time, int32_t version, key_block* key, digest_block* digest);
/**
* c1s1 is splited by digest:
* c1s1-part1: n bytes (time, version and digest-part1).
* digest-data: 32bytes
* c1s1-part2: (1536-n-32)bytes (digest-part2 and key)
* @return a new allocated bytes, user must free it.
*/
char* srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key);
/**
* compare the memory in bytes.
*/
bool srs_bytes_equals(void* pa, void* pb, int size);
/** /**
* c1s1 schema0 * c1s1 schema0
* time: 4bytes * time: 4bytes
@ -236,41 +308,14 @@ namespace srs
*/ */
virtual int s2_validate(c1s1* c1, bool& is_valid); virtual int s2_validate(c1s1* c1, bool& is_valid);
}; };
/**
* compare the memory in bytes.
*/
bool srs_bytes_equals(void* pa, void* pb, int size);
/**
* c1s1 is splited by digest:
* c1s1-part1: n bytes (time, version, key and digest-part1).
* digest-data: 32bytes
* c1s1-part2: (1536-n-32)bytes (digest-part2)
* @return a new allocated bytes, user must free it.
*/
char* srs_bytes_join_schema0(int32_t time, int32_t version, key_block* key, digest_block* digest);
/**
* c1s1 is splited by digest:
* c1s1-part1: n bytes (time, version and digest-part1).
* digest-data: 32bytes
* c1s1-part2: (1536-n-32)bytes (digest-part2 and key)
* @return a new allocated bytes, user must free it.
*/
char* srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key);
// the digest key generate size.
#define OpensslHashSize 512
extern u_int8_t SrsGenuineFMSKey[];
extern u_int8_t SrsGenuineFPKey[];
int openssl_HMACsha256(const void* data, int data_size, const void* key, int key_size, void* digest);
} }
#endif #endif
/** /**
* try complex handshake, if failed, fallback to simple handshake. * simple handshake.
* user can try complex handshake first,
* rollback to simple handshake if error ERROR_RTMP_TRY_SIMPLE_HS
*/ */
class SrsSimpleHandshake class SrsSimpleHandshake
{ {

View file

@ -36,6 +36,77 @@ ISrsThreadContext* _srs_context = new ISrsThreadContext();
SrsConfig* _srs_config = NULL; SrsConfig* _srs_config = NULL;
SrsServer* _srs_server = NULL; SrsServer* _srs_server = NULL;
MockEmptyIO::MockEmptyIO()
{
}
MockEmptyIO::~MockEmptyIO()
{
}
bool MockEmptyIO::is_never_timeout(int64_t /*timeout_us*/)
{
return true;
}
int MockEmptyIO::read_fully(const void* /*buf*/, size_t /*size*/, ssize_t* /*nread*/)
{
return ERROR_SUCCESS;
}
int MockEmptyIO::write(const void* /*buf*/, size_t /*size*/, ssize_t* /*nwrite*/)
{
return ERROR_SUCCESS;
}
void MockEmptyIO::set_recv_timeout(int64_t /*timeout_us*/)
{
}
int64_t MockEmptyIO::get_recv_timeout()
{
return -1;
}
int64_t MockEmptyIO::get_recv_bytes()
{
return -1;
}
int MockEmptyIO::get_recv_kbps()
{
return 0;
}
void MockEmptyIO::set_send_timeout(int64_t /*timeout_us*/)
{
}
int64_t MockEmptyIO::get_send_timeout()
{
return 0;
}
int64_t MockEmptyIO::get_send_bytes()
{
return 0;
}
int MockEmptyIO::get_send_kbps()
{
return 0;
}
int MockEmptyIO::writev(const iovec */*iov*/, int /*iov_size*/, ssize_t* /*nwrite*/)
{
return ERROR_SUCCESS;
}
int MockEmptyIO::read(const void* /*buf*/, size_t /*size*/, ssize_t* /*nread*/)
{
return ERROR_SUCCESS;
}
// basic test and samples. // basic test and samples.
VOID TEST(SampleTest, FastSampleInt64Test) VOID TEST(SampleTest, FastSampleInt64Test)
{ {

View file

@ -34,4 +34,36 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// we add an empty macro for upp to show the smart tips. // we add an empty macro for upp to show the smart tips.
#define VOID #define VOID
#include <srs_protocol_io.hpp>
class MockEmptyIO : public ISrsProtocolReaderWriter
{
public:
MockEmptyIO();
virtual ~MockEmptyIO();
// for protocol
public:
virtual bool is_never_timeout(int64_t timeout_us);
// for handshake.
public:
virtual int read_fully(const void* buf, size_t size, ssize_t* nread);
virtual int write(const void* buf, size_t size, ssize_t* nwrite);
// for protocol
public:
virtual void set_recv_timeout(int64_t timeout_us);
virtual int64_t get_recv_timeout();
virtual int64_t get_recv_bytes();
virtual int get_recv_kbps();
// for protocol
public:
virtual void set_send_timeout(int64_t timeout_us);
virtual int64_t get_send_timeout();
virtual int64_t get_send_bytes();
virtual int get_send_kbps();
virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite);
// for protocol/amf0/msg-codec
public:
virtual int read(const void* buf, size_t size, ssize_t* nread);
};
#endif #endif

View file

@ -24,77 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_kernel_error.hpp> #include <srs_kernel_error.hpp>
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#include <srs_protocol_utility.hpp>
MockEmptyIO::MockEmptyIO()
{
}
MockEmptyIO::~MockEmptyIO()
{
}
bool MockEmptyIO::is_never_timeout(int64_t /*timeout_us*/)
{
return true;
}
int MockEmptyIO::read_fully(const void* /*buf*/, size_t /*size*/, ssize_t* /*nread*/)
{
return ERROR_SUCCESS;
}
int MockEmptyIO::write(const void* /*buf*/, size_t /*size*/, ssize_t* /*nwrite*/)
{
return ERROR_SUCCESS;
}
void MockEmptyIO::set_recv_timeout(int64_t /*timeout_us*/)
{
}
int64_t MockEmptyIO::get_recv_timeout()
{
return -1;
}
int64_t MockEmptyIO::get_recv_bytes()
{
return -1;
}
int MockEmptyIO::get_recv_kbps()
{
return 0;
}
void MockEmptyIO::set_send_timeout(int64_t /*timeout_us*/)
{
}
int64_t MockEmptyIO::get_send_timeout()
{
return 0;
}
int64_t MockEmptyIO::get_send_bytes()
{
return 0;
}
int MockEmptyIO::get_send_kbps()
{
return 0;
}
int MockEmptyIO::writev(const iovec */*iov*/, int /*iov_size*/, ssize_t* /*nwrite*/)
{
return ERROR_SUCCESS;
}
int MockEmptyIO::read(const void* /*buf*/, size_t /*size*/, ssize_t* /*nread*/)
{
return ERROR_SUCCESS;
}
// verify the sha256 // verify the sha256
VOID TEST(HandshakeTest, OpensslSha256) VOID TEST(HandshakeTest, OpensslSha256)
@ -124,6 +54,37 @@ VOID TEST(HandshakeTest, OpensslSha256)
EXPECT_TRUE(srs_bytes_equals(digest, expect_digest, 32)); EXPECT_TRUE(srs_bytes_equals(digest, expect_digest, 32));
} }
// verify the dh key
VOID TEST(HandshakeTest, DHKey)
{
char pri_key[] = {
0x6e, 0x65, 0x69, 0x2d, 0x69, 0x2d, 0x69, 0x73,
0x6e, 0x69, 0x73, 0x6c, 0x65, 0x72, 0x69, 0x72,
0x76, 0x65, 0x72, 0x69, 0x77, 0x74, 0x2e, 0x6e,
0x72, 0x76, 0x72, 0x65, 0x72, 0x70, 0x72, 0x69,
0x69, 0x70, 0x72, 0x73, 0x6e, 0x65, 0x72, 0x72,
0x6e, 0x2d, 0x65, 0x74, 0x72, 0x6c, 0x69, 0x74,
0x69, 0x65, 0x40, 0x69, 0x69, 0x76, 0x77, 0x2d,
0x73, 0x65, 0x72, 0x72, 0x76, 0x73, 0x72, 0x2e,
0x2d, 0x76, 0x65, 0x31, 0x65, 0x6d, 0x6d, 0x73,
0x69, 0x73, 0x74, 0x2e, 0x74, 0x72, 0x65, 0x65,
0x72, 0x65, 0x2d, 0x74, 0x69, 0x31, 0x65, 0x2d,
0x6f, 0x77, 0x2e, 0x76, 0x77, 0x2d, 0x77, 0x72,
0x65, 0x65, 0x31, 0x74, 0x73, 0x70, 0x74, 0x6e,
0x72, 0x6e, 0x73, 0x6d, 0x2e, 0x69, 0x72, 0x2d,
0x65, 0x69, 0x77, 0x69, 0x76, 0x72, 0x77, 0x72,
0x32, 0x6e, 0x65, 0x6c, 0x2e, 0x2d, 0x6e, 0x69
};
char pub_key1[128];
openssl_generate_key(pri_key, pub_key1, 128);
char pub_key2[128];
openssl_generate_key(pri_key, pub_key2, 128);
EXPECT_FALSE(srs_bytes_equals(pub_key1, pub_key2, 128));
}
// flash will sendout a c0c1 encrypt by ssl. // flash will sendout a c0c1 encrypt by ssl.
VOID TEST(HandshakeTest, VerifyFPC0C1) VOID TEST(HandshakeTest, VerifyFPC0C1)
{ {
@ -172,7 +133,7 @@ VOID TEST(HandshakeTest, VerifyFPC0C1)
0xb1, 0xb5, 0xbc, 0xa6, 0xd6, 0xd6, 0x1d, 0xce, 0x93, 0x78, 0xb3, 0xec, 0xa8, 0x64, 0x19, 0x13 0xb1, 0xb5, 0xbc, 0xa6, 0xd6, 0xd6, 0x1d, 0xce, 0x93, 0x78, 0xb3, 0xec, 0xa8, 0x64, 0x19, 0x13
}; };
EXPECT_TRUE(srs_bytes_equals(c1.block1.digest.digest, digest, 32)); EXPECT_TRUE(srs_bytes_equals(c1.block1.digest.digest, digest, 32));
} }
VOID TEST(HandshakeTest, SimpleHandshake) VOID TEST(HandshakeTest, SimpleHandshake)
{ {
@ -260,3 +221,19 @@ VOID TEST(HandshakeTest, ComplexHandshake)
ASSERT_TRUE(is_valid); ASSERT_TRUE(is_valid);
} }
} }
VOID TEST(HandshakeTest, BytesEqual)
{
char a1[] = { 0x01 };
char b1[] = { 0x02 };
char a2[] = { 0x01, 0x02 };
char b2[] = { 0x02, 0x03 };
EXPECT_TRUE(srs_bytes_equals(NULL, NULL, 0));
EXPECT_FALSE(srs_bytes_equals(a1, NULL, 1));
EXPECT_FALSE(srs_bytes_equals(NULL, a1, 1));
EXPECT_FALSE(srs_bytes_equals(a1, b1, 1));
EXPECT_TRUE(srs_bytes_equals(a1, a1, 1));
EXPECT_TRUE(srs_bytes_equals(a1, a2, 1));
EXPECT_FALSE(srs_bytes_equals(a1, b2, 1));
}

View file

@ -29,39 +29,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <srs_utest.hpp> #include <srs_utest.hpp>
#include <srs_protocol_io.hpp>
#include <srs_protocol_rtmp.hpp> #include <srs_protocol_rtmp.hpp>
#include <srs_protocol_handshake.hpp> #include <srs_protocol_handshake.hpp>
using namespace srs; using namespace srs;
class MockEmptyIO : public ISrsProtocolReaderWriter
{
public:
MockEmptyIO();
virtual ~MockEmptyIO();
// for protocol
public:
virtual bool is_never_timeout(int64_t timeout_us);
// for handshake.
public:
virtual int read_fully(const void* buf, size_t size, ssize_t* nread);
virtual int write(const void* buf, size_t size, ssize_t* nwrite);
// for protocol
public:
virtual void set_recv_timeout(int64_t timeout_us);
virtual int64_t get_recv_timeout();
virtual int64_t get_recv_bytes();
virtual int get_recv_kbps();
// for protocol
public:
virtual void set_send_timeout(int64_t timeout_us);
virtual int64_t get_send_timeout();
virtual int64_t get_send_bytes();
virtual int get_send_kbps();
virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite);
// for protocol/amf0/msg-codec
public:
virtual int read(const void* buf, size_t size, ssize_t* nread);
};
#endif #endif