diff --git a/trunk/auto/generate_header.sh b/trunk/auto/generate_header.sh deleted file mode 100755 index a8d064800..000000000 --- a/trunk/auto/generate_header.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# genereate the library header file. - -objs=$1 - -rm -f $objs/include/srs_librtmp.h && -cp $objs/../src/libs/srs_librtmp.hpp $objs/include/srs_librtmp.h -echo "genereate srs-librtmp headers success" diff --git a/trunk/ide/srs_upp/srs_upp.upp b/trunk/ide/srs_upp/srs_upp.upp index 7f04cce13..9aa5a2d98 100755 --- a/trunk/ide/srs_upp/srs_upp.upp +++ b/trunk/ide/srs_upp/srs_upp.upp @@ -4,13 +4,6 @@ file ../../src/main/srs_main_ingest_hls.cpp, auto readonly separator, ../../objs/srs_auto_headers.hpp, - libs readonly separator, - ../../src/libs/srs_librtmp.hpp, - ../../src/libs/srs_librtmp.cpp, - ../../src/libs/srs_lib_bandwidth.hpp, - ../../src/libs/srs_lib_bandwidth.cpp, - ../../src/libs/srs_lib_simple_socket.hpp, - ../../src/libs/srs_lib_simple_socket.cpp, core readonly separator, ../../src/core/srs_core.hpp, ../../src/core/srs_core.cpp, diff --git a/trunk/ide/srs_vs2010/srs.vcxproj b/trunk/ide/srs_vs2010/srs.vcxproj index 8edc0b8b4..95673b490 100755 --- a/trunk/ide/srs_vs2010/srs.vcxproj +++ b/trunk/ide/srs_vs2010/srs.vcxproj @@ -116,9 +116,6 @@ - - - @@ -132,19 +129,6 @@ - - - - - - - - - - - - - @@ -198,9 +182,6 @@ - - - diff --git a/trunk/ide/srs_vs2010/srs.vcxproj.filters b/trunk/ide/srs_vs2010/srs.vcxproj.filters index bbf7fbc0d..ac1feeb90 100755 --- a/trunk/ide/srs_vs2010/srs.vcxproj.filters +++ b/trunk/ide/srs_vs2010/srs.vcxproj.filters @@ -163,36 +163,6 @@ srs - - research - - - research - - - research - - - research - - - research - - - research - - - librtmp - - - librtmp - - - librtmp - - - librtmp - srs @@ -378,15 +348,6 @@ srs - - librtmp - - - librtmp - - - librtmp - srs diff --git a/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj b/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj index 4aa190f06..96de6234a 100644 --- a/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj +++ b/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj @@ -77,9 +77,6 @@ 3C24ECCE1C3B824800460622 /* memory.error.tcmalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C24ECCC1C3B824800460622 /* memory.error.tcmalloc.cpp */; }; 3C26E3C61BB146FF00D0F9DB /* srs_app_kafka.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C26E3C41BB146FF00D0F9DB /* srs_app_kafka.cpp */; }; 3C28EDDF1AF5C43F00A3AEAC /* srs_app_caster_flv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C28EDDD1AF5C43F00A3AEAC /* srs_app_caster_flv.cpp */; }; - 3C36DB5B1ABD1CB90066CCAF /* srs_lib_bandwidth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB551ABD1CB90066CCAF /* srs_lib_bandwidth.cpp */; }; - 3C36DB5C1ABD1CB90066CCAF /* srs_lib_simple_socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB571ABD1CB90066CCAF /* srs_lib_simple_socket.cpp */; }; - 3C36DB5D1ABD1CB90066CCAF /* srs_librtmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */; }; 3C44AACF1E3AF50200D4ABC3 /* srs_kernel_mp4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C44AACD1E3AF50200D4ABC3 /* srs_kernel_mp4.cpp */; }; 3C4AB9331B8C9148006627D3 /* srs_app_ng_exec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C4AB9311B8C9148006627D3 /* srs_app_ng_exec.cpp */; }; 3C4D184C1E73F133008806F7 /* srs_app_fragment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C4D184A1E73F133008806F7 /* srs_app_fragment.cpp */; }; @@ -348,12 +345,6 @@ 3C26E3C51BB146FF00D0F9DB /* srs_app_kafka.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_kafka.hpp; path = ../../../src/app/srs_app_kafka.hpp; sourceTree = ""; }; 3C28EDDD1AF5C43F00A3AEAC /* srs_app_caster_flv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_caster_flv.cpp; path = ../../../src/app/srs_app_caster_flv.cpp; sourceTree = ""; }; 3C28EDDE1AF5C43F00A3AEAC /* srs_app_caster_flv.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_caster_flv.hpp; path = ../../../src/app/srs_app_caster_flv.hpp; sourceTree = ""; }; - 3C36DB551ABD1CB90066CCAF /* srs_lib_bandwidth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_lib_bandwidth.cpp; path = ../../../src/libs/srs_lib_bandwidth.cpp; sourceTree = ""; }; - 3C36DB561ABD1CB90066CCAF /* srs_lib_bandwidth.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_lib_bandwidth.hpp; path = ../../../src/libs/srs_lib_bandwidth.hpp; sourceTree = ""; }; - 3C36DB571ABD1CB90066CCAF /* srs_lib_simple_socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_lib_simple_socket.cpp; path = ../../../src/libs/srs_lib_simple_socket.cpp; sourceTree = ""; }; - 3C36DB581ABD1CB90066CCAF /* srs_lib_simple_socket.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_lib_simple_socket.hpp; path = ../../../src/libs/srs_lib_simple_socket.hpp; sourceTree = ""; }; - 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_librtmp.cpp; path = ../../../src/libs/srs_librtmp.cpp; sourceTree = ""; }; - 3C36DB5A1ABD1CB90066CCAF /* srs_librtmp.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_librtmp.hpp; path = ../../../src/libs/srs_librtmp.hpp; sourceTree = ""; }; 3C4468E81BB0E31300589C9D /* sources_replace.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = sources_replace.sh; path = ../../../scripts/sources_replace.sh; sourceTree = ""; }; 3C44AACD1E3AF50200D4ABC3 /* srs_kernel_mp4.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_kernel_mp4.cpp; path = ../../../src/kernel/srs_kernel_mp4.cpp; sourceTree = ""; }; 3C44AACE1E3AF50200D4ABC3 /* srs_kernel_mp4.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_kernel_mp4.hpp; path = ../../../src/kernel/srs_kernel_mp4.hpp; sourceTree = ""; }; @@ -497,7 +488,6 @@ 3C12324B1AAE81CE00CE8F6C /* app */, 3C96ADC41B00A71000885304 /* modules */, 3C1232041AAE80CB00CE8F6C /* main */, - 3C36DB541ABD1CA70066CCAF /* libs */, 3C1231F91AAE670E00CE8F6C /* objs */, 3C1EE6AF1AB107EE00576EE9 /* conf */, 3C1232EF1AAEAC5800CE8F6C /* etc */, @@ -833,19 +823,6 @@ name = doc; sourceTree = ""; }; - 3C36DB541ABD1CA70066CCAF /* libs */ = { - isa = PBXGroup; - children = ( - 3C36DB551ABD1CB90066CCAF /* srs_lib_bandwidth.cpp */, - 3C36DB561ABD1CB90066CCAF /* srs_lib_bandwidth.hpp */, - 3C36DB571ABD1CB90066CCAF /* srs_lib_simple_socket.cpp */, - 3C36DB581ABD1CB90066CCAF /* srs_lib_simple_socket.hpp */, - 3C36DB591ABD1CB90066CCAF /* srs_librtmp.cpp */, - 3C36DB5A1ABD1CB90066CCAF /* srs_librtmp.hpp */, - ); - name = libs; - sourceTree = ""; - }; 3C663F001AB014B500286D8B /* research */ = { isa = PBXGroup; children = ( @@ -1038,7 +1015,6 @@ 3C12322B1AAE814D00CE8F6C /* srs_kernel_utility.cpp in Sources */, 3C12324A1AAE81A400CE8F6C /* srs_rtsp_stack.cpp in Sources */, 3CE893BF1E876A97000B742D /* srs_service_http_client.cpp in Sources */, - 3C36DB5D1ABD1CB90066CCAF /* srs_librtmp.cpp in Sources */, 3C12329F1AAE81D900CE8F6C /* srs_app_http_api.cpp in Sources */, 3CECAF991EDC100F00C50501 /* event.c in Sources */, 3C1EE6AE1AB1055800576EE9 /* srs_app_hds.cpp in Sources */, diff --git a/trunk/research/librtmp/.gitignore b/trunk/research/librtmp/.gitignore deleted file mode 100644 index f1518d9c3..000000000 --- a/trunk/research/librtmp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.mp4 -*.gcno -*.gcda diff --git a/trunk/research/librtmp/Makefile b/trunk/research/librtmp/Makefile deleted file mode 100755 index 0e138bb36..000000000 --- a/trunk/research/librtmp/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -GCC = gcc - -ifeq ($(HANDSHAKE),) - ST_ALL = help -else - ST_ALL = objs/srs_flv_parser \ - objs/srs_flv_injecter objs/srs_publish objs/srs_play \ - objs/srs_ingest_flv objs/srs_ingest_rtmp objs/srs_detect_rtmp \ - objs/srs_bandwidth_check objs/srs_h264_raw_publish \ - objs/srs_audio_raw_publish objs/srs_aac_raw_publish \ - objs/srs_rtmp_dump objs/srs_ingest_mp4 -endif - -.PHONY: default clean help ssl nossl - -default: $(ST_ALL) - -help: - @echo "Usage: make |||" - @echo " help display this help" - @echo " clean cleanup build" - @echo " ssl all tools link ssl" - @echo " nossl all tools never link ssl" - @echo "ssl/nossl will build the following tools:" - @echo " srs_flv_parser parse flv file, print detail info." - @echo " srs_flv_injecter inject keyframes information to metadata." - @echo " srs_publish publish program using srs-librtmp" - @echo " srs_h264_raw_publish publish raw h.264 stream to SSR by srs-librtmp" - @echo " srs_audio_raw_publish publish raw audio stream to SSR by srs-librtmp" - @echo " srs_aac_raw_publish publish raw aac stream to SSR by srs-librtmp" - @echo " srs_play play program using srs-librtmp" - @echo " srs_ingest_flv ingest flv file and publish to RTMP server." - @echo " srs_ingest_mp4 ingest mp4 file and publish to RTMP server." - @echo " srs_ingest_rtmp ingest RTMP and publish to RTMP server." - @echo " srs_detect_rtmp detect RTMP stream info." - @echo " srs_bandwidth_check bandwidth check/test tool." - @echo " srs_rtmp_dump dump rtmp stream to flv file." - @echo "Remark: about simple/complex handshake, see: http://blog.csdn.net/win_lin/article/details/13006803" - @echo "Remark: srs Makefile will auto invoke this by --with/without-ssl, " - @echo " that is, if user specified ssl(by --with-ssl), srs will make this by 'make ssl'" - @echo " that is, if user not use ssl(by --without-ssl), use 'make nossl'" - @echo " see: https://github.com/ossrs/srs/wiki/v1_CN_v1_Build" - @echo "Remark: before make this sample, user must make the srs, with/without ssl" - -clean: - @rm -rf objs - -# srs library root -SRS_OBJS = ../../objs -# srs-librtmp for publish/play, built by srs. -SRS_LIBRTMP_I = $(SRS_OBJS)/include/srs_librtmp.h -SRS_LIBRTMP_L = $(SRS_OBJS)/lib/srs_librtmp.a -# openssl for complex handshake, built by srs. -SRS_LIBSSL_L = -# public depends, the Makefile or public headers. -SRS_RESEARCH_DEPS = Makefile - -# for x86/x64 platform -ifeq ($(GCC), gcc) - OTHER_FLAGS += -g -O0 -ldl -lstdc++ -lm -endif -# for arm. -ifeq ($(GCC), arm-linux-gnueabi-gcc) - OTHER_FLAGS += -g -O0 -ldl -static -lstdc++ -lm -endif -# for mips, add -lgcc_eh, or stl compile failed. -ifeq ($(GCC), mipsel-openwrt-linux-gcc) - OTHER_FLAGS += -g -O0 -ldl -lstdc++ -lm -lgcc_eh -endif -# for ssl or nossl -ifeq ($(HANDSHAKE), SSL) - SRS_LIBSSL_L = $(SRS_OBJS)/openssl/lib/libssl.a $(SRS_OBJS)/openssl/lib/libcrypto.a - ifneq ($(shell test -f $(SRS_OBJS)/openssl/lib/libssl.a && echo yes), yes) - SRS_LIBSSL_L = -lssl -lcrypto - endif -endif - -ssl: - @mkdir -p objs - $(MAKE) HANDSHAKE="SSL" -nossl: - @mkdir -p objs - $(MAKE) HANDSHAKE="NOSSL" - -CXXFLAGS += $(OTHER_FLAGS) $(EXTRA_CXXFLAGS) - -objs/srs_flv_parser: srs_flv_parser.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) - $(GCC) srs_flv_parser.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_flv_parser - -objs/srs_flv_injecter: srs_flv_injecter.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) - $(GCC) srs_flv_injecter.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_flv_injecter - -objs/srs_publish: srs_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_publish - -objs/srs_h264_raw_publish: srs_h264_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_h264_raw_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_h264_raw_publish - -objs/srs_audio_raw_publish: srs_audio_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_audio_raw_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_audio_raw_publish - -objs/srs_aac_raw_publish: srs_aac_raw_publish.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_aac_raw_publish.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_aac_raw_publish - -objs/srs_play: srs_play.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_play.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_play - -objs/srs_ingest_flv: srs_ingest_flv.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_ingest_flv.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_ingest_flv - -objs/srs_ingest_mp4: srs_ingest_mp4.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_ingest_mp4.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_ingest_mp4 - -objs/srs_ingest_rtmp: srs_ingest_rtmp.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_ingest_rtmp.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_ingest_rtmp - -objs/srs_detect_rtmp: srs_detect_rtmp.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_detect_rtmp.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_detect_rtmp - -objs/srs_bandwidth_check: srs_bandwidth_check.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_bandwidth_check.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_bandwidth_check - -objs/srs_rtmp_dump: srs_rtmp_dump.c $(SRS_RESEARCH_DEPS) $(SRS_LIBRTMP_I) $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) - $(GCC) srs_rtmp_dump.c $(SRS_LIBRTMP_L) $(SRS_LIBSSL_L) $(CXXFLAGS) -o objs/srs_rtmp_dump - diff --git a/trunk/research/librtmp/srs_aac_raw_publish.c b/trunk/research/librtmp/srs_aac_raw_publish.c deleted file mode 100644 index 1b8abc0c8..000000000 --- a/trunk/research/librtmp/srs_aac_raw_publish.c +++ /dev/null @@ -1,187 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -// for open audio raw file. -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -// https://github.com/ossrs/srs/issues/212#issuecomment-64145910 -int read_audio_frame(char* data, int size, char** pp, char** frame, int* frame_size) -{ - char* p = *pp; - - // @remark, for this demo, to publish aac raw file to SRS, - // we search the adts frame from the buffer which cached the aac data. - // please get aac adts raw data from device, it always a encoded frame. - if (!srs_aac_is_adts(p, size - (p - data))) { - srs_human_trace("aac adts raw data invalid."); - return -1; - } - - // @see srs_audio_write_raw_frame - // each frame prefixed aac adts header, '1111 1111 1111'B, that is 0xFFF., - // for instance, frame = FF F1 5C 80 13 A0 FC 00 D0 33 83 E8 5B - *frame = p; - // skip some data. - // @remark, user donot need to do this. - p += srs_aac_adts_frame_size(p, size - (p - data)); - - *pp = p; - *frame_size = p - *frame; - if (*frame_size <= 0) { - srs_human_trace("aac adts raw data invalid."); - return -1; - } - - return 0; -} - -int main(int argc, char** argv) -{ - printf("publish raw audio as rtmp stream to server like FMLE/FFMPEG/Encoder\n"); - printf("SRS(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 2) { - printf("Usage: %s \n", argv[0]); - printf(" audio_raw_file: the audio raw steam file.\n"); - printf(" rtmp_publish_url: the rtmp publish url.\n"); - printf("For example:\n"); - printf(" %s ./audio.raw.aac rtmp://127.0.0.1:1935/live/livestream\n", argv[0]); - printf("Where the file: http://winlinvip.github.io/srs.release/3rdparty/audio.raw.aac\n"); - printf("See: https://github.com/ossrs/srs/issues/212\n"); - exit(-1); - } - - const char* raw_file = argv[1]; - const char* rtmp_url = argv[2]; - srs_human_trace("raw_file=%s, rtmp_url=%s", raw_file, rtmp_url); - - // open file - int raw_fd = open(raw_file, O_RDONLY); - if (raw_fd < 0) { - srs_human_trace("open audio raw file %s failed.", raw_file); - goto rtmp_destroy; - } - - off_t file_size = lseek(raw_fd, 0, SEEK_END); - if (file_size <= 0) { - srs_human_trace("audio raw file %s empty.", raw_file); - goto rtmp_destroy; - } - srs_human_trace("read entirely audio raw file, size=%dKB", (int)(file_size / 1024)); - - char* audio_raw = (char*)malloc(file_size); - if (!audio_raw) { - srs_human_trace("alloc raw buffer failed for file %s.", raw_file); - goto rtmp_destroy; - } - - lseek(raw_fd, 0, SEEK_SET); - ssize_t nb_read = 0; - if ((nb_read = read(raw_fd, audio_raw, file_size)) != file_size) { - srs_human_trace("buffer %s failed, expect=%dKB, actual=%dKB.", - raw_file, (int)(file_size / 1024), (int)(nb_read / 1024)); - goto rtmp_destroy; - } - - // connect rtmp context - srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url); - - if (srs_rtmp_handshake(rtmp) != 0) { - srs_human_trace("simple handshake failed."); - goto rtmp_destroy; - } - srs_human_trace("simple handshake success"); - - if (srs_rtmp_connect_app(rtmp) != 0) { - srs_human_trace("connect vhost/app failed."); - goto rtmp_destroy; - } - srs_human_trace("connect vhost/app success"); - - if (srs_rtmp_publish_stream(rtmp) != 0) { - srs_human_trace("publish stream failed."); - goto rtmp_destroy; - } - srs_human_trace("publish stream success"); - - uint32_t timestamp = 0; - uint32_t time_delta = 45; - // @remark, to decode the file. - char* p = audio_raw; - for (;p < audio_raw + file_size;) { - // @remark, read a frame from file buffer. - char* data = NULL; - int size = 0; - if (read_audio_frame(audio_raw, file_size, &p, &data, &size) < 0) { - srs_human_trace("read a frame from file buffer failed."); - goto rtmp_destroy; - } - - // 0 = Linear PCM, platform endian - // 1 = ADPCM - // 2 = MP3 - // 7 = G.711 A-law logarithmic PCM - // 8 = G.711 mu-law logarithmic PCM - // 10 = AAC - // 11 = Speex - char sound_format = 10; - // 2 = 22 kHz - char sound_rate = 2; - // 1 = 16-bit samples - char sound_size = 1; - // 1 = Stereo sound - char sound_type = 1; - - timestamp += time_delta; - - int ret = 0; - if ((ret = srs_audio_write_raw_frame(rtmp, sound_format, sound_rate, sound_size, sound_type, data, size, timestamp)) != 0) { - srs_human_trace("send audio raw data failed. ret=%d", ret); - goto rtmp_destroy; - } - - srs_human_trace("sent packet: type=%s, time=%d, size=%d, codec=%d, rate=%d, sample=%d, channel=%d", - srs_human_flv_tag_type2string(SRS_RTMP_TYPE_AUDIO), timestamp, size, sound_format, sound_rate, sound_size, - sound_type); - - // @remark, when use encode device, it not need to sleep. - usleep(1000 * time_delta); - } - -rtmp_destroy: - srs_rtmp_destroy(rtmp); - close(raw_fd); - free(audio_raw); - - return 0; -} - diff --git a/trunk/research/librtmp/srs_audio_raw_publish.c b/trunk/research/librtmp/srs_audio_raw_publish.c deleted file mode 100644 index 0c504ab0a..000000000 --- a/trunk/research/librtmp/srs_audio_raw_publish.c +++ /dev/null @@ -1,183 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -// for open audio raw file. -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -// https://github.com/ossrs/srs/issues/212#issuecomment-63648892 -// allspace: -// Take this file as an example: https://github.com/allspace/files/blob/master/srs.pcm -// It's captured using SDK callback method. I have filtered out h264 video, so it's audio only now. -// For every frame, it's a 8 bytes vendor specific header, following 160 bytes audio frame. -// The header part can be ignored. -int read_audio_frame(char* audio_raw, int file_size, char** pp, char** pdata, int* psize) -{ - char* p = *pp; - - if (file_size - (p - audio_raw) < 168) { - srs_human_trace("audio must be 160+8 bytes. left %d bytes.", (int)(file_size - (p - audio_raw))); - return - 1; - } - - // ignore 8bytes vendor specific header. - p += 8; - - // 160 bytes audio frame - *pdata = p; - *psize = 160; - - // next frame. - *pp = p + *psize; - - return 0; -} - -int main(int argc, char** argv) -{ - printf("publish raw audio as rtmp stream to server like FMLE/FFMPEG/Encoder\n"); - printf("SRS(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 2) { - printf("Usage: %s \n", argv[0]); - printf(" audio_raw_file: the audio raw steam file.\n"); - printf(" rtmp_publish_url: the rtmp publish url.\n"); - printf("For example:\n"); - printf(" %s ./audio.raw.pcm rtmp://127.0.0.1:1935/live/livestream\n", argv[0]); - printf("Where the file: http://winlinvip.github.io/srs.release/3rdparty/audio.raw.pcm\n"); - printf("See: https://github.com/ossrs/srs/issues/212\n"); - exit(-1); - } - - const char* raw_file = argv[1]; - const char* rtmp_url = argv[2]; - srs_human_trace("raw_file=%s, rtmp_url=%s", raw_file, rtmp_url); - - // open file - int raw_fd = open(raw_file, O_RDONLY); - if (raw_fd < 0) { - srs_human_trace("open audio raw file %s failed.", raw_file); - goto rtmp_destroy; - } - - off_t file_size = lseek(raw_fd, 0, SEEK_END); - if (file_size <= 0) { - srs_human_trace("audio raw file %s empty.", raw_file); - goto rtmp_destroy; - } - srs_human_trace("read entirely audio raw file, size=%dKB", (int)(file_size / 1024)); - - char* audio_raw = (char*)malloc(file_size); - if (!audio_raw) { - srs_human_trace("alloc raw buffer failed for file %s.", raw_file); - goto rtmp_destroy; - } - - lseek(raw_fd, 0, SEEK_SET); - ssize_t nb_read = 0; - if ((nb_read = read(raw_fd, audio_raw, file_size)) != file_size) { - srs_human_trace("buffer %s failed, expect=%dKB, actual=%dKB.", - raw_file, (int)(file_size / 1024), (int)(nb_read / 1024)); - goto rtmp_destroy; - } - - // connect rtmp context - srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url); - - if (srs_rtmp_handshake(rtmp) != 0) { - srs_human_trace("simple handshake failed."); - goto rtmp_destroy; - } - srs_human_trace("simple handshake success"); - - if (srs_rtmp_connect_app(rtmp) != 0) { - srs_human_trace("connect vhost/app failed."); - goto rtmp_destroy; - } - srs_human_trace("connect vhost/app success"); - - if (srs_rtmp_publish_stream(rtmp) != 0) { - srs_human_trace("publish stream failed."); - goto rtmp_destroy; - } - srs_human_trace("publish stream success"); - - uint32_t timestamp = 0; - uint32_t time_delta = 17; - // @remark, to decode the file. - char* p = audio_raw; - for (;p < audio_raw + file_size;) { - // @remark, read a frame from file buffer. - char* data = NULL; - int size = 0; - if (read_audio_frame(audio_raw, file_size, &p, &data, &size) < 0) { - srs_human_trace("read a frame from file buffer failed."); - goto rtmp_destroy; - } - - // 0 = Linear PCM, platform endian - // 1 = ADPCM - // 2 = MP3 - // 7 = G.711 A-law logarithmic PCM - // 8 = G.711 mu-law logarithmic PCM - // 10 = AAC - // 11 = Speex - char sound_format = 1; - // 3 = 44 kHz - char sound_rate = 3; - // 1 = 16-bit samples - char sound_size = 1; - // 1 = Stereo sound - char sound_type = 1; - - timestamp += time_delta; - - if (srs_audio_write_raw_frame(rtmp, sound_format, sound_rate, sound_size, sound_type, data, size, timestamp) != 0) { - srs_human_trace("send audio raw data failed."); - goto rtmp_destroy; - } - - srs_human_trace("sent packet: type=%s, time=%d, size=%d, codec=%d, rate=%d, sample=%d, channel=%d", - srs_human_flv_tag_type2string(SRS_RTMP_TYPE_AUDIO), timestamp, size, sound_format, sound_rate, sound_size, - sound_type); - - // @remark, when use encode device, it not need to sleep. - usleep(1000 * time_delta); - } - -rtmp_destroy: - srs_rtmp_destroy(rtmp); - close(raw_fd); - free(audio_raw); - - return 0; -} - diff --git a/trunk/research/librtmp/srs_bandwidth_check.c b/trunk/research/librtmp/srs_bandwidth_check.c deleted file mode 100644 index ed85165a3..000000000 --- a/trunk/research/librtmp/srs_bandwidth_check.c +++ /dev/null @@ -1,143 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -// srs debug info. -char* ip = NULL; -char* sig = NULL; -int pid = 0, cid = 0; -int major = 0, minor = 0, revision= 0, build = 0; -// bandwidth test data. -int64_t start_time = 0; -int64_t end_time = 0; -int play_kbps = 0; -int publish_kbps = 0; -int play_bytes = 0; -int publish_bytes = 0; -int play_duration = 0; -int publish_duration = 0; - -int do_check(srs_rtmp_t rtmp) -{ - int ret = 0; - - if ((ret = srs_rtmp_handshake(rtmp)) != 0) { - srs_human_trace("simple handshake failed."); - return ret; - } - srs_human_trace("simple handshake success"); - - if ((ret = srs_rtmp_connect_app(rtmp)) != 0) { - srs_human_trace("connect vhost/app failed."); - return ret; - } - srs_human_trace("connect vhost/app success"); - - if ((ret = srs_rtmp_get_server_sig(rtmp, &sig)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_id(rtmp, &ip, &pid, &cid)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_version(rtmp, &major, &minor, &revision, &build)) != 0) { - srs_human_trace("Retrieve server version failed, ret=%d", ret); - return ret; - } - - if ((ret = srs_rtmp_bandwidth_check(rtmp, - &start_time, &end_time, &play_kbps, &publish_kbps, &play_bytes, &publish_bytes, - &play_duration, &publish_duration)) != 0 - ) { - srs_human_trace("bandwidth check/test failed."); - return ret; - } - srs_human_trace("bandwidth check/test success"); - - return ret; -} - -int main(int argc, char** argv) -{ - int ret = 0; - srs_rtmp_t rtmp; - - printf("RTMP bandwidth check/test with server.\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 1) { - printf("RTMP bandwidth check/test with server.\n" - "Usage: %s \n" - " rtmp_url RTMP bandwidth url to check. format: rtmp://server:port/app?key=xxx,vhost=xxx\n" - "For example:\n" - " %s rtmp://127.0.0.1:1935/app?key=35c9b402c12a7246868752e2878f7e0e,vhost=bandcheck.srs.com\n" - " %s rtmp://127.0.0.1:1935/app?key=35c9b402c12a7246868752e2878f7e0e,vhost=bandcheck.srs.com>/dev/null\n" - "@remark, output text to stdout, while json to stderr.\n", - argv[0], argv[0], argv[0]); - exit(-1); - } - - char url[512]; - snprintf(url, sizeof(url), "%s/%s", argv[1], "livestream"); - rtmp = srs_rtmp_create((const char*)url); - srs_human_trace("bandwidth check/test url: %s", argv[1]); - - if ((ret = do_check(rtmp)) != 0) { - goto rtmp_destroy; - } - - srs_human_trace("\n%s, %s, %d.%d.%d.%d, srs_pid=%d, srs_id=%d\n" - "duration: %dms(%d+%d), play: %dkbps, publish: %dkbps", - (char*)sig, (char*)ip, major, minor, revision, build, pid, cid, - (int)(end_time - start_time), play_duration, publish_duration, play_kbps, publish_kbps); - -rtmp_destroy: - fprintf(stderr, "{\"code\":%d," - "\"srs_server\":\"%s\", \"srs_primary\":\"\", \"srs_authors\":\"\", \"srs_server_ip\":\"%s\", " - "\"srs_version\":\"%d.%d.%d.%d\", " - "\"srs_pid\":%d, " - "\"srs_id\":%d, " - "\"duration\":%d, " - "\"play_duration\":%d, " - "\"publish_duration\":%d," - "\"play_kbps\":%d, " - "\"publish_kbps\":%d" - "}", - ret, - (char*)sig, (char*)ip, - major, minor, revision, build, pid, cid, - (int)(end_time - start_time), play_duration, publish_duration, - play_kbps, publish_kbps); - srs_rtmp_destroy(rtmp); - - srs_human_trace(" "); - srs_human_trace("completed"); - - return ret; -} diff --git a/trunk/research/librtmp/srs_detect_rtmp.c b/trunk/research/librtmp/srs_detect_rtmp.c deleted file mode 100644 index 65907d11f..000000000 --- a/trunk/research/librtmp/srs_detect_rtmp.c +++ /dev/null @@ -1,239 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int main(int argc, char** argv) -{ - int ret = 0; - srs_rtmp_t rtmp; - - // time - int64_t time_startup = srs_utils_time_ms(); - int64_t time_dns_resolve = 0; - int64_t time_socket_connect = 0; - int64_t time_play_stream = 0; - int64_t time_first_packet = 0; - int64_t time_cleanup = 0; - // bytes - int64_t bytes_nsend = 0; - int time_duration = 0; - int64_t bytes_nrecv = 0; - - // packet data - int size; - char type; - char* data; - uint32_t timestamp; - uint32_t basetime = 0; - - // user options - const char* rtmp_url = NULL; - int duration = 0; - int timeout = 0; - enum srs_url_schema sus; - - printf("detect rtmp stream\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 3) { - printf("detect stream on RTMP server, print result to stderr.\n" - "Usage: %s [url_schema]\n" - " rtmp_url RTMP stream url to play\n" - " duration how long to play, in seconds, stream time.\n" - " timeout how long to timeout, in seconds, system time.\n" - " url_schema the schema of url, default to vis, can be:\n" - " normal: rtmp://vhost:port/app/stream\n" - " via : rtmp://ip:port/vhost/app/stream\n" - " vis : rtmp://ip:port/app/stream?vhost=xxx\n" - " vis2 : rtmp://ip:port/app/stream?domain=xxx\n" - "For example:\n" - " %s rtmp://127.0.0.1:1935/bravo.chnvideo.com/live/livestream 3 10\n", - argv[0], argv[0]); - exit(-1); - } - - rtmp_url = argv[1]; - duration = atoi(argv[2]); - timeout = atoi(argv[3]); - - if (1) { - char *p = "vis"; - if (argc > 4) { - p = argv[4]; - } - - if (strcmp(p, "normal") == 0) { - sus = srs_url_schema_normal; - } else if (strcmp(p, "via") == 0) { - sus = srs_url_schema_via; - } else if (strcmp(p, "vis") == 0) { - sus = srs_url_schema_vis; - } else if (strcmp(p, "vis2") == 0){ - sus = srs_url_schema_vis2; - } else { - srs_human_trace("url_schema must be normal/via/vis/vis2"); - exit(-2); - } - srs_human_trace("url schema: %s", p); - } - - srs_human_trace("rtmp url: %s", rtmp_url); - srs_human_trace("duration: %ds, timeout:%ds", duration, timeout); - - if (duration <= 0 || timeout <= 0) { - srs_human_trace("duration and timeout must be positive."); - exit(-3); - } - - if ((rtmp = srs_rtmp_create(rtmp_url)) == NULL) { - srs_human_trace("create rtmp failed"); - ret = -1; - goto rtmp_destroy; - } - if ((ret = srs_rtmp_set_timeout(rtmp, timeout * 1000, timeout * 1000)) != 0) { - srs_human_trace("set timeout for rtmp failed. errno=%d", ret); - goto rtmp_destroy; - } - - if ((ret = srs_rtmp_dns_resolve(rtmp)) != 0) { - srs_human_trace("dns resolve failed. ret=%d", ret); - goto rtmp_destroy; - } - srs_human_trace("dns resolve success"); - time_dns_resolve = srs_utils_time_ms(); - - if ((ret = srs_rtmp_connect_server(rtmp)) != 0) { - srs_human_trace("socket connect failed. ret=%d", ret); - goto rtmp_destroy; - } - srs_human_trace("socket connect success"); - time_socket_connect = srs_utils_time_ms(); - - if ((ret = srs_rtmp_do_simple_handshake(rtmp)) != 0) { - srs_human_trace("do simple handshake failed. ret=%d", ret); - goto rtmp_destroy; - } - srs_human_trace("do simple handshake success"); - - if ((ret = srs_rtmp_set_schema(rtmp, sus)) != 0) { - srs_human_trace("set url schema=%d failed, ret=%d", sus, ret); - goto rtmp_destroy; - } - - if ((ret = srs_rtmp_connect_app(rtmp)) != 0) { - srs_human_trace("connect vhost/app failed. ret=%d", ret); - goto rtmp_destroy; - } - srs_human_trace("connect vhost/app success"); - - if ((ret = srs_rtmp_play_stream(rtmp)) != 0) { - srs_human_trace("play stream failed. ret=%d", ret); - goto rtmp_destroy; - } - srs_human_trace("play stream success"); - time_play_stream = srs_utils_time_ms(); - - for (;;) { - if ((ret = srs_rtmp_read_packet(rtmp, &type, ×tamp, &data, &size)) != 0) { - srs_human_trace("read packet failed. ret=%d", ret); - goto rtmp_destroy; - } - srs_human_trace("got packet: type=%s, time=%d, size=%d", srs_human_flv_tag_type2string(type), timestamp, size); - - if (SRS_RTMP_TYPE_VIDEO == type || SRS_RTMP_TYPE_AUDIO == type) { - if (time_first_packet <= 0) { - time_first_packet = srs_utils_time_ms(); - } - if (basetime <= 0) { - basetime = timestamp; - } - } - - free(data); - - if (srs_utils_time_ms() - time_startup > timeout * 1000) { - srs_human_trace("timeout, terminate."); - goto rtmp_destroy; - } - - if (timestamp > basetime && (timestamp - basetime) > duration * 1000) { - srs_human_trace("duration exceed, terminate."); - goto rtmp_destroy; - } - } - -rtmp_destroy: - bytes_nsend = srs_utils_send_bytes(rtmp); - bytes_nrecv = srs_utils_recv_bytes(rtmp); - - srs_rtmp_destroy(rtmp); - time_cleanup = srs_utils_time_ms(); - time_duration = (int)(time_cleanup - time_startup); - - // print result to stderr. - fprintf(stderr, "{" - "\"%s\":%d, " //#0 - "\"%s\":%d, " //#1 - "\"%s\":%d, " // #2 - "\"%s\":%d, " // #3 - "\"%s\":%d, " // #4 - "\"%s\":%d, " // #5 - "\"%s\":%d, " // #6 - "\"%s\":%d, " // #7 - "\"%s\":%d, " // #8 - "\"%s\":%d, " // #9 - "\"%s\":%d, " // #10 - "%s,%s,%s,%s}", - "code", ret, //#0 - // total = dns + tcp_connect + start_play + first_packet + last_packet - "total", time_duration, //#1 - "dns", (int)(time_dns_resolve - time_startup), //#2 - "tcp_connect", (int)(time_socket_connect - time_dns_resolve), //#3 - "start_play", (int)(time_play_stream - time_socket_connect), //#4 - "first_packet", (int)(time_first_packet - time_play_stream), //#5 - "last_packet", (int)(time_cleanup - time_first_packet), //#6 - "stream", (int)(timestamp - basetime), //#7 - // expect = time_cleanup - time_first_packet - // actual = stream - // delay = actual - expect - "delay", (int)(timestamp - basetime - (time_cleanup - time_first_packet)), //#8 - "publish_kbps", (int)((time_duration <= 0)? 0:(bytes_nsend * 8 / time_duration)), //#9 - "play_kbps", (int)((time_duration <= 0)? 0:(bytes_nrecv * 8 / time_duration)), //#10 - // unit in ms. - "\"unit\": \"ms\"", - "\"remark0\": \"total = dns + tcp_connect + start_play + first_packet + last_packet\"", - "\"remark1\": \"delay = stream - (time_cleanup - time_first_packet)\"", - "\"remark2\": \"if code is not 0, user must ignore all data\"" - ); - - srs_human_trace(" "); - srs_human_trace("completed"); - - return ret; -} diff --git a/trunk/research/librtmp/srs_flv_injecter.c b/trunk/research/librtmp/srs_flv_injecter.c deleted file mode 100644 index de13f6a09..000000000 --- a/trunk/research/librtmp/srs_flv_injecter.c +++ /dev/null @@ -1,383 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -#define ERROR_INJECTED 10000 - -int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc); -int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0_t* pfilepositions, int64_t* pmetadata_end_offset); -int do_inject_flv(srs_flv_t ic, srs_flv_t oc, srs_amf0_t amf0_name, srs_amf0_t amf0_data, srs_amf0_t filepositions, int64_t metadata_end_offset); - -int main(int argc, char** argv) -{ - int ret = 0; - - // user options. - char* in_flv_file; - char* out_flv_file; - // flv handler - srs_flv_t ic = NULL; - srs_flv_t oc = NULL; - - // temp variables. - int tmp_file_size = 0; - char* tmp_file; - - printf("inject flv file keyframes to metadata.\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 2) { - printf("inject flv file keyframes to metadata\n" - "Usage: %s in_flv_file out_flv_file\n" - " in_flv_file input flv file to inject.\n" - " out_flv_file the inject output file, can be in_flv_file.\n" - "For example:\n" - " %s doc/source.200kbps.768x320.flv injected.flv\n" - " %s ../../doc/source.200kbps.768x320.flv injected.flv\n", - argv[0], argv[0], argv[0]); - exit(-1); - } - - in_flv_file = argv[1]; - out_flv_file = argv[2]; - - tmp_file_size = strlen(out_flv_file) + strlen(".tmp") + 1; - tmp_file = (char*)malloc(tmp_file_size); - snprintf(tmp_file, tmp_file_size, "%s.tmp", out_flv_file); - - srs_human_trace("input: %s", in_flv_file); - srs_human_trace("output: %s", out_flv_file); - srs_human_trace("tmp_file: %s", tmp_file); - - ret = process(in_flv_file, tmp_file, &ic, &oc); - - srs_flv_close(ic); - srs_flv_close(oc); - - if (ret != 0) { - unlink(tmp_file); - if (ret == ERROR_INJECTED) { - ret = 0; - srs_human_trace("file already injected."); - } else { - srs_human_trace("error, remove tmp file."); - } - } else { - rename(tmp_file, out_flv_file); - srs_human_trace("completed, rename to %s", out_flv_file); - } - - free(tmp_file); - - return ret; -} - -int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc) -{ - int ret = 0; - - srs_flv_t ic; - srs_flv_t oc; - - // to adjust metadata. - // the ic metadata end offset, the next tag start offset. - // all oc metadata must adjust according to: - // adjust = new_metadata_end_offset - metadata_end_offset - int64_t metadata_end_offset = 0; - - // metadata - srs_amf0_t amf0_name = NULL; - srs_amf0_t amf0_data = NULL; - srs_amf0_t filepositions = NULL; - - if ((ic = srs_flv_open_read(in_flv_file)) == NULL) { - ret = 2; - srs_human_trace("open input flv file failed. ret=%d", ret); - return ret; - } - *pic = ic; - - if ((oc = srs_flv_open_write(out_flv_file)) == NULL) { - ret = 2; - srs_human_trace("open output flv file failed. ret=%d", ret); - return ret; - } - *poc = oc; - - /** - * we use two roundtrip to avoid the paddings of metadata, - * to support large keyframes videos without padding fields. - */ - // build keyframes offset to metadata. - if ((ret = build_keyframes(ic, &amf0_name, &amf0_data, &filepositions, &metadata_end_offset)) != 0) { - return ret; - } - - // inject the metadata to oc. - if ((ret = do_inject_flv(ic, oc, amf0_name, amf0_data, filepositions, metadata_end_offset)) != 0) { - return ret; - } - - // TODO: FIXME: mem leak when error. - srs_amf0_free(amf0_name); - srs_amf0_free(amf0_data); - - return ret; -} - -int parse_metadata(char* data, int size, srs_amf0_t* pname, srs_amf0_t* pdata) -{ - int ret = 0; - - int nparsed = 0; - *pname = srs_amf0_parse(data, size, &nparsed); - - if (*pname == NULL || nparsed >= size) { - srs_human_trace("invalid amf0 name data."); - return -1; - } - - *pdata = srs_amf0_parse(data + nparsed, size - nparsed, &nparsed); - if (*pdata == NULL || nparsed > size) { - srs_human_trace("invalid amf0 value data"); - return -1; - } - - return ret; -} - -int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0_t* pfilepositions, int64_t* pmetadata_end_offset) -{ - int ret = 0; - - // flv header - char header[13]; - - // packet data - char type; - uint32_t timestamp = 0; - char* data = NULL; - int32_t size; - int64_t offset = 0; - - // metadata - srs_amf0_t amf0_name = NULL; - srs_amf0_t amf0_data = NULL; - - srs_amf0_t keyframes = NULL; - srs_amf0_t filepositions = NULL; - srs_amf0_t times = NULL; - - // reset to generate metadata - srs_flv_lseek(ic, 0); - - if ((ret = srs_flv_read_header(ic, header)) != 0) { - return ret; - } - - srs_human_trace("build keyframe infos from flv"); - for (;;) { - offset = srs_flv_tellg(ic); - - // tag header - if ((ret = srs_flv_read_tag_header(ic, &type, &size, ×tamp)) != 0) { - if (srs_flv_is_eof(ret)) { - srs_human_trace("parse completed."); - return 0; - } - srs_human_trace("flv get packet failed. ret=%d", ret); - return ret; - } - - if (size <= 0) { - srs_human_trace("invalid size=%d", size); - return ret; - } - - // TODO: FIXME: mem leak when error. - data = (char*)malloc(size); - if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) { - return ret; - } - - // data tag - if (type == SRS_RTMP_TYPE_VIDEO) { - if (!srs_flv_is_sequence_header(data, size) && srs_flv_is_keyframe(data, size)) { - srs_amf0_strict_array_append(filepositions, srs_amf0_create_number(offset)); - srs_amf0_strict_array_append(times, srs_amf0_create_number(((double)timestamp)/ 1000)); - } - } else if (type == SRS_RTMP_TYPE_SCRIPT) { - *pmetadata_end_offset = srs_flv_tellg(ic); - if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) { - return ret; - } - - *pname = amf0_name; - *pdata = amf0_data; - - if (srs_amf0_is_object(amf0_data)) { - keyframes = srs_amf0_object_property(amf0_data, "keyframes"); - if (keyframes == NULL) { - keyframes = srs_amf0_create_object(); - srs_amf0_object_property_set(amf0_data, "keyframes", keyframes); - } - // always clear the old keyframes. - srs_amf0_object_clear(keyframes); - - *pfilepositions = filepositions = srs_amf0_create_strict_array(); - srs_amf0_object_property_set(keyframes, "filepositions", filepositions); - - times = srs_amf0_create_strict_array(); - srs_amf0_object_property_set(keyframes, "times", times); - } else if (srs_amf0_is_ecma_array(amf0_data)) { - keyframes = srs_amf0_ecma_array_property(amf0_data, "keyframes"); - if (keyframes == NULL) { - keyframes = srs_amf0_create_object(); - srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes); - } - // always clear the old keyframes. - srs_amf0_object_clear(keyframes); - - *pfilepositions = filepositions = srs_amf0_create_strict_array(); - srs_amf0_object_property_set(keyframes, "filepositions", filepositions); - - times = srs_amf0_create_strict_array(); - srs_amf0_object_property_set(keyframes, "times", times); - } - } - - free(data); - } - - return ret; -} - -int do_inject_flv(srs_flv_t ic, srs_flv_t oc, srs_amf0_t amf0_name, srs_amf0_t amf0_data, srs_amf0_t filepositions, int64_t metadata_end_offset) -{ - int ret = 0; - - // flv header - char header[13]; - // packet data - char type; - uint32_t timestamp = 0; - char* data = NULL; - int32_t size; - - // metadata - srs_amf0_t fileposition = NULL; - int amf0_name_size = 0; - int i; - - // the metadata end offset, the next tag start offset. - int64_t new_metadata_end_offset = 0; - int offset_adjust = 0; - - // reset to write injected file - srs_flv_lseek(ic, 0); - - if ((ret = srs_flv_read_header(ic, header)) != 0) { - return ret; - } - - if ((ret = srs_flv_write_header(oc, header)) != 0) { - return ret; - } - - // write metadata - if (amf0_name != NULL && amf0_data != NULL) { - amf0_name_size = srs_amf0_size(amf0_name); - size = amf0_name_size + srs_amf0_size(amf0_data); - - // adjust all offset of keyframes. - new_metadata_end_offset = srs_flv_tellg(oc) + srs_flv_size_tag(size); - // the adjust is new offset sub the old offset of metadata end. - offset_adjust = new_metadata_end_offset - metadata_end_offset; - for (i = 0; i < srs_amf0_strict_array_property_count(filepositions); i++) { - fileposition = srs_amf0_strict_array_property_at(filepositions, i); - srs_amf0_set_number(fileposition, srs_amf0_to_number(fileposition) + offset_adjust); - } - - data = (char*)malloc(size); - memset(data, 0, size); - if ((ret = srs_amf0_serialize(amf0_name, data, amf0_name_size)) != 0) { - return ret; - } - if ((ret = srs_amf0_serialize(amf0_data, data + amf0_name_size, size - amf0_name_size)) != 0) { - return ret; - } - if ((ret = srs_flv_write_tag(oc, SRS_RTMP_TYPE_SCRIPT, 0, data, size)) != 0) { - return ret; - } - free(data); - } - - srs_human_trace("build keyframe infos from flv"); - for (;;) { - // tag header - if ((ret = srs_flv_read_tag_header(ic, &type, &size, ×tamp)) != 0) { - if (srs_flv_is_eof(ret)) { - srs_human_trace("parse completed."); - return 0; - } - srs_human_trace("flv get packet failed. ret=%d", ret); - return ret; - } - - if (size <= 0) { - srs_human_trace("invalid size=%d", size); - break; - } - - // TODO: FIXME: mem leak when error. - data = (char*)malloc(size); - if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) { - return ret; - } - - // data tag - if (type == SRS_RTMP_TYPE_SCRIPT) { - continue; - } - - // copy - if ((ret = srs_flv_write_tag(oc, type, timestamp, data, size)) != 0) { - return ret; - } - - free(data); - } - - return ret; -} diff --git a/trunk/research/librtmp/srs_flv_parser.c b/trunk/research/librtmp/srs_flv_parser.c deleted file mode 100644 index 388397a80..000000000 --- a/trunk/research/librtmp/srs_flv_parser.c +++ /dev/null @@ -1,188 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int parse_flv(srs_flv_t flv); -int main(int argc, char** argv) -{ - int ret = 0; - - // user options. - char* in_flv_file; - // flv handler - srs_flv_t flv; - - printf("parse and show flv file detail.\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 1) { - printf("parse and show flv file detail\n" - "Usage: %s in_flv_file\n" - " in_flv_file flv file to parse and show.\n" - "For example:\n" - " %s doc/source.200kbps.768x320.flv\n" - " %s ../../doc/source.200kbps.768x320.flv\n", - argv[0], argv[0], argv[0]); - exit(-1); - } - - in_flv_file = argv[1]; - srs_human_trace("input: %s", in_flv_file); - - if ((flv = srs_flv_open_read(in_flv_file)) == NULL) { - ret = 2; - srs_human_trace("open flv file failed. ret=%d", ret); - return ret; - } - - ret = parse_flv(flv); - srs_flv_close(flv); - - return ret; -} - -void digit_to_char(char* src, int ssize, char* dst, int dsize) -{ - int i, j; - char v; - - for (i = 0, j = 0; i < ssize && j < dsize; i++) { - if (j >= dsize) { - break; - } - v = (src[i] >> 4) & 0x0F; - if (v < 10) { - dst[j++] = '0' + v; - } else { - dst[j++] = 'A' + (v - 10); - } - - if (j >= dsize) { - break; - } - v = src[i] & 0x0F; - if (v < 10) { - dst[j++] = '0' + v; - } else { - dst[j++] = 'A' + (v - 10); - } - - if (j >= dsize) { - break; - } - if (i < ssize - 1) { - dst[j++] = ' '; - } - } -} - -int parse_bytes(char* data, int size, char* hbuf, int hsize, char* tbuf, int tsize, int print_size) -{ - memset(hbuf, 0, hsize); - memset(tbuf, 0, tsize); - - if (size > 0) { - digit_to_char(data, size, hbuf, hsize - 1); - } - - if (size > print_size * 2) { - digit_to_char(data + size - print_size, size, tbuf, tsize - 1); - } - - return 0; -} - -int parse_flv(srs_flv_t flv) -{ - int ret = 0; - - // flv header - char header[13]; - // packet data - char type; - uint32_t timestamp = 0; - char* data = NULL; - int32_t size; - int64_t offset = 0; - - if ((ret = srs_flv_read_header(flv, header)) != 0) { - return ret; - } - - srs_human_trace("start parse flv"); - char buffer[1024]; - for (;;) { - offset = srs_flv_tellg(flv); - - // tag header - if ((ret = srs_flv_read_tag_header(flv, &type, &size, ×tamp)) != 0) { - if (srs_flv_is_eof(ret)) { - srs_human_trace("parse completed."); - return 0; - } - srs_human_trace("flv get packet failed. ret=%d", ret); - return ret; - } - - if (size <= 0) { - srs_human_trace("invalid size=%d", size); - break; - } - - data = (char*)malloc(size); - - if ((ret = srs_flv_read_tag_data(flv, data, size)) == 0) { - if ((ret = srs_human_format_rtmp_packet(buffer, sizeof(buffer), type, timestamp, data, size)) == 0) { - srs_human_trace("%s", buffer); - - char hbuf[48]; char tbuf[48]; - parse_bytes(data, size, hbuf, sizeof(hbuf), tbuf, sizeof(tbuf), 16); - srs_human_raw("offset=%d, first and last 16 bytes:\n[+00, +15] %s\n[-15, EOF] %s\n", (int)offset, hbuf, tbuf); - } else { - srs_human_trace("print packet failed. ret=%d", ret); - } - } else { - srs_human_trace("read flv failed. ret=%d", ret); - } - - free(data); - - if (ret != 0) { - srs_human_trace("parse failed, ret=%d", ret); - return ret; - } - } - - return ret; -} diff --git a/trunk/research/librtmp/srs_h264_raw_publish.c b/trunk/research/librtmp/srs_h264_raw_publish.c deleted file mode 100644 index 5b21a8611..000000000 --- a/trunk/research/librtmp/srs_h264_raw_publish.c +++ /dev/null @@ -1,203 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -// for open h264 raw file. -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int read_h264_frame(char* data, int size, char** pp, int* pnb_start_code, int fps, - char** frame, int* frame_size, int* dts, int* pts) -{ - char* p = *pp; - - // @remark, for this demo, to publish h264 raw file to SRS, - // we search the h264 frame from the buffer which cached the h264 data. - // please get h264 raw data from device, it always a encoded frame. - if (!srs_h264_startswith_annexb(p, size - (p - data), pnb_start_code)) { - srs_human_trace("h264 raw data invalid."); - return -1; - } - - // @see srs_write_h264_raw_frames - // each frame prefixed h.264 annexb header, by N[00] 00 00 01, where N>=0, - // for instance, frame = header(00 00 00 01) + payload(67 42 80 29 95 A0 14 01 6E 40) - *frame = p; - p += *pnb_start_code; - - for (;p < data + size; p++) { - if (srs_h264_startswith_annexb(p, size - (p - data), NULL)) { - break; - } - } - - *pp = p; - *frame_size = p - *frame; - if (*frame_size <= 0) { - srs_human_trace("h264 raw data invalid."); - return -1; - } - - // @remark, please get the dts and pts from device, - // we assume there is no B frame, and the fps can guess the fps and dts, - // while the dts and pts must read from encode lib or device. - *dts += 1000 / fps; - *pts = *dts; - - return 0; -} - -int main(int argc, char** argv) -{ - printf("publish raw h.264 as rtmp stream to server like FMLE/FFMPEG/Encoder\n"); - printf("SRS(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 3) { - printf("Usage: %s \n", argv[0]); - printf(" h264_raw_file: the h264 raw steam file.\n"); - printf(" rtmp_publish_url: the rtmp publish url.\n"); - printf(" fps: the video average fps, for example, 25.\n"); - printf("For example:\n"); - printf(" %s ./720p.h264.raw rtmp://127.0.0.1:1935/live/livestream 25\n", argv[0]); - printf("Where the file: http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw\n"); - printf(" See: https://github.com/ossrs/srs/issues/66\n"); - exit(-1); - } - - const char* raw_file = argv[1]; - const char* rtmp_url = argv[2]; - // @remark, the dts and pts if read from device, for instance, the encode lib, - // so we assume the fps is 25, and each h264 frame is 1000ms/25fps=40ms/f. - double fps = atof(argv[3]); - srs_human_trace("raw_file=%s, rtmp_url=%s, fps=%.2f", raw_file, rtmp_url, fps); - - // open file - int raw_fd = open(raw_file, O_RDONLY); - if (raw_fd < 0) { - srs_human_trace("open h264 raw file %s failed.", raw_file); - goto rtmp_destroy; - } - - off_t file_size = lseek(raw_fd, 0, SEEK_END); - if (file_size <= 0) { - srs_human_trace("h264 raw file %s empty.", raw_file); - goto rtmp_destroy; - } - srs_human_trace("read entirely h264 raw file, size=%dKB", (int)(file_size / 1024)); - - char* h264_raw = (char*)malloc(file_size); - if (!h264_raw) { - srs_human_trace("alloc raw buffer failed for file %s.", raw_file); - goto rtmp_destroy; - } - - lseek(raw_fd, 0, SEEK_SET); - ssize_t nb_read = 0; - if ((nb_read = read(raw_fd, h264_raw, file_size)) != file_size) { - srs_human_trace("buffer %s failed, expect=%dKB, actual=%dKB.", - raw_file, (int)(file_size / 1024), (int)(nb_read / 1024)); - goto rtmp_destroy; - } - - // connect rtmp context - srs_rtmp_t rtmp = srs_rtmp_create(rtmp_url); - - if (srs_rtmp_handshake(rtmp) != 0) { - srs_human_trace("simple handshake failed."); - goto rtmp_destroy; - } - srs_human_trace("simple handshake success"); - - if (srs_rtmp_connect_app(rtmp) != 0) { - srs_human_trace("connect vhost/app failed."); - goto rtmp_destroy; - } - srs_human_trace("connect vhost/app success"); - - if (srs_rtmp_publish_stream(rtmp) != 0) { - srs_human_trace("publish stream failed."); - goto rtmp_destroy; - } - srs_human_trace("publish stream success"); - - int dts = 0; - int pts = 0; - // @remark, to decode the file. - char* p = h264_raw; - int count = 0; - for (; p < h264_raw + file_size;) { - // @remark, read a frame from file buffer. - char* data = NULL; - int size = 0; - int nb_start_code = 0; - if (read_h264_frame(h264_raw, (int)file_size, &p, &nb_start_code, fps, &data, &size, &dts, &pts) < 0) { - srs_human_trace("read a frame from file buffer failed."); - goto rtmp_destroy; - } - - // send out the h264 packet over RTMP - int ret = srs_h264_write_raw_frames(rtmp, data, size, dts, pts); - if (ret != 0) { - if (srs_h264_is_dvbsp_error(ret)) { - srs_human_trace("ignore drop video error, code=%d", ret); - } else if (srs_h264_is_duplicated_sps_error(ret)) { - srs_human_trace("ignore duplicated sps, code=%d", ret); - } else if (srs_h264_is_duplicated_pps_error(ret)) { - srs_human_trace("ignore duplicated pps, code=%d", ret); - } else { - srs_human_trace("send h264 raw data failed. ret=%d", ret); - goto rtmp_destroy; - } - } - - // 5bits, 7.3.1 NAL unit syntax, - // ISO_IEC_14496-10-AVC-2003.pdf, page 44. - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame, 9: AUD, 6: SEI - uint8_t nut = (char)data[nb_start_code] & 0x1f; - srs_human_trace("sent packet: type=%s, time=%d, size=%d, fps=%.2f, b[%d]=%#x(%s)", - srs_human_flv_tag_type2string(SRS_RTMP_TYPE_VIDEO), dts, size, fps, nb_start_code, (char)data[nb_start_code], - (nut == 7? "SPS":(nut == 8? "PPS":(nut == 5? "I":(nut == 1? "P":(nut == 9? "AUD":(nut == 6? "SEI":"Unknown"))))))); - - // @remark, when use encode device, it not need to sleep. - if (count++ == 9) { - usleep(1000 * 1000 * count / fps); - count = 0; - } - } - srs_human_trace("h264 raw data completed"); - -rtmp_destroy: - srs_rtmp_destroy(rtmp); - close(raw_fd); - free(h264_raw); - - return 0; -} - diff --git a/trunk/research/librtmp/srs_ingest_flv.c b/trunk/research/librtmp/srs_ingest_flv.c deleted file mode 100644 index b1c6d98e5..000000000 --- a/trunk/research/librtmp/srs_ingest_flv.c +++ /dev/null @@ -1,273 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int proxy(srs_flv_t flv, srs_rtmp_t ortmp); -int connect_oc(srs_rtmp_t ortmp); - -#define RE_PULSE_MS 300 -#define RE_PULSE_JITTER_MS 3000 -int64_t re_create(); -void re_update(int64_t re, int32_t starttime, uint32_t time); -void re_cleanup(int64_t re, int32_t starttime, uint32_t time); - -int64_t tools_main_entrance_startup_time; -int main(int argc, char** argv) -{ - int ret = 0; - - // main function - tools_main_entrance_startup_time = srs_utils_time_ms(); - - // user option parse index. - int opt = 0; - // user options. - char* in_flv_file = NULL; - char* out_rtmp_url = NULL; - // rtmp handler - srs_rtmp_t ortmp; - // flv handler - srs_flv_t flv; - - printf("ingest flv file and publish to RTMP server like FFMPEG.\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 2) { - printf("ingest flv file and publish to RTMP server\n" - "Usage: %s <-i in_flv_file> <-y out_rtmp_url>\n" - " in_flv_file input flv file, ingest from this file.\n" - " out_rtmp_url output rtmp url, publish to this url.\n" - "For example:\n" - " %s -i doc/source.200kbps.768x320.flv -y rtmp://127.0.0.1/live/livestream\n" - " %s -i ../../doc/source.200kbps.768x320.flv -y rtmp://127.0.0.1/live/livestream\n", - argv[0], argv[0], argv[0]); - exit(-1); - } - - for (opt = 0; opt < argc; opt++) { - srs_human_trace("argv[%d]=%s", opt, argv[opt]); - } - - // fill the options for mac - for (opt = 0; opt < argc - 1; opt++) { - // ignore all options except -i and -y. - char* p = argv[opt]; - - // only accept -x - if (p[0] != '-' || p[1] == 0 || p[2] != 0) { - continue; - } - - // parse according the option name. - switch (p[1]) { - case 'i': in_flv_file = argv[opt + 1]; break; - case 'y': out_rtmp_url = argv[opt + 1]; break; - default: break; - } - } - - if (!in_flv_file) { - srs_human_trace("input invalid, use -i "); - return -1; - } - if (!out_rtmp_url) { - srs_human_trace("output invalid, use -y "); - return -1; - } - - srs_human_trace("input: %s", in_flv_file); - srs_human_trace("output: %s", out_rtmp_url); - - if ((flv = srs_flv_open_read(in_flv_file)) == NULL) { - ret = 2; - srs_human_trace("open flv file failed. ret=%d", ret); - return ret; - } - - ortmp = srs_rtmp_create(out_rtmp_url); - - ret = proxy(flv, ortmp); - srs_human_trace("ingest flv to RTMP completed"); - - srs_rtmp_destroy(ortmp); - srs_flv_close(flv); - - return ret; -} - -int do_proxy(srs_flv_t flv, srs_rtmp_t ortmp, int64_t re, int32_t* pstarttime, uint32_t* ptimestamp) -{ - int ret = 0; - - // packet data - char type; - int size; - char* data = NULL; - - srs_human_trace("start ingest flv to RTMP stream"); - char buffer[1024]; - for (;;) { - // tag header - if ((ret = srs_flv_read_tag_header(flv, &type, &size, ptimestamp)) != 0) { - if (srs_flv_is_eof(ret)) { - srs_human_trace("parse completed."); - return 0; - } - srs_human_trace("flv get packet failed. ret=%d", ret); - return ret; - } - - if (size <= 0) { - srs_human_trace("invalid size=%d", size); - break; - } - - // TODO: FIXME: mem leak when error. - data = (char*)malloc(size); - if ((ret = srs_flv_read_tag_data(flv, data, size)) != 0) { - return ret; - } - - uint32_t timestamp = *ptimestamp; - - if ((ret = srs_human_format_rtmp_packet(buffer, sizeof(buffer), type, timestamp, data, size)) != 0) { - srs_human_trace("print packet failed. ret=%d", ret); - return ret; - } - srs_human_trace("%s", buffer); - - if ((ret = srs_rtmp_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { - srs_human_trace("irtmp get packet failed. ret=%d", ret); - return ret; - } - - if (*pstarttime < 0 && srs_utils_flv_tag_is_av(type)) { - *pstarttime = *ptimestamp; - } - - re_update(re, *pstarttime, *ptimestamp); - } - - return ret; -} - -int proxy(srs_flv_t flv, srs_rtmp_t ortmp) -{ - int ret = 0; - uint32_t timestamp = 0; - int32_t starttime = -1; - - char header[13]; - if ((ret = srs_flv_read_header(flv, header)) != 0) { - return ret; - } - if ((ret = connect_oc(ortmp)) != 0) { - return ret; - } - - int64_t re = re_create(); - - ret = do_proxy(flv, ortmp, re, &starttime, ×tamp); - - // for the last pulse, always sleep. - re_cleanup(re, starttime, timestamp); - - return ret; -} - -int connect_oc(srs_rtmp_t ortmp) -{ - int ret = 0; - - if ((ret = srs_rtmp_handshake(ortmp)) != 0) { - srs_human_trace("ortmp simple handshake failed. ret=%d", ret); - return ret; - } - srs_human_trace("ortmp simple handshake success"); - - if ((ret = srs_rtmp_connect_app(ortmp)) != 0) { - srs_human_trace("ortmp connect vhost/app failed. ret=%d", ret); - return ret; - } - srs_human_trace("ortmp connect vhost/app success"); - - if ((ret = srs_rtmp_publish_stream(ortmp)) != 0) { - srs_human_trace("ortmp publish stream failed. ret=%d", ret); - return ret; - } - srs_human_trace("ortmp publish stream success"); - - return ret; -} - -int64_t re_create() -{ - // if not very precise, we can directly use this as re. - int64_t re = srs_utils_time_ms(); - - // use the starttime to get the deviation - int64_t deviation = re - tools_main_entrance_startup_time; - srs_human_trace("deviation is %d ms, pulse is %d ms", (int)(deviation), (int)(RE_PULSE_MS)); - - // so, we adjust time to max(0, deviation) - // because the last pulse, we already sleeped - int adjust = (int)(deviation); - if (adjust > 0) { - srs_human_trace("adjust re time for %d ms", adjust); - re -= adjust; - } else { - srs_human_trace("no need to adjust re time"); - } - - return re; -} -void re_update(int64_t re, int32_t starttime, uint32_t time) -{ - // send by pulse algorithm. - int64_t now = srs_utils_time_ms(); - int64_t diff = time - starttime - (now -re); - if (diff > RE_PULSE_MS && diff < RE_PULSE_JITTER_MS) { - usleep((useconds_t)(diff * 1000)); - } -} -void re_cleanup(int64_t re, int32_t starttime, uint32_t time) -{ - // for the last pulse, always sleep. - // for the virtual live encoder long time publishing. - int64_t now = srs_utils_time_ms(); - int64_t diff = time - starttime - (now -re); - if (diff > 0) { - srs_human_trace("re_cleanup, diff=%d, start=%d, last=%d ms", (int)diff, starttime, time); - usleep((useconds_t)(diff * 1000)); - } -} diff --git a/trunk/research/librtmp/srs_ingest_mp4.c b/trunk/research/librtmp/srs_ingest_mp4.c deleted file mode 100644 index ca723b109..000000000 --- a/trunk/research/librtmp/srs_ingest_mp4.c +++ /dev/null @@ -1,261 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int64_t tools_main_entrance_startup_time; -int proxy(srs_mp4_t mp4, srs_rtmp_t ortmp); -int main(int argc, char** argv) -{ - // main function - tools_main_entrance_startup_time = srs_utils_time_ms(); - - printf("Ingest mp4 file and publish to RTMP server like FFMPEG.\n"); - printf("SRS(OSSRS) client librtmp library.\n"); - printf("Version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 2) { - printf("Ingest mp4 file and publish to RTMP server\n" - "Usage: %s <-i in_mp4_file> <-y out_rtmp_url>\n" - " in_mp4_file input mp4 file, ingest from this file.\n" - " out_rtmp_url output rtmp url, publish to this url.\n" - "@remark Only support non-seek mp4, see https://github.com/ossrs/srs/issues/738#issuecomment-276343669\n" - "For example:\n" - " %s -i avatar.mp4 -y rtmp://127.0.0.1/live/livestream\n", - argv[0], argv[0]); - exit(-1); - } - - int opt; - for (opt = 0; opt < argc; opt++) { - srs_human_trace("The argv[%d]=%s", opt, argv[opt]); - } - - // fill the options for mac - char* in_file = NULL; - char* out_rtmp_url = NULL; - for (opt = 0; opt < argc - 1; opt++) { - // ignore all options except -i and -y. - char* p = argv[opt]; - - // only accept -x - if (p[0] != '-' || p[1] == 0 || p[2] != 0) { - continue; - } - - // parse according the option name. - switch (p[1]) { - case 'i': in_file = argv[opt + 1]; break; - case 'y': out_rtmp_url = argv[opt + 1]; break; - default: break; - } - } - - if (!in_file) { - srs_human_trace("Invalid input file, use -i "); - return -1; - } - if (!out_rtmp_url) { - srs_human_trace("Invalid output url, use -y "); - return -1; - } - - srs_human_trace("Input file: %s", in_file); - srs_human_trace("Output url: %s", out_rtmp_url); - - int ret = 0; - - srs_mp4_t mp4 = NULL; - if ((mp4 = srs_mp4_open_read(in_file)) == NULL) { - ret = 2; - srs_human_trace("open mp4 file failed. ret=%d", ret); - return ret; - } - - srs_rtmp_t ortmp = srs_rtmp_create(out_rtmp_url); - - ret = proxy(mp4, ortmp); - srs_human_trace("Ingest mp4 to RTMP ok."); - - srs_rtmp_destroy(ortmp); - srs_mp4_close(mp4); - - return ret; -} - -int connect_oc(srs_rtmp_t ortmp) -{ - int ret = 0; - - if ((ret = srs_rtmp_handshake(ortmp)) != 0) { - srs_human_trace("ortmp simple handshake failed. ret=%d", ret); - return ret; - } - srs_human_trace("ortmp simple handshake success"); - - if ((ret = srs_rtmp_connect_app(ortmp)) != 0) { - srs_human_trace("ortmp connect vhost/app failed. ret=%d", ret); - return ret; - } - srs_human_trace("ortmp connect vhost/app success"); - - if ((ret = srs_rtmp_publish_stream(ortmp)) != 0) { - srs_human_trace("ortmp publish stream failed. ret=%d", ret); - return ret; - } - srs_human_trace("ortmp publish stream success"); - - return ret; -} - -#define RE_PULSE_MS 300 -#define RE_PULSE_JITTER_MS 3000 - -int64_t re_create() -{ - // if not very precise, we can directly use this as re. - int64_t re = srs_utils_time_ms(); - - // use the starttime to get the deviation - int64_t deviation = re - tools_main_entrance_startup_time; - srs_human_trace("deviation is %d ms, pulse is %d ms", (int)(deviation), (int)(RE_PULSE_MS)); - - // so, we adjust time to max(0, deviation) - // because the last pulse, we already sleeped - int adjust = (int)(deviation); - if (adjust > 0) { - srs_human_trace("adjust re time for %d ms", adjust); - re -= adjust; - } else { - srs_human_trace("no need to adjust re time"); - } - - return re; -} - -void re_update(int64_t re, int32_t starttime, uint32_t time) -{ - // send by pulse algorithm. - int64_t now = srs_utils_time_ms(); - int64_t diff = time - starttime - (now -re); - if (diff > RE_PULSE_MS && diff < RE_PULSE_JITTER_MS) { - usleep((useconds_t)(diff * 1000)); - } -} - -void re_cleanup(int64_t re, int32_t starttime, uint32_t time) -{ - // for the last pulse, always sleep. - // for the virtual live encoder long time publishing. - int64_t now = srs_utils_time_ms(); - int64_t diff = time - starttime - (now -re); - if (diff > 0) { - srs_human_trace("re_cleanup, diff=%d, start=%d, last=%d ms", - (int)diff, starttime, time); - usleep((useconds_t)(diff * 1000)); - } -} - -int do_proxy(srs_mp4_t mp4, srs_rtmp_t ortmp, int64_t re, int32_t* pstarttime, uint32_t* ptimestamp) -{ - int ret = 0; - - srs_human_trace("start ingest mp4 to RTMP stream"); - char buffer[1024]; - for (;;) { - // packet data - char type; - int32_t size; - char* data = NULL; - - // Read a mp4 sample and convert to flv tag. - if (1) { - srs_mp4_sample_t sample; - if ((ret = srs_mp4_read_sample(mp4, &sample)) != 0) { - if (srs_mp4_is_eof(ret)) { - srs_human_trace("parse completed."); - return 0; - } - srs_human_trace("mp4 get sample failed. ret=%d", ret); - return ret; - } - - size = srs_mp4_sizeof(mp4, &sample); - data = (char*)malloc(size); - - if ((ret = srs_mp4_to_flv_tag(mp4, &sample, &type, ptimestamp, data, size)) != 0) { - return ret; - } - - srs_mp4_free_sample(&sample); - } - uint32_t timestamp = *ptimestamp; - - if ((ret = srs_human_format_rtmp_packet(buffer, sizeof(buffer), type, timestamp, data, size)) != 0) { - srs_human_trace("print packet failed. ret=%d", ret); - return ret; - } - srs_human_trace("%s", buffer); - - if ((ret = srs_rtmp_write_packet(ortmp, type, *ptimestamp, data, size)) != 0) { - srs_human_trace("irtmp get packet failed. ret=%d", ret); - return ret; - } - - if (*pstarttime < 0 && srs_utils_flv_tag_is_av(type)) { - *pstarttime = *ptimestamp; - } - - re_update(re, *pstarttime, *ptimestamp); - } - - return ret; -} - -int proxy(srs_mp4_t mp4, srs_rtmp_t ortmp) -{ - int ret = 0; - - if ((ret = srs_mp4_init_demuxer(mp4)) != 0) { - srs_human_trace("init demuxer failed. ret=%d", ret); - return ret; - } - if ((ret = connect_oc(ortmp)) != 0) { - return ret; - } - - int64_t re = re_create(); - - uint32_t timestamp = 0; - int32_t starttime = -1; - ret = do_proxy(mp4, ortmp, re, &starttime, ×tamp); - - // for the last pulse, always sleep. - re_cleanup(re, starttime, timestamp); - - return ret; -} - diff --git a/trunk/research/librtmp/srs_ingest_rtmp.c b/trunk/research/librtmp/srs_ingest_rtmp.c deleted file mode 100644 index 222488b44..000000000 --- a/trunk/research/librtmp/srs_ingest_rtmp.c +++ /dev/null @@ -1,279 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int connect_ic(srs_rtmp_t irtmp); -int connect_oc(srs_rtmp_t ortmp); -int proxy(srs_rtmp_t irtmp, srs_rtmp_t ortmp); - -// whether use verbose log. -int verbose = 0; -// 2000 is about 30s. -#define PITHY_PRINT_EVERY_MSGS 2000 - -int main(int argc, char** argv) -{ - int ret = 0; - - // user option parse index. - int opt = 0; - // user options. - char* in_rtmp_url = NULL; - char* out_rtmp_url = NULL; - // rtmp handler - srs_rtmp_t irtmp, ortmp; - - printf("Ingest RTMP to server like FFMPEG over srs-librtmp %d.%d.%d\n", - srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 2) { - printf("ingest RTMP and publish to RTMP server\n" - "Usage: %s <-i in_rtmp_url> <-y out_rtmp_url> [-v verbose]\n" - " in_rtmp_url input rtmp url, ingest from this url.\n" - " out_rtmp_url output rtmp url, publish to this url.\n" - " verbose output verbose log.\n" - "For example:\n" - " %s -i rtmp://127.0.0.1/live/livestream -y rtmp://127.0.0.1/live/demo\n" - " %s -i rtmp://127.0.0.1/live/livestream -y rtmp://127.0.0.1/live/demo -v verbose\n", - argv[0], argv[0], argv[0]); - exit(-1); - } - - // fill the options for mac - for (opt = 0; opt < argc - 1; opt++) { - // ignore all options except -i and -y. - char* p = argv[opt]; - - // only accept -x - if (p[0] != '-' || p[1] == 0 || p[2] != 0) { - continue; - } - - // parse according the option name. - switch (p[1]) { - case 'i': in_rtmp_url = argv[++opt]; break; - case 'y': out_rtmp_url = argv[++opt]; break; - case 'v': verbose=1; opt++; break; - default: break; - } - } - - if (!in_rtmp_url) { - srs_human_trace("input invalid, use -i "); - return -1; - } - if (!out_rtmp_url) { - srs_human_trace("output invalid, use -y "); - return -1; - } - - srs_human_trace("ingest %s to %s, verbose=%d", in_rtmp_url, out_rtmp_url, verbose); - - irtmp = srs_rtmp_create(in_rtmp_url); - ortmp = srs_rtmp_create(out_rtmp_url); - - ret = proxy(irtmp, ortmp); - srs_human_trace("proxy completed"); - - srs_rtmp_destroy(irtmp); - srs_rtmp_destroy(ortmp); - - return ret; -} - -int proxy(srs_rtmp_t irtmp, srs_rtmp_t ortmp) -{ - int ret = 0; - - // packet data - int size; - char type; - char* data; - uint32_t timestamp; - uint64_t nb_msgs = 0; - - if ((ret = connect_ic(irtmp)) != 0) { - return ret; - } - if ((ret = connect_oc(ortmp)) != 0) { - return ret; - } - - if (verbose) { - srs_human_trace("start proxy RTMP stream"); - } else { - srs_human_verbose("start proxy RTMP stream"); - } - - char buffer[1024]; - for (;;) { - if ((ret = srs_rtmp_read_packet(irtmp, &type, ×tamp, &data, &size)) != 0) { - srs_human_trace("irtmp get packet failed. ret=%d", ret); - return ret; - } - - if (!srs_utils_flv_tag_is_ok(type)) { - if (verbose) { - srs_human_trace("ignore invalid flv tag=%d, dts=%d, %d bytes", type, timestamp, size); - } else { - srs_human_verbose("ignore invalid flv tag=%d, dts=%d, %d bytes", type, timestamp, size); - } - free(data); - continue; - } - - if (verbose || ((nb_msgs++ % PITHY_PRINT_EVERY_MSGS) == 0 && nb_msgs > 10)) { - if ((ret = srs_human_format_rtmp_packet(buffer, sizeof(buffer), type, timestamp, data, size)) != 0) { - srs_human_trace("print packet failed. ret=%d", ret); - return ret; - } - srs_human_trace("%s", buffer); - } - - if ((ret = srs_rtmp_write_packet(ortmp, type, timestamp, data, size)) != 0) { - srs_human_trace("irtmp get packet failed. ret=%d", ret); - return ret; - } - - if (verbose) { - srs_human_trace("ortmp sent packet: type=%s, time=%d, size=%d", - srs_human_flv_tag_type2string(type), timestamp, size); - } else { - srs_human_verbose("ortmp sent packet: type=%s, time=%d, size=%d", - srs_human_flv_tag_type2string(type), timestamp, size); - } - } - - return ret; -} - -int connect_ic(srs_rtmp_t irtmp) -{ - int ret = 0; - - // srs debug info. - char* ip = NULL; - char* sig = NULL; - int pid = 0, cid = 0; - int major = 0, minor = 0, revision= 0, build = 0; - - if ((ret = srs_rtmp_handshake(irtmp)) != 0) { - srs_human_trace("irtmp simple handshake failed. ret=%d", ret); - return ret; - } - if (verbose) { - srs_human_trace("irtmp simple handshake success"); - } else { - srs_human_verbose("irtmp simple handshake success"); - } - - if (srs_rtmp_connect_app(irtmp) != 0) { - srs_human_trace("irtmp connect vhost/app failed. ret=%d", ret); - return ret; - } - - if ((ret = srs_rtmp_get_server_sig(irtmp, &sig)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_id(irtmp, &ip, &pid, &cid)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_version(irtmp, &major, &minor, &revision, &build)) != 0) { - srs_human_trace("Retrieve server version failed, ret=%d", ret); - return ret; - } - srs_human_trace("irtmp connect ok, ip=%s, server=%s/%d.%d.%d.%d, pid=%d, cid=%d", - ip, sig, major, minor, revision, build, pid, cid); - - if ((ret = srs_rtmp_play_stream(irtmp)) != 0) { - srs_human_trace("irtmp play stream failed. ret=%d", ret); - return ret; - } - if (verbose) { - srs_human_trace("irtmp play stream success"); - } else { - srs_human_verbose("irtmp play stream success"); - } - - return ret; -} - -int connect_oc(srs_rtmp_t ortmp) -{ - int ret = 0; - - // srs debug info. - char* ip = NULL; - char* sig = NULL; - int pid = 0, cid = 0; - int major = 0, minor = 0, revision= 0, build = 0; - - if ((ret = srs_rtmp_handshake(ortmp)) != 0) { - srs_human_trace("ortmp simple handshake failed. ret=%d", ret); - return ret; - } - if (verbose) { - srs_human_trace("ortmp simple handshake success"); - } else { - srs_human_verbose("ortmp simple handshake success"); - } - - if (srs_rtmp_connect_app(ortmp) != 0) { - srs_human_trace("ortmp connect vhost/app failed. ret=%d", ret); - return ret; - } - - if ((ret = srs_rtmp_get_server_sig(ortmp, &sig)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_id(ortmp, &ip, &pid, &cid)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_version(ortmp, &major, &minor, &revision, &build)) != 0) { - srs_human_trace("Retrieve server version failed, ret=%d", ret); - return ret; - } - srs_human_trace("ortmp connect ok, ip=%s, server=%s/%d.%d.%d.%d, pid=%d, cid=%d", - ip, sig, major, minor, revision, build, pid, cid); - - if ((ret = srs_rtmp_publish_stream(ortmp)) != 0) { - srs_human_trace("ortmp publish stream failed. ret=%d", ret); - return ret; - } - if (verbose) { - srs_human_trace("ortmp publish stream success"); - } else { - srs_human_verbose("ortmp publish stream success"); - } - - return ret; -} diff --git a/trunk/research/librtmp/srs_play.c b/trunk/research/librtmp/srs_play.c deleted file mode 100644 index 6bf8b26b7..000000000 --- a/trunk/research/librtmp/srs_play.c +++ /dev/null @@ -1,88 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int main(int argc, char** argv) -{ - printf("suck rtmp stream like rtmpdump\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 1) { - printf("Usage: %s \n" - " rtmp_url RTMP stream url to play\n" - "For example:\n" - " %s rtmp://127.0.0.1:1935/live/livestream\n", - argv[0], argv[0]); - exit(-1); - } - - srs_human_trace("rtmp url: %s", argv[1]); - srs_rtmp_t rtmp = srs_rtmp_create(argv[1]); - - if (srs_rtmp_handshake(rtmp) != 0) { - srs_human_trace("simple handshake failed."); - goto rtmp_destroy; - } - srs_human_trace("simple handshake success"); - - if (srs_rtmp_connect_app(rtmp) != 0) { - srs_human_trace("connect vhost/app failed."); - goto rtmp_destroy; - } - srs_human_trace("connect vhost/app success"); - - if (srs_rtmp_play_stream(rtmp) != 0) { - srs_human_trace("play stream failed."); - goto rtmp_destroy; - } - srs_human_trace("play stream success"); - - char buffer[1024]; - for (;;) { - int size; - char type; - char* data; - uint32_t timestamp; - - if (srs_rtmp_read_packet(rtmp, &type, ×tamp, &data, &size) != 0) { - goto rtmp_destroy; - } - - if (srs_human_format_rtmp_packet(buffer, sizeof(buffer), type, timestamp, data, size) != 0) { - goto rtmp_destroy; - } - srs_human_trace("%s", buffer); - - free(data); - } - -rtmp_destroy: - srs_rtmp_destroy(rtmp); - - return 0; -} diff --git a/trunk/research/librtmp/srs_publish.c b/trunk/research/librtmp/srs_publish.c deleted file mode 100644 index 880f8a7fc..000000000 --- a/trunk/research/librtmp/srs_publish.c +++ /dev/null @@ -1,93 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -int main(int argc, char** argv) -{ - printf("publish rtmp stream to server like FMLE/FFMPEG/Encoder\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - - if (argc <= 1) { - printf("Usage: %s \n" - " rtmp_url RTMP stream url to publish\n" - "For example:\n" - " %s rtmp://127.0.0.1:1935/live/livestream\n", - argv[0], argv[0]); - exit(-1); - } - - // warn it . - // @see: https://github.com/ossrs/srs/issues/126 - srs_human_trace("\033[33m%s\033[0m", - "[warning] it's only a sample to use librtmp. " - "please never use it to publish and test forward/transcode/edge/HLS whatever. " - "you should refer to this tool to use the srs-librtmp to publish the real media stream." - "read about: https://github.com/ossrs/srs/issues/126"); - srs_human_trace("rtmp url: %s", argv[1]); - srs_rtmp_t rtmp = srs_rtmp_create(argv[1]); - - if (srs_rtmp_handshake(rtmp) != 0) { - srs_human_trace("simple handshake failed."); - goto rtmp_destroy; - } - srs_human_trace("simple handshake success"); - - if (srs_rtmp_connect_app(rtmp) != 0) { - srs_human_trace("connect vhost/app failed."); - goto rtmp_destroy; - } - srs_human_trace("connect vhost/app success"); - - if (srs_rtmp_publish_stream(rtmp) != 0) { - srs_human_trace("publish stream failed."); - goto rtmp_destroy; - } - srs_human_trace("publish stream success"); - - uint32_t timestamp = 0; - for (;;) { - char type = SRS_RTMP_TYPE_VIDEO; - int size = 4096; - char* data = (char*)malloc(4096); - - timestamp += 40; - - if (srs_rtmp_write_packet(rtmp, type, timestamp, data, size) != 0) { - goto rtmp_destroy; - } - srs_human_trace("sent packet: type=%s, time=%d, size=%d", srs_human_flv_tag_type2string(type), timestamp, size); - - usleep(40 * 1000); - } - -rtmp_destroy: - srs_rtmp_destroy(rtmp); - - return 0; -} diff --git a/trunk/research/librtmp/srs_rtmp_dump.c b/trunk/research/librtmp/srs_rtmp_dump.c deleted file mode 100644 index 03d94ae50..000000000 --- a/trunk/research/librtmp/srs_rtmp_dump.c +++ /dev/null @@ -1,350 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include -#include -#include - -#include "../../objs/include/srs_librtmp.h" - -void parse_amf0_object(char* p, srs_amf0_t args) -{ - char opvt = 0; // object property value type. - const char* opnp = NULL; // object property name ptr. - const char* opvp = NULL; // object property value ptr. - - while (*p) { - switch (*p++) { - case 'O': - while (*p && *p++ != ':') { - } - if (*p++ == '1') { - printf("amf0 object start\n"); - } else { - printf("amf0 object end\n"); - } - break; - case 'N': - opvt = *p++; - if (*p++ != ':') { - printf("object property must split by :.\n"); - exit(-1); - } - opnp = p++; - while (*p && *p++ != ':') { - } - p[-1] = 0; - opvp = p; - printf("amf0 %c property[%s]=%s\n", opvt, opnp, opvp); - switch(opvt) { - case 'S': - srs_amf0_object_property_set(args, opnp, srs_amf0_create_string(opvp)); - break; - default: - printf("unsupported object property.\n"); - exit(-1); - } - *p=0; - break; - default: - printf("only supports an object arg.\n"); - exit(-1); - } - } -} - -// srs debug info. -char* ip = NULL; -char* sig = NULL; -int pid = 0, cid = 0; -int major = 0, minor = 0, revision= 0, build = 0; -// User options. -int complex_handshake = 0; -const char* rtmp_url = NULL; -const char* output_flv = NULL; -const char* swfUrl = NULL; -const char* tcUrl = NULL; -const char* pageUrl = NULL; -srs_amf0_t args = NULL; - -int do_proxy(srs_rtmp_t rtmp, srs_flv_t flv) -{ - int ret = 0; - - if ((ret = srs_rtmp_dns_resolve(rtmp)) != 0) { - srs_human_trace("dns resolve failed, ret=%d", ret); - return ret; - } - - if ((ret = srs_rtmp_connect_server(rtmp)) != 0) { - srs_human_trace("connect to server failed, ret=%d", ret); - return ret; - } - - if (complex_handshake) { - if ((ret = srs_rtmp_do_complex_handshake(rtmp)) != 0) { - srs_human_trace("complex handshake failed, ret=%d", ret); - return ret; - } - srs_human_trace("do complex handshake success"); - } else { - if ((ret = srs_rtmp_do_simple_handshake(rtmp)) != 0) { - srs_human_trace("simple handshake failed, ret=%d", ret); - return ret; - } - srs_human_trace("do simple handshake success"); - } - - if ((ret = srs_rtmp_set_connect_args(rtmp, tcUrl, swfUrl, pageUrl, args)) != 0) { - srs_human_trace("set connect args failed, ret=%d", ret); - return ret; - } - - if ((ret = srs_rtmp_connect_app(rtmp)) != 0) { - srs_human_trace("connect vhost/app failed, ret=%d", ret); - return ret; - } - - if ((ret = srs_rtmp_get_server_sig(rtmp, &sig)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_id(rtmp, &ip, &pid, &cid)) != 0) { - srs_human_trace("Retrieve server ID failed, ret=%d", ret); - return ret; - } - if ((ret = srs_rtmp_get_server_version(rtmp, &major, &minor, &revision, &build)) != 0) { - srs_human_trace("Retrieve server version failed, ret=%d", ret); - return ret; - } - srs_human_trace("connect ok, ip=%s, server=%s/%d.%d.%d.%d, pid=%d, cid=%d", - ip, sig, major, minor, revision, build, pid, cid); - - if ((ret = srs_rtmp_play_stream(rtmp)) != 0) { - srs_human_trace("play stream failed, ret=%d", ret); - return ret; - } - srs_human_trace("play stream success"); - - if (flv) { - // flv header - char header[9]; - // 3bytes, signature, "FLV", - header[0] = 'F'; - header[1] = 'L'; - header[2] = 'V'; - // 1bytes, version, 0x01, - header[3] = 0x01; - // 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. - header[4] = 0x03; // audio + video. - // 4bytes, dataoffset - header[5] = 0x00; - header[6] = 0x00; - header[7] = 0x00; - header[8] = 0x09; - if ((ret = srs_flv_write_header(flv, header)) != 0) { - srs_human_trace("write flv header failed, ret=%d", ret); - return ret; - } - } - - int64_t nb_packets = 0; - uint32_t pre_timestamp = 0; - int64_t pre_now = -1; - int64_t start_time = -1; - char buffer[1024]; - for (;;) { - int size; - char type; - char* data; - uint32_t timestamp; - - if ((ret = srs_rtmp_read_packet(rtmp, &type, ×tamp, &data, &size)) != 0) { - srs_human_trace("read rtmp packet failed, ret=%d", ret); - return ret; - } - - if (pre_now == -1) { - pre_now = srs_utils_time_ms(); - } - if (start_time == -1) { - start_time = srs_utils_time_ms(); - } - - if ((ret = srs_human_format_rtmp_packet2(buffer, sizeof(buffer), type, timestamp, data, size, pre_timestamp, pre_now, start_time, nb_packets++)) != 0) { - srs_human_trace("print rtmp packet failed, ret=%d", ret); - return ret; - } - srs_human_trace("%s", buffer); - - pre_timestamp = timestamp; - pre_now = srs_utils_time_ms(); - - // we only write some types of messages to flv file. - int is_flv_msg = type == SRS_RTMP_TYPE_AUDIO - || type == SRS_RTMP_TYPE_VIDEO || type == SRS_RTMP_TYPE_SCRIPT; - - // for script data, ignore except onMetaData - if (type == SRS_RTMP_TYPE_SCRIPT) { - if (!srs_rtmp_is_onMetaData(type, data, size)) { - is_flv_msg = 0; - } - } - - if (flv) { - if (is_flv_msg) { - if ((ret = srs_flv_write_tag(flv, type, timestamp, data, size)) != 0) { - srs_human_trace("dump rtmp packet failed, ret=%d", ret); - return ret; - } - } else { - srs_human_trace("drop message type=%#x, size=%dB", type, size); - } - } - - free(data); - } - - return ret; -} - -int main(int argc, char** argv) -{ - srs_flv_t flv = NULL; - srs_rtmp_t rtmp = NULL; - - printf("dump rtmp stream to flv file\n"); - printf("srs(ossrs) client librtmp library.\n"); - printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision()); - printf("@refer to http://rtmpdump.mplayerhq.hu/rtmpdump.1.html\n"); - - int show_help = 0; - const char* short_options = "hxr:o:s:t:p:C:"; - struct option long_options[] = { - {"rtmp", required_argument, 0, 'r'}, - {"flv", required_argument, 0, 'o'}, - {"swfUrl", required_argument, 0, 's'}, - {"tcUrl", required_argument, 0, 't'}, - {"pageUrl", required_argument, 0, 'p'}, - {"conn", required_argument, 0, 'C'}, - {"complex", no_argument, 0, 'x'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - int opt = 0; - int option_index = 0; - while((opt = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1){ - switch(opt){ - case 'r': - rtmp_url = optarg; - break; - case 'o': - output_flv = optarg; - break; - case 's': - swfUrl = optarg; - break; - case 't': - tcUrl = optarg; - break; - case 'p': - pageUrl = optarg; - break; - case 'C': - if (!args) { - args = srs_amf0_create_object(); - } - char* p = (char*)optarg; - parse_amf0_object(p, args); - break; - case 'x': - complex_handshake = 1; - break; - case 'h': - show_help = 1; - break; - default: - printf("unsupported opt.\n"); - exit(-1); - } - } - - if (!rtmp_url || show_help) { - printf("Usage: %s -r url [-o output] [-s swfUrl] [-t tcUrl] [-p pageUrl] [-C conndata] [--complex] [-h]\n" - "Options:\n" - " --rtmp -r url\n" - " URL of the server and media content.\n" - " --flv -o output\n" - " Specify the output file name. If the name is − or is omitted, the stream is written to stdout.\n" - " --complex\n" - " Whether use complex handshake(srs-librtmp with ssl required).\n" - " --swfUrl -s url\n" - " URL of the SWF player for the media. By default no value will be sent.\n" - " --tcUrl -t url\n" - " URL of the target stream. Defaults to rtmp[e]://host[:port]/app/playpath.\n" - " --pageUrl -p url\n" - " URL of the web page in which the media was embedded. By default no value will be sent.\n" - " −−conn −C type:data\n" - " Append arbitrary AMF data to the Connect message. The type must be B for Boolean, N for number, S for string, O for object, or Z for null. For Booleans the data must be either 0 or 1 for FALSE or TRUE, respectively. Likewise for Objects the data must be 0 or 1 to end or begin an object, respectively. Data items in subobjects may be named, by prefixing the type with 'N' and specifying the name before the value, e.g. NB:myFlag:1. This option may be used multiple times to construct arbitrary AMF sequences. E.g.\n" - " −C B:1 −C S:authMe −C O:1 −C NN:code:1.23 −C NS:flag:ok −C O:0\n" - " -C O:1 -C NS:CONN:\" -C B:4Rg9vr0\" -C O:0\n" - " @remark, support a object args only.\n" - " --help -h\n" - " Print a summary of command options.\n" - "For example:\n" - " %s -r rtmp://127.0.0.1:1935/live/livestream -o output.flv\n" - " %s -h\n", - argv[0], argv[0], argv[0]); - exit(-1); - } - - srs_human_trace("rtmp url: %s", rtmp_url); - srs_human_trace("handshake: %s", (complex_handshake? "complex" : "simple")); - srs_human_trace("swfUrl: %s", swfUrl); - srs_human_trace("pageUrl: %s", pageUrl); - srs_human_trace("tcUrl: %s", tcUrl); - if (output_flv) { - srs_human_trace("flv output path: %s", output_flv); - } else { - srs_human_trace("output to console"); - } - - rtmp = srs_rtmp_create(rtmp_url); - if (output_flv) { - flv = srs_flv_open_write(output_flv); - } - - int ret = 0; - if ((ret = do_proxy(rtmp, flv)) != 0) { - srs_human_trace("Dump RTMP failed, ret=%d", ret); - } - - srs_rtmp_destroy(rtmp); - srs_flv_close(flv); - srs_human_trace("completed"); - - return 0; -} diff --git a/trunk/src/libs/srs_lib_bandwidth.cpp b/trunk/src/libs/srs_lib_bandwidth.cpp deleted file mode 100644 index 611c2c6b8..000000000 --- a/trunk/src/libs/srs_lib_bandwidth.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifndef _WIN32 -#include -#endif - -#include -using namespace std; - -#include -#include -#include -#include -#include -#include - -/** - * recv bandwidth helper. - */ -typedef bool (*_CheckPacketType)(SrsBandwidthPacket* pkt); -bool _bandwidth_is_start_play(SrsBandwidthPacket* pkt) -{ - return pkt->is_start_play(); -} -bool _bandwidth_is_stop_play(SrsBandwidthPacket* pkt) -{ - return pkt->is_stop_play(); -} -bool _bandwidth_is_start_publish(SrsBandwidthPacket* pkt) -{ - return pkt->is_start_publish(); -} -bool _bandwidth_is_stop_publish(SrsBandwidthPacket* pkt) -{ - return pkt->is_stop_publish(); -} -bool _bandwidth_is_finish(SrsBandwidthPacket* pkt) -{ - return pkt->is_finish(); -} -int _srs_expect_bandwidth_packet(SrsRtmpClient* rtmp, _CheckPacketType pfn) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - while (true) { - SrsCommonMessage* msg = NULL; - SrsBandwidthPacket* pkt = NULL; - if ((err = rtmp->expect_message(&msg, &pkt)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsBandwidthPacket, pkt); - srs_info("get final message success."); - - if (pfn(pkt)) { - return ret; - } - } - - return ret; -} -int _srs_expect_bandwidth_packet2(SrsRtmpClient* rtmp, _CheckPacketType pfn, SrsBandwidthPacket** ppkt) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - while (true) { - SrsCommonMessage* msg = NULL; - SrsBandwidthPacket* pkt = NULL; - if ((err = rtmp->expect_message(&msg, &pkt)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - SrsAutoFree(SrsCommonMessage, msg); - srs_info("get final message success."); - - if (pfn(pkt)) { - *ppkt = pkt; - return ret; - } - - srs_freep(pkt); - } - - return ret; -} - -SrsBandwidthClient::SrsBandwidthClient() -{ - _rtmp = NULL; -} - -SrsBandwidthClient::~SrsBandwidthClient() -{ -} - -int SrsBandwidthClient::initialize(SrsRtmpClient* rtmp) -{ - _rtmp = rtmp; - - return ERROR_SUCCESS; -} - -int SrsBandwidthClient::bandwidth_check( - int64_t* start_time, int64_t* end_time, - int* play_kbps, int* publish_kbps, - int* play_bytes, int* publish_bytes, - int* play_duration, int* publish_duration -) { - int ret = ERROR_SUCCESS; - - *start_time = srsu2ms(srs_update_system_time()); - - // play - if ((ret = play_start()) != ERROR_SUCCESS) { - return ret; - } - if ((ret = play_checking()) != ERROR_SUCCESS) { - return ret; - } - if ((ret = play_stop()) != ERROR_SUCCESS) { - return ret; - } - - // publish - int duration_ms = 0; - int actual_play_kbps = 0; - if ((ret = publish_start(duration_ms, actual_play_kbps)) != ERROR_SUCCESS) { - return ret; - } - if ((ret = publish_checking(duration_ms, actual_play_kbps)) != ERROR_SUCCESS) { - return ret; - } - if ((ret = publish_stop()) != ERROR_SUCCESS) { - return ret; - } - - SrsBandwidthPacket* pkt = NULL; - if ((ret = do_final(&pkt)) != ERROR_SUCCESS) { - return ret; - } - SrsAutoFree(SrsBandwidthPacket, pkt); - - // get data - if (true ) { - SrsAmf0Any* prop = NULL; - if ((prop = pkt->data->ensure_property_number("play_kbps")) != NULL) { - *play_kbps = (int)prop->to_number(); - } - if ((prop = pkt->data->ensure_property_number("publish_kbps")) != NULL) { - *publish_kbps = (int)prop->to_number(); - } - if ((prop = pkt->data->ensure_property_number("play_bytes")) != NULL) { - *play_bytes = (int)prop->to_number(); - } - if ((prop = pkt->data->ensure_property_number("publish_bytes")) != NULL) { - *publish_bytes = (int)prop->to_number(); - } - if ((prop = pkt->data->ensure_property_number("play_time")) != NULL) { - *play_duration = (int)prop->to_number(); - } - if ((prop = pkt->data->ensure_property_number("publish_time")) != NULL) { - *publish_duration = (int)prop->to_number(); - } - } - - *end_time = srsu2ms(srs_update_system_time()); - - return ret; -} - -int SrsBandwidthClient::play_start() -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - if ((ret = _srs_expect_bandwidth_packet(_rtmp, _bandwidth_is_start_play)) != ERROR_SUCCESS) { - return ret; - } - srs_info("BW check recv play begin request."); - - if (true) { - // send start play response to server. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_starting_play(); - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check start play message failed. ret=%d", ret); - return ret; - } - } - srs_info("BW check play begin."); - - return ret; -} - -int SrsBandwidthClient::play_checking() -{ - int ret = ERROR_SUCCESS; - return ret; -} - -int SrsBandwidthClient::play_stop() -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - if ((ret = _srs_expect_bandwidth_packet(_rtmp, _bandwidth_is_stop_play)) != ERROR_SUCCESS) { - return ret; - } - srs_info("BW check recv play stop request."); - - if (true) { - // send stop play response to server. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_stopped_play(); - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check stop play message failed. ret=%d", ret); - return ret; - } - } - srs_info("BW check play stop."); - - return ret; -} - -int SrsBandwidthClient::publish_start(int& duration_ms, int& play_kbps) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - if (true) { - SrsBandwidthPacket* pkt = NULL; - if ((ret = _srs_expect_bandwidth_packet2(_rtmp, _bandwidth_is_start_publish, &pkt)) != ERROR_SUCCESS) { - return ret; - } - SrsAutoFree(SrsBandwidthPacket, pkt); - - SrsAmf0Any* prop = NULL; - if ((prop = pkt->data->ensure_property_number("duration_ms")) != NULL) { - duration_ms = (int)prop->to_number(); - } - if ((prop = pkt->data->ensure_property_number("limit_kbps")) != NULL) { - play_kbps = (int)prop->to_number(); - } - } - srs_info("BW check recv publish begin request."); - - if (true) { - // send start publish response to server. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_starting_publish(); - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check start publish message failed. ret=%d", ret); - return ret; - } - } - srs_info("BW check publish begin."); - - return ret; -} - -int SrsBandwidthClient::publish_checking(int duration_ms, int play_kbps) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - if (duration_ms <= 0) { - ret = ERROR_RTMP_BWTC_DATA; - srs_error("server must specifies the duration, ret=%d", ret); - return ret; - } - - if (play_kbps <= 0) { - ret = ERROR_RTMP_BWTC_DATA; - srs_error("server must specifies the play kbp, ret=%d", ret); - return ret; - } - - int data_count = 1; - int64_t starttime = srsu2ms(srs_update_system_time()); - while (int64_t(srsu2ms(srs_get_system_time()) - starttime) < duration_ms) { - // TODO: FIXME: use shared ptr message. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_publishing(); - - // TODO: FIXME: magic number - for (int i = 0; i < data_count; ++i) { - std::stringstream seq; - seq << i; - std::string play_data = "SRS band check data from server's publishing......"; - pkt->data->set(seq.str(), SrsAmf0Any::str(play_data.c_str())); - } - data_count += 2; - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check publish messages failed. ret=%d", ret); - return ret; - } - - // use the play kbps to control the publish - int elaps = (int)(srsu2ms(srs_update_system_time()) - starttime); - if (elaps > 0) { - int current_kbps = (int)(_rtmp->get_send_bytes() * 8 / elaps); - while (current_kbps > play_kbps) { - srs_update_system_time(); - elaps = (int)(srsu2ms(srs_get_system_time()) - starttime); - current_kbps = (int)(_rtmp->get_send_bytes() * 8 / elaps); - usleep(100 * 1000); // TODO: FIXME: magic number. - } - } - } - srs_info("BW check send publish bytes over."); - - return ret; -} - -int SrsBandwidthClient::publish_stop() -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - if (true) { - // send start publish response to server. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_stop_publish(); - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check stop publish message failed. ret=%d", ret); - return ret; - } - } - srs_info("BW client stop publish request."); - - if ((ret = _srs_expect_bandwidth_packet(_rtmp, _bandwidth_is_stop_publish)) != ERROR_SUCCESS) { - return ret; - } - srs_info("BW check recv publish stop request."); - - if (true) { - // send start publish response to server. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_stopped_publish(); - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check stop publish message failed. ret=%d", ret); - return ret; - } - } - srs_info("BW check publish stop."); - - return ret; -} - -int SrsBandwidthClient::do_final(SrsBandwidthPacket** ppkt) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - if ((ret = _srs_expect_bandwidth_packet2(_rtmp, _bandwidth_is_finish, ppkt)) != ERROR_SUCCESS) { - return ret; - } - srs_info("BW check recv finish/report request."); - - if (true) { - // send final response to server. - SrsBandwidthPacket* pkt = SrsBandwidthPacket::create_final(); - - if ((err = _rtmp->send_and_free_packet(pkt, 0)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_error("send bandwidth check final message failed. ret=%d", ret); - return ret; - } - } - srs_info("BW check final."); - - return ret; -} - diff --git a/trunk/src/libs/srs_lib_bandwidth.hpp b/trunk/src/libs/srs_lib_bandwidth.hpp deleted file mode 100644 index 2bcf57956..000000000 --- a/trunk/src/libs/srs_lib_bandwidth.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SRS_LIB_BANDWIDTH_HPP -#define SRS_LIB_BANDWIDTH_HPP - -#include - -class SrsRtmpClient; -class SrsBandwidthPacket; - -/** - * bandwith client library for srs-librtmp. - */ -class SrsBandwidthClient -{ -private: - SrsRtmpClient* _rtmp; -public: - SrsBandwidthClient(); - virtual ~SrsBandwidthClient(); -public: - /** - * initialize the bandwidth check client. - */ - virtual int initialize(SrsRtmpClient* rtmp); - /** - * do bandwidth check. - * - * bandwidth info: - * @param start_time, output the start time, in ms. - * @param end_time, output the end time, in ms. - * @param play_kbps, output the play/download kbps. - * @param publish_kbps, output the publish/upload kbps. - * @param play_bytes, output the play/download bytes. - * @param publish_bytes, output the publish/upload bytes. - * @param play_duration, output the play/download test duration, in ms. - * @param publish_duration, output the publish/upload test duration, in ms. - */ - virtual int bandwidth_check( - int64_t* start_time, int64_t* end_time, - int* play_kbps, int* publish_kbps, - int* play_bytes, int* publish_bytes, - int* play_duration, int* publish_duration); -private: - /** - * play check/test, downloading bandwidth kbps. - */ - virtual int play_start(); - virtual int play_checking(); - virtual int play_stop(); - /** - * publish check/test, publishing bandwidth kbps. - */ - virtual int publish_start(int& duration_ms, int& play_kbps); - virtual int publish_checking(int duration_ms, int play_kbps); - virtual int publish_stop(); - /** - * report and final packet - */ - virtual int do_final(SrsBandwidthPacket** ppkt); -}; - -#endif - diff --git a/trunk/src/libs/srs_lib_simple_socket.cpp b/trunk/src/libs/srs_lib_simple_socket.cpp deleted file mode 100644 index 59adf2278..000000000 --- a/trunk/src/libs/srs_lib_simple_socket.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include - -#include - -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifndef _WIN32 -#define SOCKET_ETIME EWOULDBLOCK -#define SOCKET_ECONNRESET ECONNRESET - -#define SOCKET_ERRNO() errno -#define SOCKET_RESET(fd) fd = -1; (void)0 -#define SOCKET_CLOSE(fd) \ - if (fd > 0) {\ - ::close(fd); \ - fd = -1; \ - } \ - (void)0 -#define SOCKET_VALID(x) (x > 0) -#define SOCKET_SETUP() (void)0 -#define SOCKET_CLEANUP() (void)0 -#else -#define SOCKET_ETIME WSAETIMEDOUT -#define SOCKET_ECONNRESET WSAECONNRESET -#define SOCKET_ERRNO() WSAGetLastError() -#define SOCKET_RESET(x) x=INVALID_SOCKET -#define SOCKET_CLOSE(x) if(x!=INVALID_SOCKET){::closesocket(x);x=INVALID_SOCKET;} -#define SOCKET_VALID(x) (x!=INVALID_SOCKET) -#define SOCKET_BUFF(x) ((char*)x) -#define SOCKET_SETUP() socket_setup() -#define SOCKET_CLEANUP() socket_cleanup() -#endif - -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifndef _WIN32 -#include -#include -#include -#include -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include - -// when io not hijacked, use simple socket, the block sync stream. -#ifndef SRS_HIJACK_IO -struct SrsBlockSyncSocket -{ - int family; - SOCKET fd; - SOCKET fdv4; - SOCKET fdv6; - // Bytes transmit. - int64_t rbytes; - int64_t sbytes; - // The send/recv timeout in ms. - int64_t rtm; - int64_t stm; - - SrsBlockSyncSocket() { - family = AF_UNSPEC; - stm = rtm = SRS_UTIME_NO_TIMEOUT; - rbytes = sbytes = 0; - - SOCKET_RESET(fd); - SOCKET_RESET(fdv4); - SOCKET_RESET(fdv6); - SOCKET_SETUP(); - } - - virtual ~SrsBlockSyncSocket() { - if (SOCKET_VALID(fd)) { - SOCKET_CLOSE(fd); - } - if (SOCKET_VALID(fdv4)) { - SOCKET_CLOSE(fdv4); - } - if (SOCKET_VALID(fdv6)) { - SOCKET_CLOSE(fdv6); - } - SOCKET_CLEANUP(); - } -}; -srs_hijack_io_t srs_hijack_io_create() -{ - SrsBlockSyncSocket* skt = new SrsBlockSyncSocket(); - return skt; -} -void srs_hijack_io_destroy(srs_hijack_io_t ctx) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - srs_freep(skt); -} -int srs_hijack_io_create_socket(srs_hijack_io_t ctx, srs_rtmp_t owner) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - skt->family = AF_UNSPEC; - skt->fdv4 = ::socket(AF_INET, SOCK_STREAM, 0); - skt->fdv6 = ::socket(AF_INET6, SOCK_STREAM, 0); - if (!SOCKET_VALID(skt->fdv4) && !SOCKET_VALID(skt->fdv4)) { - return ERROR_SOCKET_CREATE; - } - - // No TCP cache. - int v = 1; - setsockopt(skt->fdv4, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); - setsockopt(skt->fdv6, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); - - return ERROR_SUCCESS; -} -int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - char sport[8]; - snprintf(sport, sizeof(sport), "%d", port); - - addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - addrinfo* r = NULL; - SrsAutoFree(addrinfo, r); - if(getaddrinfo(server_ip, sport, (const addrinfo*)&hints, &r)) { - return ERROR_SOCKET_CONNECT; - } - - skt->family = r->ai_family; - if (r->ai_family == AF_INET6) { - skt->fd = skt->fdv6; - SOCKET_RESET(skt->fdv6); - } else { - skt->fd = skt->fdv4; - SOCKET_RESET(skt->fdv4); - } - - if(::connect(skt->fd, r->ai_addr, r->ai_addrlen) < 0){ - return ERROR_SOCKET_CONNECT; - } - - return ERROR_SUCCESS; -} -int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - int ret = ERROR_SUCCESS; - - ssize_t nb_read = ::recv(skt->fd, (char*)buf, size, 0); - - if (nread) { - *nread = nb_read; - } - - // On success a non-negative integer indicating the number of bytes actually read is returned - // (a value of 0 means the network connection is closed or end of file is reached). - if (nb_read <= 0) { - if (nb_read < 0 && SOCKET_ERRNO() == SOCKET_ETIME) { - return ERROR_SOCKET_TIMEOUT; - } - - if (nb_read == 0) { - errno = SOCKET_ECONNRESET; - } - - return ERROR_SOCKET_READ; - } - - skt->rbytes += nb_read; - - return ret; -} -int srs_hijack_io_set_recv_timeout(srs_hijack_io_t ctx, int64_t tm) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - -#ifdef _WIN32 - DWORD tv = (DWORD)(tm); - - // To convert tv to const char* to make VS2015 happy. - if (setsockopt(skt->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { - return SOCKET_ERRNO(); - } -#else - // The default for this option is zero, - // which indicates that a receive operation shall not time out. - int32_t sec = 0; - int32_t usec = 0; - - if (tm != SRS_UTIME_NO_TIMEOUT) { - sec = (int32_t)(tm / 1000); - usec = (int32_t)((tm % 1000)*1000); - } - - struct timeval tv = { sec , usec }; - if (setsockopt(skt->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { - return SOCKET_ERRNO(); - } -#endif - - skt->rtm = tm; - - return ERROR_SUCCESS; -} -int64_t srs_hijack_io_get_recv_timeout(srs_hijack_io_t ctx) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - return skt->rtm; -} -int64_t srs_hijack_io_get_recv_bytes(srs_hijack_io_t ctx) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - return skt->rbytes; -} -int srs_hijack_io_set_send_timeout(srs_hijack_io_t ctx, int64_t tm) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - -#ifdef _WIN32 - DWORD tv = (DWORD)(tm); - - // To convert tv to const char* to make VS2015 happy. - if (setsockopt(skt->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { - return SOCKET_ERRNO(); - } -#else - // The default for this option is zero, - // which indicates that a receive operation shall not time out. - int32_t sec = 0; - int32_t usec = 0; - - if (tm != SRS_UTIME_NO_TIMEOUT) { - sec = (int32_t)(tm / 1000); - usec = (int32_t)((tm % 1000)*1000); - } - - struct timeval tv = { sec , usec }; - if (setsockopt(skt->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { - return SOCKET_ERRNO(); - } -#endif - - skt->stm = tm; - - return ERROR_SUCCESS; -} -int64_t srs_hijack_io_get_send_timeout(srs_hijack_io_t ctx) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - return skt->stm; -} -int64_t srs_hijack_io_get_send_bytes(srs_hijack_io_t ctx) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - return skt->sbytes; -} -int srs_hijack_io_writev(srs_hijack_io_t ctx, const iovec *iov, int iov_size, ssize_t* nwrite) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - int ret = ERROR_SUCCESS; - - ssize_t nb_write = ::writev(skt->fd, iov, iov_size); - - if (nwrite) { - *nwrite = nb_write; - } - - // On success, the readv() function returns the number of bytes read; - // the writev() function returns the number of bytes written. On error, -1 is - // returned, and errno is set appropriately. - if (nb_write <= 0) { - // @see https://github.com/ossrs/srs/issues/200 - if (nb_write < 0 && SOCKET_ERRNO() == SOCKET_ETIME) { - return ERROR_SOCKET_TIMEOUT; - } - - return ERROR_SOCKET_WRITE; - } - - skt->sbytes += nb_write; - - return ret; -} -int srs_hijack_io_is_never_timeout(srs_hijack_io_t ctx, int64_t tm) -{ - return tm == SRS_UTIME_NO_TIMEOUT; -} -int srs_hijack_io_read_fully(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - int ret = ERROR_SUCCESS; - - size_t left = size; - ssize_t nb_read = 0; - - while (left > 0) { - char* this_buf = (char*)buf + nb_read; - ssize_t this_nread; - - if ((ret = srs_hijack_io_read(ctx, this_buf, left, &this_nread)) != ERROR_SUCCESS) { - return ret; - } - - nb_read += this_nread; - left -= (size_t)this_nread; - } - - if (nread) { - *nread = nb_read; - } - skt->rbytes += nb_read; - - return ret; -} -int srs_hijack_io_write(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nwrite) -{ - SrsBlockSyncSocket* skt = (SrsBlockSyncSocket*)ctx; - - int ret = ERROR_SUCCESS; - - ssize_t nb_write = ::send(skt->fd, (char*)buf, size, 0); - - if (nwrite) { - *nwrite = nb_write; - } - - if (nb_write <= 0) { - // @see https://github.com/ossrs/srs/issues/200 - if (nb_write < 0 && SOCKET_ERRNO() == SOCKET_ETIME) { - return ERROR_SOCKET_TIMEOUT; - } - - return ERROR_SOCKET_WRITE; - } - - skt->sbytes += nb_write; - - return ret; -} -#endif - -SimpleSocketStream::SimpleSocketStream() -{ - io = srs_hijack_io_create(); -} - -SimpleSocketStream::~SimpleSocketStream() -{ - if (io) { - srs_hijack_io_destroy(io); - io = NULL; - } -} - -srs_hijack_io_t SimpleSocketStream::hijack_io() -{ - return io; -} - -int SimpleSocketStream::create_socket(srs_rtmp_t owner) -{ - srs_assert(io); - return srs_hijack_io_create_socket(io, owner); -} - -int SimpleSocketStream::connect(const char* server_ip, int port) -{ - srs_assert(io); - return srs_hijack_io_connect(io, server_ip, port); -} - -// Interface ISrsReader -srs_error_t SimpleSocketStream::read(void* buf, size_t size, ssize_t* nread) -{ - srs_assert(io); - int ret = srs_hijack_io_read(io, buf, size, nread); - if (ret != ERROR_SUCCESS) { - return srs_error_new(ret, "read"); - } - return srs_success; -} - -// Interface ISrsProtocolReader -void SimpleSocketStream::set_recv_timeout(srs_utime_t tm) -{ - srs_assert(io); - srs_hijack_io_set_recv_timeout(io, srsu2ms(tm)); -} - -srs_utime_t SimpleSocketStream::get_recv_timeout() -{ - srs_assert(io); - return srs_hijack_io_get_recv_timeout(io) * SRS_UTIME_MILLISECONDS; -} - -int64_t SimpleSocketStream::get_recv_bytes() -{ - srs_assert(io); - return srs_hijack_io_get_recv_bytes(io); -} - -// Interface ISrsProtocolWriter -void SimpleSocketStream::set_send_timeout(srs_utime_t tm) -{ - srs_assert(io); - srs_hijack_io_set_send_timeout(io, srsu2ms(tm)); -} - -srs_utime_t SimpleSocketStream::get_send_timeout() -{ - srs_assert(io); - return srs_hijack_io_get_send_timeout(io) * SRS_UTIME_MILLISECONDS; -} - -int64_t SimpleSocketStream::get_send_bytes() -{ - srs_assert(io); - return srs_hijack_io_get_send_bytes(io); -} - -srs_error_t SimpleSocketStream::writev(const iovec *iov, int iov_size, ssize_t* nwrite) -{ - srs_assert(io); - int ret = srs_hijack_io_writev(io, iov, iov_size, nwrite); - if (ret != ERROR_SUCCESS) { - return srs_error_new(ret, "read"); - } - return srs_success; -} - -srs_error_t SimpleSocketStream::read_fully(void* buf, size_t size, ssize_t* nread) -{ - srs_assert(io); - int ret = srs_hijack_io_read_fully(io, buf, size, nread); - if (ret != ERROR_SUCCESS) { - return srs_error_new(ret, "read"); - } - return srs_success; -} - -srs_error_t SimpleSocketStream::write(void* buf, size_t size, ssize_t* nwrite) -{ - srs_assert(io); - int ret = srs_hijack_io_write(io, buf, size, nwrite); - if (ret != ERROR_SUCCESS) { - return srs_error_new(ret, "read"); - } - return srs_success; -} - - diff --git a/trunk/src/libs/srs_lib_simple_socket.hpp b/trunk/src/libs/srs_lib_simple_socket.hpp deleted file mode 100644 index 021aeeea5..000000000 --- a/trunk/src/libs/srs_lib_simple_socket.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SRS_LIB_SIMPLE_SOCKET_HPP -#define SRS_LIB_SIMPLE_SOCKET_HPP - -#include - -#include -#include - -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifndef _WIN32 -#define SOCKET int -#endif - -/** - * simple socket stream, - * use tcp socket, sync block mode, for client like srs-librtmp. - */ -class SimpleSocketStream : public ISrsProtocolReadWriter -{ -private: - srs_hijack_io_t io; -public: - SimpleSocketStream(); - virtual ~SimpleSocketStream(); -public: - virtual srs_hijack_io_t hijack_io(); - virtual int create_socket(srs_rtmp_t owner); - virtual int connect(const char* server, int port); -// Interface ISrsReader -public: - virtual srs_error_t read(void* buf, size_t size, ssize_t* nread); -// Interface ISrsProtocolReader -public: - virtual void set_recv_timeout(srs_utime_t tm); - virtual srs_utime_t get_recv_timeout(); - virtual int64_t get_recv_bytes(); -// Interface ISrsProtocolWriter -public: - virtual void set_send_timeout(srs_utime_t tm); - virtual srs_utime_t get_send_timeout(); - virtual int64_t get_send_bytes(); - virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t* nwrite); -// Interface ISrsProtocolReadWriter -public: - virtual srs_error_t read_fully(void* buf, size_t size, ssize_t* nread); - virtual srs_error_t write(void* buf, size_t size, ssize_t* nwrite); -}; - -#endif - diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp deleted file mode 100644 index a2f9728e0..000000000 --- a/trunk/src/libs/srs_librtmp.cpp +++ /dev/null @@ -1,2924 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - -#include -#include - -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifndef _WIN32 -#include -#include -#endif - -#include -#include -using namespace std; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// kernel module. -ISrsLog* _srs_log = new ISrsLog(); -ISrsThreadContext* _srs_context = new ISrsThreadContext(); - -// The default socket timeout in ms. -#define SRS_SOCKET_DEFAULT_TMMS (30 * 1000) - -/** - * export runtime context. - */ -struct Context -{ - // The original RTMP url. - std::string url; - - // Parse from url. - std::string tcUrl; - std::string host; - std::string vhost; - std::string app; - std::string stream; - std::string param; - - // Parse ip:port from host. - std::string ip; - int port; - - // The URL schema, about vhost/app/stream?param - srs_url_schema schema; - // The server information, response by connect app. - SrsServerInfo si; - - // The extra request object for connect to server, NULL to ignore. - SrsRequest* req; - - // the message received cache, - // for example, when got aggregate message, - // the context will parse to videos/audios, - // and return one by one. - std::vector msgs; - - SrsRtmpClient* rtmp; - SimpleSocketStream* skt; - int stream_id; - - // the remux raw codec. - SrsRawH264Stream avc_raw; - SrsRawAacStream aac_raw; - - // about SPS, @see: 7.3.2.1.1, ISO_IEC_14496-10-AVC-2012.pdf, page 62 - std::string h264_sps; - std::string h264_pps; - // whether the sps and pps sent, - // @see https://github.com/ossrs/srs/issues/203 - bool h264_sps_pps_sent; - // only send the ssp and pps when both changed. - // @see https://github.com/ossrs/srs/issues/204 - bool h264_sps_changed; - bool h264_pps_changed; - // the aac sequence header. - std::string aac_specific_config; - - // user set timeout, in ms. - int64_t stimeout; - int64_t rtimeout; - - // The RTMP handler level buffer, can used to format packet. - char buffer[1024]; - - Context() : port(0) { - rtmp = NULL; - skt = NULL; - req = NULL; - stream_id = 0; - h264_sps_pps_sent = false; - h264_sps_changed = false; - h264_pps_changed = false; - rtimeout = stimeout = SRS_UTIME_NO_TIMEOUT; - schema = srs_url_schema_normal; - } - virtual ~Context() { - srs_freep(req); - srs_freep(rtmp); - srs_freep(skt); - - std::vector::iterator it; - for (it = msgs.begin(); it != msgs.end(); ++it) { - SrsCommonMessage* msg = *it; - srs_freep(msg); - } - msgs.clear(); - } -}; - -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifdef _WIN32 -int gettimeofday(struct timeval* tv, struct timezone* tz) -{ - time_t clock; - struct tm tm; - SYSTEMTIME win_time; - - GetLocalTime(&win_time); - - tm.tm_year = win_time.wYear - 1900; - tm.tm_mon = win_time.wMonth - 1; - tm.tm_mday = win_time.wDay; - tm.tm_hour = win_time.wHour; - tm.tm_min = win_time.wMinute; - tm.tm_sec = win_time.wSecond; - tm.tm_isdst = -1; - - clock = mktime(&tm); - - tv->tv_sec = (long)clock; - tv->tv_usec = win_time.wMilliseconds * 1000; - - return 0; -} - -int socket_setup() -{ - WORD wVersionRequested; - WSADATA wsaData; - int err; - - /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ - wVersionRequested = MAKEWORD(2, 2); - - err = WSAStartup(wVersionRequested, &wsaData); - if (err != 0) { - /* Tell the user that we could not find a usable */ - /* Winsock DLL. */ - //printf("WSAStartup failed with error: %d\n", err); - return -1; - } - return 0; -} - -int socket_cleanup() -{ - WSACleanup(); - return 0; -} - -pid_t getpid(void) -{ - return (pid_t)GetCurrentProcessId(); -} - -int usleep(useconds_t usec) -{ - Sleep((DWORD)(usec / 1000)); - return 0; -} - -ssize_t writev(int fd, const struct iovec *iov, int iovcnt) -{ - ssize_t nwrite = 0; - for (int i = 0; i < iovcnt; i++) { - const struct iovec* current = iov + i; - - int nsent = ::send(fd, (char*)current->iov_base, current->iov_len, 0); - if (nsent < 0) { - return nsent; - } - - nwrite += nsent; - if (nsent == 0) { - return nwrite; - } - } - return nwrite; -} - -//////////////////////// strlcpy.c (modified) ////////////////////////// - -/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ - -/*- - * Copyright (c) 1998 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -//#include // **** -//#include // **** -// __FBSDID("$FreeBSD: stable/9/sys/libkern/strlcpy.c 243811 2012-12-03 18:08:44Z delphij $"); // **** - -// #include // **** -// #include // **** - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ - -//#define __restrict // **** - -std::size_t strlcpy(char * __restrict dst, const char * __restrict src, size_t siz) -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0) { - while (--n != 0) { - if ((*d++ = *s++) == '\0') - break; - } - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} - -// http://www.cplusplus.com/forum/general/141779///////////////////////// inet_ntop.c (modified) ////////////////////////// -/* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1996-1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -// #if defined(LIBC_SCCS) && !defined(lint) // **** -//static const char rcsid[] = "$Id: inet_ntop.c,v 1.3.18.2 2005/11/03 23:02:22 marka Exp $"; -// #endif /* LIBC_SCCS and not lint */ // **** -// #include // **** -// __FBSDID("$FreeBSD: stable/9/sys/libkern/inet_ntop.c 213103 2010-09-24 15:01:45Z attilio $"); // **** - -//#define _WIN32_WINNT _WIN32_WINNT_WIN8 // **** -//#include // **** -#pragma comment(lib, "Ws2_32.lib") // **** -//#include // **** - -// #include // **** -// #include // **** -// #include // **** - -// #include // **** - -/*% - * WARNING: Don't even consider trying to compile this on a system where - * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. - */ - -static char *inet_ntop4(const u_char *src, char *dst, socklen_t size); -static char *inet_ntop6(const u_char *src, char *dst, socklen_t size); - -/* char * - * inet_ntop(af, src, dst, size) - * convert a network format address to presentation format. - * return: - * pointer to presentation format address (`dst'), or NULL (see errno). - * author: - * Paul Vixie, 1996. - */ -const char* inet_ntop(int af, const void *src, char *dst, socklen_t size) -{ - switch (af) { - case AF_INET: - return (inet_ntop4((unsigned char*)src, (char*)dst, size)); - case AF_INET6: - return (char*)(inet_ntop6((unsigned char*)src, (char*)dst, size)); - default: - return (NULL); - } - /* NOTREACHED */ -} - -/* const char * - * inet_ntop4(src, dst, size) - * format an IPv4 address - * return: - * `dst' (as a const) - * notes: - * (1) uses no statics - * (2) takes a u_char* not an in_addr as input - * author: - * Paul Vixie, 1996. - */ -static char * inet_ntop4(const u_char *src, char *dst, socklen_t size) -{ - static const char fmt[128] = "%u.%u.%u.%u"; - char tmp[sizeof "255.255.255.255"]; - int l; - - l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); // **** - if (l <= 0 || (socklen_t) l >= size) { - return (NULL); - } - strlcpy(dst, tmp, size); - return (dst); -} - -/* const char * - * inet_ntop6(src, dst, size) - * convert IPv6 binary address into presentation (printable) format - * author: - * Paul Vixie, 1996. - */ -static char * inet_ntop6(const u_char *src, char *dst, socklen_t size) -{ - /* - * Note that int32_t and int16_t need only be "at least" large enough - * to contain a value of the specified size. On some systems, like - * Crays, there is no such thing as an integer variable with 16 bits. - * Keep this in mind if you think this function should have been coded - * to use pointer overlays. All the world's not a VAX. - */ - char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; - struct { int base, len; } best, cur; -#define NS_IN6ADDRSZ 16 -#define NS_INT16SZ 2 - u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; - int i; - - /* - * Preprocess: - * Copy the input (bytewise) array into a wordwise array. - * Find the longest run of 0x00's in src[] for :: shorthanding. - */ - memset(words, '\0', sizeof words); - for (i = 0; i < NS_IN6ADDRSZ; i++) - words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); - best.base = -1; - best.len = 0; - cur.base = -1; - cur.len = 0; - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { - if (words[i] == 0) { - if (cur.base == -1) - cur.base = i, cur.len = 1; - else - cur.len++; - } else { - if (cur.base != -1) { - if (best.base == -1 || cur.len > best.len) - best = cur; - cur.base = -1; - } - } - } - if (cur.base != -1) { - if (best.base == -1 || cur.len > best.len) - best = cur; - } - if (best.base != -1 && best.len < 2) - best.base = -1; - - /* - * Format the result. - */ - tp = tmp; - for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { - /* Are we inside the best run of 0x00's? */ - if (best.base != -1 && i >= best.base && - i < (best.base + best.len)) { - if (i == best.base) - *tp++ = ':'; - continue; - } - /* Are we following an initial run of 0x00s or any real hex? */ - if (i != 0) - *tp++ = ':'; - /* Is this address an encapsulated IPv4? */ - if (i == 6 && best.base == 0 && (best.len == 6 || - (best.len == 7 && words[7] != 0x0001) || - (best.len == 5 && words[5] == 0xffff))) { - if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) - return (NULL); - tp += strlen(tp); - break; - } - tp += std::sprintf(tp, "%x", words[i]); // **** - } - /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == - (NS_IN6ADDRSZ / NS_INT16SZ)) - *tp++ = ':'; - *tp++ = '\0'; - - /* - * Check for overflow, copy, and we're done. - */ - if ((socklen_t)(tp - tmp) > size) { - return (NULL); - } - strcpy(dst, tmp); - return (dst); -} -#endif - -int srs_librtmp_context_parse_uri(Context* context) -{ - int ret = ERROR_SUCCESS; - - std::string schema; - - srs_parse_rtmp_url(context->url, context->tcUrl, context->stream); - - // when connect, we only need to parse the tcUrl - srs_discovery_tc_url(context->tcUrl, - schema, context->host, context->vhost, context->app, context->stream, context->port, - context->param); - - return ret; -} - -int srs_librtmp_context_resolve_host(Context* context) -{ - int ret = ERROR_SUCCESS; - - // connect to server:port - int family = AF_UNSPEC; - context->ip = srs_dns_resolve(context->host, family); - if (context->ip.empty()) { - return ERROR_SYSTEM_DNS_RESOLVE; - } - - return ret; -} - -int srs_librtmp_context_connect(Context* context) -{ - int ret = ERROR_SUCCESS; - - srs_assert(context->skt); - - std::string ip = context->ip; - if ((ret = context->skt->connect(ip.c_str(), context->port)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - -#ifdef __cplusplus -extern "C"{ -#endif - -int srs_version_major() -{ - return VERSION_MAJOR; -} - -int srs_version_minor() -{ - return VERSION_MINOR; -} - -int srs_version_revision() -{ - return VERSION_REVISION; -} - -srs_rtmp_t srs_rtmp_create(const char* url) -{ - int ret = ERROR_SUCCESS; - - Context* context = new Context(); - context->url = url; - - // create socket - srs_freep(context->skt); - context->skt = new SimpleSocketStream(); - - if ((ret = context->skt->create_socket(context)) != ERROR_SUCCESS) { - srs_human_error("Create socket failed, ret=%d", ret); - - // free the context and return NULL - srs_freep(context); - return NULL; - } - - return context; -} - -int srs_rtmp_set_timeout(srs_rtmp_t rtmp, int recv_timeout_ms, int send_timeout_ms) -{ - int ret = ERROR_SUCCESS; - - if (!rtmp) { - return ret; - } - - Context* context = (Context*)rtmp; - - context->stimeout = send_timeout_ms; - context->rtimeout = recv_timeout_ms; - - context->skt->set_recv_timeout(context->rtimeout * SRS_UTIME_MILLISECONDS); - context->skt->set_send_timeout(context->stimeout * SRS_UTIME_MILLISECONDS); - - return ret; -} - -void srs_rtmp_destroy(srs_rtmp_t rtmp) -{ - if (!rtmp) { - return; - } - - Context* context = (Context*)rtmp; - - srs_freep(context); -} - -int srs_rtmp_handshake(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - - if ((ret = srs_rtmp_dns_resolve(rtmp)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = srs_rtmp_connect_server(rtmp)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = srs_rtmp_do_simple_handshake(rtmp)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - -int srs_rtmp_dns_resolve(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - // parse uri - if ((ret = srs_librtmp_context_parse_uri(context)) != ERROR_SUCCESS) { - return ret; - } - // resolve host - if ((ret = srs_librtmp_context_resolve_host(context)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - -int srs_rtmp_connect_server(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - // set timeout if user not set. - if (context->stimeout == SRS_UTIME_NO_TIMEOUT) { - context->stimeout = SRS_SOCKET_DEFAULT_TMMS; - context->skt->set_send_timeout(context->stimeout * SRS_UTIME_MILLISECONDS); - } - if (context->rtimeout == SRS_UTIME_NO_TIMEOUT) { - context->rtimeout = SRS_SOCKET_DEFAULT_TMMS; - context->skt->set_recv_timeout(context->rtimeout * SRS_UTIME_MILLISECONDS); - } - - if ((ret = srs_librtmp_context_connect(context)) != ERROR_SUCCESS) { - return ret; - } - - return ret; -} - -int srs_rtmp_do_complex_handshake(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - srs_assert(context->skt != NULL); - - // simple handshake - srs_freep(context->rtmp); - context->rtmp = new SrsRtmpClient(context->skt); - - if ((err = context->rtmp->complex_handshake()) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_rtmp_do_simple_handshake(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - srs_assert(context->skt != NULL); - - // simple handshake - srs_freep(context->rtmp); - context->rtmp = new SrsRtmpClient(context->skt); - - if ((err = context->rtmp->simple_handshake()) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_rtmp_set_connect_args(srs_rtmp_t rtmp, const char* tcUrl, const char* swfUrl, const char* pageUrl, srs_amf0_t args) -{ - int ret = ERROR_SUCCESS; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - srs_freep(context->req); - context->req = new SrsRequest(); - - if (args) { - context->req->args = (SrsAmf0Object*)args; - } - if (tcUrl) { - context->req->tcUrl = tcUrl; - } - if (swfUrl) { - context->req->swfUrl = swfUrl; - } - if (pageUrl) { - context->req->pageUrl = pageUrl; - } - - return ret; -} - -int srs_rtmp_set_schema(srs_rtmp_t rtmp, enum srs_url_schema schema) -{ - int ret = ERROR_SUCCESS; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - context->schema = schema; - - return ret; -} - -int srs_rtmp_connect_app(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - string tcUrl; - switch(context->schema) { - // For SRS3, only use one format url. - case srs_url_schema_normal: - case srs_url_schema_via: - case srs_url_schema_vis: - case srs_url_schema_vis2: - tcUrl = srs_generate_tc_url(context->ip, context->vhost, context->app, context->port); - default: - break; - } - - Context* c = context; - if ((err = context->rtmp->connect_app(c->app, tcUrl, c->req, true, &c->si)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_rtmp_get_server_id(srs_rtmp_t rtmp, char** ip, int* pid, int* cid) -{ - int ret = ERROR_SUCCESS; - - Context* context = (Context*)rtmp; - *pid = context->si.pid; - *cid = context->si.cid; - *ip = context->si.ip.empty()? NULL:(char*)context->si.ip.c_str(); - - return ret; -} - -int srs_rtmp_get_server_sig(srs_rtmp_t rtmp, char** sig) -{ - int ret = ERROR_SUCCESS; - - Context* context = (Context*)rtmp; - *sig = context->si.sig.empty()? NULL:(char*)context->si.sig.c_str(); - - return ret; -} - -int srs_rtmp_get_server_version(srs_rtmp_t rtmp, int* major, int* minor, int* revision, int* build) -{ - int ret = ERROR_SUCCESS; - - Context* context = (Context*)rtmp; - *major = context->si.major; - *minor = context->si.minor; - *revision = context->si.revision; - *build = context->si.build; - - return ret; -} - -int srs_rtmp_play_stream(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - if ((err = context->rtmp->create_stream(context->stream_id)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // Pass params in stream, @see https://github.com/ossrs/srs/issues/1031#issuecomment-409745733 - string stream = srs_generate_stream_with_query(context->host, context->vhost, context->stream, context->param); - - if ((err = context->rtmp->play(stream, context->stream_id, SRS_CONSTS_RTMP_PROTOCOL_CHUNK_SIZE)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_rtmp_publish_stream(srs_rtmp_t rtmp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - // Pass params in stream, @see https://github.com/ossrs/srs/issues/1031#issuecomment-409745733 - string stream = srs_generate_stream_with_query(context->host, context->vhost, context->stream, context->param); - - if ((err = context->rtmp->fmle_publish(stream, context->stream_id)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_rtmp_bandwidth_check(srs_rtmp_t rtmp, - int64_t* start_time, int64_t* end_time, - int* play_kbps, int* publish_kbps, - int* play_bytes, int* publish_bytes, - int* play_duration, int* publish_duration -) { - *start_time = 0; - *end_time = 0; - *play_kbps = 0; - *publish_kbps = 0; - *play_bytes = 0; - *publish_bytes = 0; - *play_duration = 0; - *publish_duration = 0; - - int ret = ERROR_SUCCESS; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - SrsBandwidthClient client; - - if ((ret = client.initialize(context->rtmp)) != ERROR_SUCCESS) { - return ret; - } - - if ((ret = client.bandwidth_check( - start_time, end_time, play_kbps, publish_kbps, - play_bytes, publish_bytes, play_duration, publish_duration)) != ERROR_SUCCESS - ) { - return ret; - } - - return ret; -} - - -int srs_rtmp_on_aggregate(Context* context, SrsCommonMessage* msg) -{ - int ret = ERROR_SUCCESS; - - SrsBuffer* stream = new SrsBuffer(msg->payload, msg->size); - SrsAutoFree(SrsBuffer, stream); - - // the aggregate message always use abs time. - int delta = -1; - - while (!stream->empty()) { - if (!stream->require(1)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message type. ret=%d", ret); - return ret; - } - int8_t type = stream->read_1bytes(); - - if (!stream->require(3)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message size. ret=%d", ret); - return ret; - } - int32_t data_size = stream->read_3bytes(); - - if (data_size < 0) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message size(negative). ret=%d", ret); - return ret; - } - - if (!stream->require(3)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message time. ret=%d", ret); - return ret; - } - int32_t timestamp = stream->read_3bytes(); - - if (!stream->require(1)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message time(high). ret=%d", ret); - return ret; - } - int32_t time_h = stream->read_1bytes(); - - timestamp |= time_h<<24; - timestamp &= 0x7FFFFFFF; - - // adjust abs timestamp in aggregate msg. - if (delta < 0) { - delta = (int)msg->header.timestamp - (int)timestamp; - } - timestamp += delta; - - if (!stream->require(3)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message stream_id. ret=%d", ret); - return ret; - } - int32_t stream_id = stream->read_3bytes(); - - if (data_size > 0 && !stream->require(data_size)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message data. ret=%d", ret); - return ret; - } - - // to common message. - SrsCommonMessage o; - - o.header.message_type = type; - o.header.payload_length = data_size; - o.header.timestamp_delta = timestamp; - o.header.timestamp = timestamp; - o.header.stream_id = stream_id; - o.header.perfer_cid = msg->header.perfer_cid; - - if (data_size > 0) { - o.size = data_size; - o.payload = new char[o.size]; - stream->read_bytes(o.payload, o.size); - } - - if (!stream->require(4)) { - ret = ERROR_RTMP_AGGREGATE; - srs_error("invalid aggregate message previous tag size. ret=%d", ret); - return ret; - } - stream->read_4bytes(); - - // process parsed message - SrsCommonMessage* parsed_msg = new SrsCommonMessage(); - parsed_msg->header = o.header; - parsed_msg->payload = o.payload; - parsed_msg->size = o.size; - o.payload = NULL; - context->msgs.push_back(parsed_msg); - } - - return ret; -} - -int srs_rtmp_go_packet(Context* context, SrsCommonMessage* msg, - char* type, uint32_t* timestamp, char** data, int* size, - bool* got_msg -) { - int ret = ERROR_SUCCESS; - - // generally we got a message. - *got_msg = true; - - if (msg->header.is_audio()) { - *type = SRS_RTMP_TYPE_AUDIO; - *timestamp = (uint32_t)msg->header.timestamp; - *data = (char*)msg->payload; - *size = (int)msg->size; - // detach bytes from packet. - msg->payload = NULL; - } else if (msg->header.is_video()) { - *type = SRS_RTMP_TYPE_VIDEO; - *timestamp = (uint32_t)msg->header.timestamp; - *data = (char*)msg->payload; - *size = (int)msg->size; - // detach bytes from packet. - msg->payload = NULL; - } else if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) { - *type = SRS_RTMP_TYPE_SCRIPT; - *data = (char*)msg->payload; - *size = (int)msg->size; - // detach bytes from packet. - msg->payload = NULL; - } else if (msg->header.is_aggregate()) { - if ((ret = srs_rtmp_on_aggregate(context, msg)) != ERROR_SUCCESS) { - return ret; - } - *got_msg = false; - } else { - *type = msg->header.message_type; - *data = (char*)msg->payload; - *size = (int)msg->size; - // detach bytes from packet. - msg->payload = NULL; - } - - return ret; -} - -int srs_rtmp_read_packet(srs_rtmp_t rtmp, char* type, uint32_t* timestamp, char** data, int* size) -{ - *type = 0; - *timestamp = 0; - *data = NULL; - *size = 0; - - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - for (;;) { - SrsCommonMessage* msg = NULL; - - // read from cache first. - if (!context->msgs.empty()) { - std::vector::iterator it = context->msgs.begin(); - msg = *it; - context->msgs.erase(it); - } - - // read from protocol sdk. - if (!msg && (err = context->rtmp->recv_message(&msg)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // no msg, try again. - if (!msg) { - continue; - } - - SrsAutoFree(SrsCommonMessage, msg); - - // process the got packet, if nothing, try again. - bool got_msg; - if ((ret = srs_rtmp_go_packet(context, msg, type, timestamp, data, size, &got_msg)) != ERROR_SUCCESS) { - return ret; - } - - // got expected message. - if (got_msg) { - break; - } - } - - return ret; -} - -int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, uint32_t timestamp, char* data, int size) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - SrsSharedPtrMessage* msg = NULL; - - if ((err = srs_rtmp_create_msg(type, timestamp, data, size, context->stream_id, &msg)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - srs_assert(msg); - - // send out encoded msg. - if ((err = context->rtmp->send_and_free_message(msg, context->stream_id)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -void srs_rtmp_free_packet(char* data) -{ - srs_freepa(data); -} - -srs_bool srs_rtmp_is_onMetaData(char type, char* data, int size) -{ - srs_error_t err = srs_success; - - if (type != SRS_RTMP_TYPE_SCRIPT) { - return false; - } - - SrsBuffer stream(data, size); - - std::string name; - if ((err = srs_amf0_read_string(&stream, name)) != srs_success) { - srs_freep(err); - return false; - } - - if (name == SRS_CONSTS_RTMP_ON_METADATA) { - return true; - } - - if (name == SRS_CONSTS_RTMP_SET_DATAFRAME) { - return true; - } - - return false; -} - -/** - * directly write a audio frame. - */ -int srs_write_audio_raw_frame(Context* context, char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t timestamp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - char* data = NULL; - int size = 0; - if ((err = context->aac_raw.mux_aac2flv(frame, frame_size, codec, timestamp, &data, &size)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); -} - -/** - * write aac frame in adts. - */ -int srs_write_aac_adts_frame(Context* context, SrsRawAacStreamCodec* codec, char* frame, int frame_size, uint32_t timestamp) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - // send out aac sequence header if not sent. - if (context->aac_specific_config.empty()) { - std::string sh; - if ((err = context->aac_raw.mux_sequence_header(codec, sh)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - context->aac_specific_config = sh; - - codec->aac_packet_type = 0; - - if ((ret = srs_write_audio_raw_frame(context, (char*)sh.data(), (int)sh.length(), codec, timestamp)) != ERROR_SUCCESS) { - return ret; - } - } - - codec->aac_packet_type = 1; - return srs_write_audio_raw_frame(context, frame, frame_size, codec, timestamp); -} - -/** - * write aac frames in adts. - */ -int srs_write_aac_adts_frames(Context* context, char sound_format, char sound_rate, - char sound_size, char sound_type, char* frames, int frames_size, uint32_t timestamp -) { - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - SrsBuffer* stream = new SrsBuffer(frames, frames_size); - SrsAutoFree(SrsBuffer, stream); - - while (!stream->empty()) { - char* frame = NULL; - int frame_size = 0; - SrsRawAacStreamCodec codec; - if ((err = context->aac_raw.adts_demux(stream, &frame, &frame_size, codec)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // override by user specified. - codec.sound_format = sound_format; - codec.sound_rate = sound_rate; - codec.sound_size = sound_size; - codec.sound_type = sound_type; - - if ((ret = srs_write_aac_adts_frame(context, &codec, frame, frame_size, timestamp)) != ERROR_SUCCESS) { - return ret; - } - } - - return ret; -} - -/** - * write audio raw frame to SRS. - */ -int srs_audio_write_raw_frame(srs_rtmp_t rtmp, char sound_format, char sound_rate, - char sound_size, char sound_type, char* frame, int frame_size, uint32_t timestamp -) { - int ret = ERROR_SUCCESS; - - Context* context = (Context*)rtmp; - srs_assert(context); - - if (sound_format == SrsAudioCodecIdAAC) { - // for aac, the frame must be ADTS format. - if (!srs_aac_is_adts(frame, frame_size)) { - return ERROR_AAC_REQUIRED_ADTS; - } - - // for aac, demux the ADTS to RTMP format. - return srs_write_aac_adts_frames(context, sound_format, sound_rate, sound_size, sound_type, frame, frame_size, timestamp); - } else { - // use codec info for aac. - SrsRawAacStreamCodec codec; - codec.sound_format = sound_format; - codec.sound_rate = sound_rate; - codec.sound_size = sound_size; - codec.sound_type = sound_type; - codec.aac_packet_type = 0; - - // for other data, directly write frame. - return srs_write_audio_raw_frame(context, frame, frame_size, &codec, timestamp); - } - - return ret; -} - -/** - * whether aac raw data is in adts format, - * which bytes sequence matches '1111 1111 1111'B, that is 0xFFF. - */ -srs_bool srs_aac_is_adts(char* aac_raw_data, int ac_raw_size) -{ - SrsBuffer stream(aac_raw_data, ac_raw_size); - return srs_aac_startswith_adts(&stream); -} - -/** - * parse the adts header to get the frame size. - */ -int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size) -{ - int size = -1; - - if (!srs_aac_is_adts(aac_raw_data, ac_raw_size)) { - return size; - } - - // adts always 7bytes. - if (ac_raw_size <= 7) { - return size; - } - - // last 2bits - int16_t ch3 = aac_raw_data[3]; - // whole 8bits - int16_t ch4 = aac_raw_data[4]; - // first 3bits - int16_t ch5 = aac_raw_data[5]; - - size = ((ch3 << 11) & 0x1800) | ((ch4 << 3) & 0x07f8) | ((ch5 >> 5) & 0x0007); - - return size; -} - -/** - * write h264 IPB-frame. - */ -int srs_write_h264_ipb_frame(Context* context, char* frame, int frame_size, uint32_t dts, uint32_t pts) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - // when sps or pps not sent, ignore the packet. - // @see https://github.com/ossrs/srs/issues/203 - if (!context->h264_sps_pps_sent) { - return ERROR_H264_DROP_BEFORE_SPS_PPS; - } - - // 5bits, 7.3.1 NAL unit syntax, - // ISO_IEC_14496-10-AVC-2003.pdf, page 44. - // 5: I Frame, 1: P/B Frame - // @remark we already group sps/pps to sequence header frame; - // for I/P NALU, we send them in isolate frame, each NALU in a frame; - // for other NALU, for example, AUD/SEI, we just ignore them, because - // AUD used in annexb to split frame, while SEI generally we can ignore it. - // TODO: maybe we should group all NALUs split by AUD to a frame. - SrsAvcNaluType nut = (SrsAvcNaluType)(frame[0] & 0x1f); - if (nut != SrsAvcNaluTypeIDR && nut != SrsAvcNaluTypeNonIDR) { - return ret; - } - - // for IDR frame, the frame is keyframe. - SrsVideoAvcFrameType frame_type = SrsVideoAvcFrameTypeInterFrame; - if (nut == SrsAvcNaluTypeIDR) { - frame_type = SrsVideoAvcFrameTypeKeyFrame; - } - - std::string ibp; - if ((err = context->avc_raw.mux_ipb_frame(frame, frame_size, ibp)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - int8_t avc_packet_type = SrsVideoAvcFrameTraitNALU; - char* flv = NULL; - int nb_flv = 0; - if ((err = context->avc_raw.mux_avc2flv(ibp, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // the timestamp in rtmp message header is dts. - uint32_t timestamp = dts; - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, flv, nb_flv); -} - -/** - * write the h264 sps/pps in context over RTMP. - */ -int srs_write_h264_sps_pps(Context* context, uint32_t dts, uint32_t pts) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - // send when sps or pps changed. - if (!context->h264_sps_changed && !context->h264_pps_changed) { - return ret; - } - - // h264 raw to h264 packet. - std::string sh; - if ((err = context->avc_raw.mux_sequence_header(context->h264_sps, context->h264_pps, dts, pts, sh)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // h264 packet to flv packet. - int8_t frame_type = SrsVideoAvcFrameTypeKeyFrame; - int8_t avc_packet_type = SrsVideoAvcFrameTraitSequenceHeader; - char* flv = NULL; - int nb_flv = 0; - if ((err = context->avc_raw.mux_avc2flv(sh, frame_type, avc_packet_type, dts, pts, &flv, &nb_flv)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // reset sps and pps. - context->h264_sps_changed = false; - context->h264_pps_changed = false; - context->h264_sps_pps_sent = true; - - // the timestamp in rtmp message header is dts. - uint32_t timestamp = dts; - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, flv, nb_flv); -} - -/** - * write h264 raw frame, maybe sps/pps/IPB-frame. - */ -int srs_write_h264_raw_frame(Context* context, char* frame, int frame_size, uint32_t dts, uint32_t pts) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - // empty frame. - if (frame_size <= 0) { - return ret; - } - - // for sps - if (context->avc_raw.is_sps(frame, frame_size)) { - std::string sps; - if ((err = context->avc_raw.sps_demux(frame, frame_size, sps)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - if (context->h264_sps == sps) { - return ERROR_H264_DUPLICATED_SPS; - } - context->h264_sps_changed = true; - context->h264_sps = sps; - - return ret; - } - - // for pps - if (context->avc_raw.is_pps(frame, frame_size)) { - std::string pps; - if ((err = context->avc_raw.pps_demux(frame, frame_size, pps)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - if (context->h264_pps == pps) { - return ERROR_H264_DUPLICATED_PPS; - } - context->h264_pps_changed = true; - context->h264_pps = pps; - - return ret; - } - - // ignore others. - // 5bits, 7.3.1 NAL unit syntax, - // ISO_IEC_14496-10-AVC-2003.pdf, page 44. - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame, 9: AUD - SrsAvcNaluType nut = (SrsAvcNaluType)(frame[0] & 0x1f); - if (nut != SrsAvcNaluTypeSPS && nut != SrsAvcNaluTypePPS - && nut != SrsAvcNaluTypeIDR && nut != SrsAvcNaluTypeNonIDR - && nut != SrsAvcNaluTypeAccessUnitDelimiter - ) { - return ret; - } - - // send pps+sps before ipb frames when sps/pps changed. - if ((ret = srs_write_h264_sps_pps(context, dts, pts)) != ERROR_SUCCESS) { - return ret; - } - - // ibp frame. - return srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); -} - -/** - * write h264 multiple frames, in annexb format. - */ -int srs_h264_write_raw_frames(srs_rtmp_t rtmp, char* frames, int frames_size, uint32_t dts, uint32_t pts) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - srs_assert(frames != NULL); - srs_assert(frames_size > 0); - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - - SrsBuffer* stream = new SrsBuffer(frames, frames_size); - SrsAutoFree(SrsBuffer, stream); - - // use the last error - // @see https://github.com/ossrs/srs/issues/203 - // @see https://github.com/ossrs/srs/issues/204 - int error_code_return = ret; - - // send each frame. - while (!stream->empty()) { - char* frame = NULL; - int frame_size = 0; - if ((err = context->avc_raw.annexb_demux(stream, &frame, &frame_size)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - // ignore invalid frame, - // atleast 1bytes for SPS to decode the type - if (frame_size <= 0) { - continue; - } - - // it may be return error, but we must process all packets. - if ((ret = srs_write_h264_raw_frame(context, frame, frame_size, dts, pts)) != ERROR_SUCCESS) { - error_code_return = ret; - - // ignore known error, process all packets. - if (srs_h264_is_dvbsp_error(ret) - || srs_h264_is_duplicated_sps_error(ret) - || srs_h264_is_duplicated_pps_error(ret) - ) { - continue; - } - - return ret; - } - } - - return error_code_return; -} - -srs_bool srs_h264_is_dvbsp_error(int error_code) -{ - return error_code == ERROR_H264_DROP_BEFORE_SPS_PPS; -} - -srs_bool srs_h264_is_duplicated_sps_error(int error_code) -{ - return error_code == ERROR_H264_DUPLICATED_SPS; -} - -srs_bool srs_h264_is_duplicated_pps_error(int error_code) -{ - return error_code == ERROR_H264_DUPLICATED_PPS; -} - -srs_bool srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code) -{ - SrsBuffer stream(h264_raw_data, h264_raw_size); - return srs_avc_startswith_annexb(&stream, pnb_start_code); -} - -struct Mp4Context -{ - SrsFileReader reader; - SrsMp4Decoder dec; -}; - -srs_mp4_t srs_mp4_open_read(const char* file) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - Mp4Context* mp4 = new Mp4Context(); - - if ((err = mp4->reader.open(file)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_human_error("Open MP4 file failed, ret=%d", ret); - - srs_freep(mp4); - return NULL; - } - - return mp4; -} - -void srs_mp4_close(srs_mp4_t mp4) -{ - Mp4Context* context = (Mp4Context*)mp4; - srs_freep(context); -} - -int srs_mp4_init_demuxer(srs_mp4_t mp4) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - Mp4Context* context = (Mp4Context*)mp4; - - if ((err = context->dec.initialize(&context->reader)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_mp4_read_sample(srs_mp4_t mp4, srs_mp4_sample_t* s) -{ - s->sample = NULL; - - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - Mp4Context* context = (Mp4Context*)mp4; - SrsMp4Decoder* dec = &context->dec; - - SrsMp4HandlerType ht = SrsMp4HandlerTypeForbidden; - if ((err = dec->read_sample(&ht, &s->frame_type, &s->frame_trait, &s->dts, &s->pts, &s->sample, &s->nb_sample)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - if (ht == SrsMp4HandlerTypeForbidden) { - return ERROR_MP4_ILLEGAL_HANDLER; - } - - if (ht == SrsMp4HandlerTypeSOUN) { - s->codec = (uint16_t)dec->acodec; - s->sample_rate = dec->sample_rate; - s->channels = dec->channels; - s->sound_bits = dec->sound_bits; - } else { - s->codec = (uint16_t)dec->vcodec; - } - s->handler_type = (uint32_t)ht; - - return ret; -} - -void srs_mp4_free_sample(srs_mp4_sample_t* s) -{ - srs_freepa(s->sample); -} - -int32_t srs_mp4_sizeof(srs_mp4_t mp4, srs_mp4_sample_t* s) -{ - if (s->handler_type == SrsMp4HandlerTypeSOUN) { - if (s->codec == (uint16_t)SrsAudioCodecIdAAC) { - return s->nb_sample + 2; - } - return s->nb_sample + 1; - } - - if (s->codec == (uint16_t)SrsVideoCodecIdAVC) { - return s->nb_sample + 5; - } - return s->nb_sample + 1; -} - -int srs_mp4_to_flv_tag(srs_mp4_t mp4, srs_mp4_sample_t* s, char* type, uint32_t* time, char* data, int32_t size) -{ - int ret = ERROR_SUCCESS; - - *time = s->dts; - - SrsBuffer p(data, size); - if (s->handler_type == SrsMp4HandlerTypeSOUN) { - *type = SRS_RTMP_TYPE_AUDIO; - - // E.4.2.1 AUDIODATA, flv_v10_1.pdf, page 3 - p.write_1bytes(uint8_t(s->codec << 4) | uint8_t(s->sample_rate << 2) | uint8_t(s->sound_bits << 1) | s->channels); - if (s->codec == SrsAudioCodecIdAAC) { - p.write_1bytes(uint8_t(s->frame_trait == (uint16_t)SrsAudioAacFrameTraitSequenceHeader? 0:1)); - } - - p.write_bytes((char*)s->sample, s->nb_sample); - return ret; - } - - // E.4.3.1 VIDEODATA, flv_v10_1.pdf, page 5 - p.write_1bytes(uint8_t(s->frame_type<<4) | uint8_t(s->codec)); - if (s->codec == SrsVideoCodecIdAVC || s->codec == SrsVideoCodecIdHEVC || s->codec == SrsVideoCodecIdAV1) { - *type = SRS_RTMP_TYPE_VIDEO; - - p.write_1bytes(uint8_t(s->frame_trait == (uint16_t)SrsVideoAvcFrameTraitSequenceHeader? 0:1)); - // cts = pts - dts, where dts = flvheader->timestamp. - uint32_t cts = s->pts - s->dts; - p.write_3bytes(cts); - } - p.write_bytes((char*)s->sample, s->nb_sample); - - return ret; -} - -srs_bool srs_mp4_is_eof(int error_code) -{ - return error_code == ERROR_SYSTEM_FILE_EOF; -} - -struct FlvContext -{ - SrsFileReader reader; - SrsFileWriter writer; - SrsFlvTransmuxer enc; - SrsFlvDecoder dec; -}; - -srs_flv_t srs_flv_open_read(const char* file) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* flv = new FlvContext(); - - if ((err = flv->reader.open(file)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_human_error("Open FLV file failed, ret=%d", ret); - - srs_freep(flv); - return NULL; - } - - if ((err = flv->dec.initialize(&flv->reader)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_human_error("Initialize FLV demuxer failed, ret=%d", ret); - - srs_freep(flv); - return NULL; - } - - return flv; -} - -srs_flv_t srs_flv_open_write(const char* file) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* flv = new FlvContext(); - - if ((err = flv->writer.open(file)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_human_error("Open FLV file failed, ret=%d", ret); - - srs_freep(flv); - return NULL; - } - - if ((err = flv->enc.initialize(&flv->writer)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - srs_human_error("Initilize FLV muxer failed, ret=%d", ret); - - srs_freep(flv); - return NULL; - } - - return flv; -} - -void srs_flv_close(srs_flv_t flv) -{ - FlvContext* context = (FlvContext*)flv; - srs_freep(context); -} - -int srs_flv_read_header(srs_flv_t flv, char header[9]) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* context = (FlvContext*)flv; - - if (!context->reader.is_open()) { - return ERROR_SYSTEM_IO_INVALID; - } - - if ((err = context->dec.read_header(header)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - char ts[4]; // tag size - if ((err = context->dec.read_previous_tag_size(ts)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, uint32_t* ptime) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* context = (FlvContext*)flv; - - if (!context->reader.is_open()) { - return ERROR_SYSTEM_IO_INVALID; - } - - if ((err = context->dec.read_tag_header(ptype, pdata_size, ptime)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* context = (FlvContext*)flv; - - if (!context->reader.is_open()) { - return ERROR_SYSTEM_IO_INVALID; - } - - if ((err = context->dec.read_tag_data(data, size)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - char ts[4]; // tag size - if ((err = context->dec.read_previous_tag_size(ts)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_flv_write_header(srs_flv_t flv, char header[9]) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* context = (FlvContext*)flv; - - if (!context->writer.is_open()) { - return ERROR_SYSTEM_IO_INVALID; - } - - if ((err = context->enc.write_header(header)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - FlvContext* context = (FlvContext*)flv; - - if (!context->writer.is_open()) { - return ERROR_SYSTEM_IO_INVALID; - } - - if (type == SRS_RTMP_TYPE_AUDIO) { - if ((err = context->enc.write_audio(time, data, size)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - } else if (type == SRS_RTMP_TYPE_VIDEO) { - if ((err = context->enc.write_video(time, data, size)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - } else { - if ((err = context->enc.write_metadata(type, data, size)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - } - - return ret; -} - -int srs_flv_size_tag(int data_size) -{ - return SrsFlvTransmuxer::size_tag(data_size); -} - -int64_t srs_flv_tellg(srs_flv_t flv) -{ - FlvContext* context = (FlvContext*)flv; - return context->reader.tellg(); -} - -void srs_flv_lseek(srs_flv_t flv, int64_t offset) -{ - FlvContext* context = (FlvContext*)flv; - int64_t r0 = context->reader.seek2(offset); - srs_assert(r0 != -1); -} - -srs_bool srs_flv_is_eof(int error_code) -{ - return error_code == ERROR_SYSTEM_FILE_EOF; -} - -srs_bool srs_flv_is_sequence_header(char* data, int32_t size) -{ - return SrsFlvVideo::sh(data, (int)size); -} - -srs_bool srs_flv_is_keyframe(char* data, int32_t size) -{ - return SrsFlvVideo::keyframe(data, (int)size); -} - -srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) -{ - srs_error_t err = srs_success; - - srs_amf0_t amf0 = NULL; - - SrsBuffer stream(data, size); - - SrsAmf0Any* any = NULL; - if ((err = SrsAmf0Any::discovery(&stream, &any)) != srs_success) { - srs_freep(err); - return amf0; - } - - stream.skip(-1 * stream.pos()); - if ((err = any->read(&stream)) != srs_success) { - srs_freep(err); - srs_freep(any); - return amf0; - } - - if (nparsed) { - *nparsed = stream.pos(); - } - amf0 = (srs_amf0_t)any; - - return amf0; -} - -srs_amf0_t srs_amf0_create_string(const char* value) -{ - return SrsAmf0Any::str(value); -} - -srs_amf0_t srs_amf0_create_number(srs_amf0_number value) -{ - return SrsAmf0Any::number(value); -} - -srs_amf0_t srs_amf0_create_ecma_array() -{ - return SrsAmf0Any::ecma_array(); -} - -srs_amf0_t srs_amf0_create_strict_array() -{ - return SrsAmf0Any::strict_array(); -} - -srs_amf0_t srs_amf0_create_object() -{ - return SrsAmf0Any::object(); -} - -srs_amf0_t srs_amf0_ecma_array_to_object(srs_amf0_t ecma_arr) -{ - srs_assert(srs_amf0_is_ecma_array(ecma_arr)); - - SrsAmf0EcmaArray* arr = (SrsAmf0EcmaArray*)ecma_arr; - SrsAmf0Object* obj = SrsAmf0Any::object(); - - for (int i = 0; i < arr->count(); i++) { - std::string key = arr->key_at(i); - SrsAmf0Any* value = arr->value_at(i); - obj->set(key, value->copy()); - } - - return obj; -} - -void srs_amf0_free(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_freep(any); -} - -int srs_amf0_size(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->total_size(); -} - -int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size) -{ - int ret = ERROR_SUCCESS; - srs_error_t err = srs_success; - - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - - SrsBuffer stream(data, size); - - if ((err = any->write(&stream)) != srs_success) { - ret = srs_error_code(err); - srs_freep(err); - return ret; - } - - return ret; -} - -srs_bool srs_amf0_is_string(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_string(); -} - -srs_bool srs_amf0_is_boolean(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_boolean(); -} - -srs_bool srs_amf0_is_number(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_number(); -} - -srs_bool srs_amf0_is_null(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_null(); -} - -srs_bool srs_amf0_is_object(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_object(); -} - -srs_bool srs_amf0_is_ecma_array(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_ecma_array(); -} - -srs_bool srs_amf0_is_strict_array(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->is_strict_array(); -} - -const char* srs_amf0_to_string(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->to_str_raw(); -} - -srs_bool srs_amf0_to_boolean(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->to_boolean(); -} - -srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - return any->to_number(); -} - -void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - any->set_number(value); -} - -int srs_amf0_object_property_count(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_object()); - - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; - return obj->count(); -} - -const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_object()); - - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; - return obj->key_raw_at(index); -} - -srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_object()); - - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; - return (srs_amf0_t)obj->value_at(index); -} - -srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_object()); - - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; - return (srs_amf0_t)obj->get_property(name); -} - -void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_object()); - - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; - any = (SrsAmf0Any*)value; - obj->set(name, any); -} - -void srs_amf0_object_clear(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_object()); - - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; - obj->clear(); -} - -int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_ecma_array()); - - SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; - return obj->count(); -} - -const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_ecma_array()); - - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; - return obj->key_raw_at(index); -} - -srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_ecma_array()); - - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; - return (srs_amf0_t)obj->value_at(index); -} - -srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_ecma_array()); - - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; - return (srs_amf0_t)obj->get_property(name); -} - -void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_ecma_array()); - - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; - any = (SrsAmf0Any*)value; - obj->set(name, any); -} - -int srs_amf0_strict_array_property_count(srs_amf0_t amf0) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_strict_array()); - - SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; - return obj->count(); -} - -srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_strict_array()); - - SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; - return (srs_amf0_t)obj->at(index); -} - -void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) -{ - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - srs_assert(any->is_strict_array()); - - SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; - any = (SrsAmf0Any*)value; - obj->append(any); -} - -int64_t srs_utils_time_ms() -{ - return srs_update_system_time(); -} - -int64_t srs_utils_send_bytes(srs_rtmp_t rtmp) -{ - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - if (!context->rtmp) { - return 0; - } - return context->rtmp->get_send_bytes(); -} - -int64_t srs_utils_recv_bytes(srs_rtmp_t rtmp) -{ - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - if (!context->rtmp) { - return 0; - } - return context->rtmp->get_recv_bytes(); -} - -int srs_utils_parse_timestamp( - uint32_t time, char type, char* data, int size, - uint32_t* ppts - ) { - int ret = ERROR_SUCCESS; - - if (type != SRS_RTMP_TYPE_VIDEO) { - *ppts = time; - return ret; - } - - if (!SrsFlvVideo::h264(data, size)) { - return ERROR_FLV_INVALID_VIDEO_TAG; - } - - if (SrsFlvVideo::sh(data, size)) { - *ppts = time; - return ret; - } - - // 1bytes, frame type and codec id. - // 1bytes, avc packet type. - // 3bytes, cts, composition time, - // pts = dts + cts, or - // cts = pts - dts. - if (size < 5) { - return ERROR_FLV_INVALID_VIDEO_TAG; - } - - uint32_t cts = 0; - char* p = data + 2; - char* pp = (char*)&cts; - pp[2] = *p++; - pp[1] = *p++; - pp[0] = *p++; - - *ppts = time + cts; - - return ret; -} - -srs_bool srs_utils_flv_tag_is_ok(char type) -{ - return type == SRS_RTMP_TYPE_AUDIO || type == SRS_RTMP_TYPE_VIDEO || type == SRS_RTMP_TYPE_SCRIPT; -} - -srs_bool srs_utils_flv_tag_is_audio(char type) -{ - return type == SRS_RTMP_TYPE_AUDIO; -} - -srs_bool srs_utils_flv_tag_is_video(char type) -{ - return type == SRS_RTMP_TYPE_VIDEO; -} - -srs_bool srs_utils_flv_tag_is_av(char type) -{ - return type == SRS_RTMP_TYPE_AUDIO || type == SRS_RTMP_TYPE_VIDEO; -} - -char srs_utils_flv_video_codec_id(char* data, int size) -{ - if (size < 1) { - return 0; - } - - char codec_id = data[0]; - codec_id = codec_id & 0x0F; - - return codec_id; -} - -char srs_utils_flv_video_avc_packet_type(char* data, int size) -{ - if (size < 2) { - return -1; - } - - if (!SrsFlvVideo::h264(data, size)) { - return -1; - } - - uint8_t avc_packet_type = data[1]; - - if (avc_packet_type > 2) { - return -1; - } - - return avc_packet_type; -} - -char srs_utils_flv_video_frame_type(char* data, int size) -{ - if (size < 1) { - return -1; - } - - if (!SrsFlvVideo::h264(data, size)) { - return -1; - } - - uint8_t frame_type = data[0]; - frame_type = (frame_type >> 4) & 0x0f; - if (frame_type < 1 || frame_type > 5) { - return -1; - } - - return frame_type; -} - -char srs_utils_flv_audio_sound_format(char* data, int size) -{ - if (size < 1) { - return -1; - } - - uint8_t sound_format = data[0]; - sound_format = (sound_format >> 4) & 0x0f; - if (sound_format > 15 || sound_format == 12) { - return -1; - } - - return sound_format; -} - -char srs_utils_flv_audio_sound_rate(char* data, int size) -{ - if (size < 3) { - return -1; - } - - uint8_t sound_rate = data[0]; - sound_rate = (sound_rate >> 2) & 0x03; - - // For Opus, the first UINT8 is sampling rate. - uint8_t sound_format = (data[0] >> 4) & 0x0f; - if (sound_format != SrsAudioCodecIdOpus) { - return sound_rate; - } - - // The FrameTrait for AAC or Opus. - uint8_t frame_trait = data[1]; - if ((frame_trait&SrsAudioOpusFrameTraitSamplingRate) == SrsAudioOpusFrameTraitSamplingRate) { - sound_rate = data[2]; - } - - return sound_rate; -} - -char srs_utils_flv_audio_sound_size(char* data, int size) -{ - if (size < 1) { - return -1; - } - - uint8_t sound_size = data[0]; - sound_size = (sound_size >> 1) & 0x01; - - return sound_size; -} - -char srs_utils_flv_audio_sound_type(char* data, int size) -{ - if (size < 1) { - return -1; - } - - uint8_t sound_type = data[0]; - sound_type = sound_type & 0x01; - - return sound_type; -} - -char srs_utils_flv_audio_aac_packet_type(char* data, int size) -{ - if (size < 2) { - return -1; - } - - uint8_t sound_format = srs_utils_flv_audio_sound_format(data, size); - if (sound_format != SrsAudioCodecIdAAC && sound_format != SrsAudioCodecIdOpus) { - return -1; - } - - uint8_t frame_trait = data[1]; - return frame_trait; -} - -char* srs_human_amf0_print(srs_amf0_t amf0, char** pdata, int* psize) -{ - if (!amf0) { - return NULL; - } - - SrsAmf0Any* any = (SrsAmf0Any*)amf0; - - return any->human_print(pdata, psize); -} - -const char* srs_human_flv_tag_type2string(char type) -{ - static const char* audio = "Audio"; - static const char* video = "Video"; - static const char* data = "Data"; - static const char* unknown = "Unknown"; - - switch (type) { - case SRS_RTMP_TYPE_AUDIO: return audio; - case SRS_RTMP_TYPE_VIDEO: return video; - case SRS_RTMP_TYPE_SCRIPT: return data; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_video_codec_id2string(char codec_id) -{ - static const char* h263 = "H.263"; - static const char* screen = "Screen"; - static const char* vp6 = "VP6"; - static const char* vp6_alpha = "VP6Alpha"; - static const char* screen2 = "Screen2"; - static const char* h264 = "H.264"; - static const char* unknown = "Unknown"; - - switch (codec_id) { - case 2: return h263; - case 3: return screen; - case 4: return vp6; - case 5: return vp6_alpha; - case 6: return screen2; - case 7: return h264; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_video_avc_packet_type2string(char avc_packet_type) -{ - static const char* sps_pps = "SH"; - static const char* nalu = "Nalu"; - static const char* sps_pps_end = "SpsPpsEnd"; - static const char* unknown = "Unknown"; - - switch (avc_packet_type) { - case 0: return sps_pps; - case 1: return nalu; - case 2: return sps_pps_end; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_video_frame_type2string(char frame_type) -{ - static const char* keyframe = "I"; - static const char* interframe = "P/B"; - static const char* disposable_interframe = "DI"; - static const char* generated_keyframe = "GI"; - static const char* video_infoframe = "VI"; - static const char* unknown = "Unknown"; - - switch (frame_type) { - case 1: return keyframe; - case 2: return interframe; - case 3: return disposable_interframe; - case 4: return generated_keyframe; - case 5: return video_infoframe; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_audio_sound_format2string(char sound_format) -{ - static const char* linear_pcm = "LinearPCM"; - static const char* ad_pcm = "ADPCM"; - static const char* mp3 = "MP3"; - static const char* linear_pcm_le = "LinearPCMLe"; - static const char* nellymoser_16khz = "NellymoserKHz16"; - static const char* nellymoser_8khz = "NellymoserKHz8"; - static const char* nellymoser = "Nellymoser"; - static const char* g711_a_pcm = "G711APCM"; - static const char* g711_mu_pcm = "G711MuPCM"; - static const char* reserved = "Reserved"; - static const char* aac = "AAC"; - static const char* speex = "Speex"; - static const char* mp3_8khz = "MP3KHz8"; - static const char* opus = "Opus"; - static const char* device_specific = "DeviceSpecific"; - static const char* unknown = "Unknown"; - - switch (sound_format) { - case 0: return linear_pcm; - case 1: return ad_pcm; - case 2: return mp3; - case 3: return linear_pcm_le; - case 4: return nellymoser_16khz; - case 5: return nellymoser_8khz; - case 6: return nellymoser; - case 7: return g711_a_pcm; - case 8: return g711_mu_pcm; - case 9: return reserved; - case 10: return aac; - case 11: return speex; - case 13: return opus; - case 14: return mp3_8khz; - case 15: return device_specific; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_audio_sound_rate2string(char sound_rate) -{ - static const char* khz_5_5 = "5.5KHz"; - static const char* khz_11 = "11KHz"; - static const char* khz_22 = "22KHz"; - static const char* khz_44 = "44KHz"; - static const char* unknown = "Unknown"; - - // For Opus, support 8, 12, 16, 24, 48KHz - // We will write a UINT8 sampling rate after FLV audio tag header. - // @doc https://tools.ietf.org/html/rfc6716#section-2 - static const char* NB8kHz = "NB8kHz"; - static const char* MB12kHz = "MB12kHz"; - static const char* WB16kHz = "WB16kHz"; - static const char* SWB24kHz = "SWB24kHz"; - static const char* FB48kHz = "FB48kHz"; - - switch (sound_rate) { - case 0: return khz_5_5; - case 1: return khz_11; - case 2: return khz_22; - case 3: return khz_44; - // For Opus, support 8, 12, 16, 24, 48KHz - case 8: return NB8kHz; - case 12: return MB12kHz; - case 16: return WB16kHz; - case 24: return SWB24kHz; - case 48: return FB48kHz; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_audio_sound_size2string(char sound_size) -{ - static const char* bit_8 = "8bit"; - static const char* bit_16 = "16bit"; - static const char* unknown = "Unknown"; - - switch (sound_size) { - case 0: return bit_8; - case 1: return bit_16; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_audio_sound_type2string(char sound_type) -{ - static const char* mono = "Mono"; - static const char* stereo = "Stereo"; - static const char* unknown = "Unknown"; - - switch (sound_type) { - case 0: return mono; - case 1: return stereo; - default: return unknown; - } - - return unknown; -} - -const char* srs_human_flv_audio_aac_packet_type2string(char aac_packet_type) -{ - static const char* sps_pps = "SH"; - static const char* raw = "Raw"; - static const char* unknown = "Unknown"; - - switch (aac_packet_type) { - case 0: return sps_pps; - case 1: return raw; - - // See enum SrsAudioAacFrameTrait - // For Opus, the frame trait, may has more than one traits. - case 2: return "RAW"; - case 4: return "SR"; - case 8: return "AL"; - case 6: return "RAW|SR"; - case 10: return "RAW|AL"; - case 14: return "RAW|SR|AL"; - - default: return unknown; - } - - return unknown; -} - -int srs_human_format_rtmp_packet(char* buffer, int nb_buffer, char type, uint32_t timestamp, char* data, int size) -{ - int ret = ERROR_SUCCESS; - - // Initialize to empty NULL terminated string. - buffer[0] = 0; - - char sbytes[40]; - if (true) { - int nb = srs_min(8, size); - int p = 0; - for (int i = 0; i < nb; i++) { - p += snprintf(sbytes+p, 40-p, "0x%02x ", (uint8_t)data[i]); - } - } - - uint32_t pts; - if ((ret = srs_utils_parse_timestamp(timestamp, type, data, size, &pts)) != ERROR_SUCCESS) { - snprintf(buffer, nb_buffer, "Rtmp packet type=%s, dts=%d, size=%d, DecodeError, (%s), ret=%d", - srs_human_flv_tag_type2string(type), timestamp, size, sbytes, ret); - return ret; - } - - if (type == SRS_RTMP_TYPE_VIDEO) { - snprintf(buffer, nb_buffer, "Video packet type=%s, dts=%d, pts=%d, size=%d, %s(%s,%s), (%s)", - srs_human_flv_tag_type2string(type), timestamp, pts, size, - srs_human_flv_video_codec_id2string(srs_utils_flv_video_codec_id(data, size)), - srs_human_flv_video_avc_packet_type2string(srs_utils_flv_video_avc_packet_type(data, size)), - srs_human_flv_video_frame_type2string(srs_utils_flv_video_frame_type(data, size)), - sbytes); - } else if (type == SRS_RTMP_TYPE_AUDIO) { - snprintf(buffer, nb_buffer, "Audio packet type=%s, dts=%d, pts=%d, size=%d, %s(%s,%s,%s,%s), (%s)", - srs_human_flv_tag_type2string(type), timestamp, pts, size, - srs_human_flv_audio_sound_format2string(srs_utils_flv_audio_sound_format(data, size)), - srs_human_flv_audio_sound_rate2string(srs_utils_flv_audio_sound_rate(data, size)), - srs_human_flv_audio_sound_size2string(srs_utils_flv_audio_sound_size(data, size)), - srs_human_flv_audio_sound_type2string(srs_utils_flv_audio_sound_type(data, size)), - srs_human_flv_audio_aac_packet_type2string(srs_utils_flv_audio_aac_packet_type(data, size)), - sbytes); - } else if (type == SRS_RTMP_TYPE_SCRIPT) { - int nb = snprintf(buffer, nb_buffer, "Data packet type=%s, time=%d, size=%d, (%s)", - srs_human_flv_tag_type2string(type), timestamp, size, sbytes); - int nparsed = 0; - while (nparsed < size) { - int nb_parsed_this = 0; - srs_amf0_t amf0 = srs_amf0_parse(data + nparsed, size - nparsed, &nb_parsed_this); - if (amf0 == NULL) { - break; - } - - nparsed += nb_parsed_this; - - char* amf0_str = NULL; - nb += snprintf(buffer + nb, nb_buffer - nb, "\n%s", srs_human_amf0_print(amf0, &amf0_str, NULL)) - 1; - srs_freepa(amf0_str); - } - buffer[nb] = 0; - } else { - snprintf(buffer, nb_buffer, "Rtmp packet type=%#x, dts=%d, pts=%d, size=%d, (%s)", - type, timestamp, pts, size, sbytes); - } - - return ret; -} - -int srs_human_format_rtmp_packet2(char* buffer, int nb_buffer, char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp, int64_t pre_now, int64_t starttime, int64_t nb_packets) -{ - int ret = ERROR_SUCCESS; - - // Initialize to empty NULL terminated string. - buffer[0] = 0; - - // packets interval in milliseconds. - double pi = 0; - if (pre_now > starttime && nb_packets > 0) { - pi = (pre_now - starttime) / (double)nb_packets; - } - - // global fps(video and audio mixed fps). - double gfps = 0; - if (pi > 0) { - gfps = 1000 / pi; - } - - int diff = 0; - if (pre_timestamp > 0) { - diff = (int)timestamp - (int)pre_timestamp; - } - - int ndiff = 0; - if (pre_now > 0) { - ndiff = (int)(srs_utils_time_ms() - pre_now); - } - - char sbytes[40]; - if (true) { - int nb = srs_min(8, size); - int p = 0; - for (int i = 0; i < nb; i++) { - p += snprintf(sbytes+p, 40-p, "0x%02x ", (uint8_t)data[i]); - } - } - - uint32_t pts; - if ((ret = srs_utils_parse_timestamp(timestamp, type, data, size, &pts)) != ERROR_SUCCESS) { - snprintf(buffer, nb_buffer, "Rtmp packet id=%" PRId64 "/%.1f/%.1f, type=%s, dts=%d, ndiff=%d, diff=%d, size=%d, DecodeError, (%s), ret=%d", - nb_packets, pi, gfps, srs_human_flv_tag_type2string(type), timestamp, ndiff, diff, size, sbytes, ret); - return ret; - } - - if (type == SRS_RTMP_TYPE_VIDEO) { - snprintf(buffer, nb_buffer, "Video packet id=%" PRId64 "/%.1f/%.1f, type=%s, dts=%d, pts=%d, ndiff=%d, diff=%d, size=%d, %s(%s,%s), (%s)", - nb_packets, pi, gfps, srs_human_flv_tag_type2string(type), timestamp, pts, ndiff, diff, size, - srs_human_flv_video_codec_id2string(srs_utils_flv_video_codec_id(data, size)), - srs_human_flv_video_avc_packet_type2string(srs_utils_flv_video_avc_packet_type(data, size)), - srs_human_flv_video_frame_type2string(srs_utils_flv_video_frame_type(data, size)), - sbytes); - } else if (type == SRS_RTMP_TYPE_AUDIO) { - snprintf(buffer, nb_buffer, "Audio packet id=%" PRId64 "/%.1f/%.1f, type=%s, dts=%d, pts=%d, ndiff=%d, diff=%d, size=%d, %s(%s,%s,%s,%s), (%s)", - nb_packets, pi, gfps, srs_human_flv_tag_type2string(type), timestamp, pts, ndiff, diff, size, - srs_human_flv_audio_sound_format2string(srs_utils_flv_audio_sound_format(data, size)), - srs_human_flv_audio_sound_rate2string(srs_utils_flv_audio_sound_rate(data, size)), - srs_human_flv_audio_sound_size2string(srs_utils_flv_audio_sound_size(data, size)), - srs_human_flv_audio_sound_type2string(srs_utils_flv_audio_sound_type(data, size)), - srs_human_flv_audio_aac_packet_type2string(srs_utils_flv_audio_aac_packet_type(data, size)), - sbytes); - } else if (type == SRS_RTMP_TYPE_SCRIPT) { - int nb = snprintf(buffer, nb_buffer, "Data packet id=%" PRId64 "/%.1f/%.1f, type=%s, time=%d, ndiff=%d, diff=%d, size=%d, (%s)", - nb_packets, pi, gfps, srs_human_flv_tag_type2string(type), timestamp, ndiff, diff, size, sbytes); - int nparsed = 0; - while (nparsed < size) { - int nb_parsed_this = 0; - srs_amf0_t amf0 = srs_amf0_parse(data + nparsed, size - nparsed, &nb_parsed_this); - if (amf0 == NULL) { - break; - } - - nparsed += nb_parsed_this; - - char* amf0_str = NULL; - nb += snprintf(buffer + nb, nb_buffer - nb, "\n%s", srs_human_amf0_print(amf0, &amf0_str, NULL)) - 1; - srs_freepa(amf0_str); - } - buffer[nb] = 0; - } else { - snprintf(buffer, nb_buffer, "Rtmp packet id=%" PRId64 "/%.1f/%.1f, type=%#x, dts=%d, pts=%d, ndiff=%d, diff=%d, size=%d, (%s)", - nb_packets, pi, gfps, type, timestamp, pts, ndiff, diff, size, sbytes); - } - - return ret; -} - -const char* srs_human_format_time() -{ - struct timeval tv; - static char buf[24]; - - memset(buf, 0, sizeof(buf)); - - // clock time - if (gettimeofday(&tv, NULL) == -1) { - return buf; - } - - // to calendar time - struct tm* tm; - if ((tm = localtime((const time_t*)&tv.tv_sec)) == NULL) { - return buf; - } - - snprintf(buf, sizeof(buf), - "%d-%02d-%02d %02d:%02d:%02d.%03d", - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, - (int)(tv.tv_usec / 1000)); - - // for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 - buf[sizeof(buf) - 1] = 0; - - return buf; -} - - -#ifdef SRS_HIJACK_IO -srs_hijack_io_t srs_hijack_io_get(srs_rtmp_t rtmp) -{ - if (!rtmp) { - return NULL; - } - - Context* context = (Context*)rtmp; - if (!context->skt) { - return NULL; - } - - return context->skt->hijack_io(); -} -#endif - -srs_rtmp_t srs_rtmp_create2(const char* url) -{ - Context* context = new Context(); - - // use url as tcUrl. - context->url = url; - // auto append stream. - context->url += "/livestream"; - - // create socket - srs_freep(context->skt); - context->skt = new SimpleSocketStream(); - - int ret = ERROR_SUCCESS; - if ((ret = context->skt->create_socket(context)) != ERROR_SUCCESS) { - srs_human_error("Create socket failed, ret=%d", ret); - - // free the context and return NULL - srs_freep(context); - return NULL; - } - - return context; -} - -int srs_rtmp_connect_app2(srs_rtmp_t rtmp, char srs_server_ip[128],char srs_server[128], char srs_primary[128], char srs_authors[128], char srs_version[32], int* srs_id, int* srs_pid) -{ - srs_server_ip[0] = 0; - srs_server[0] = 0; - srs_primary[0] = 0; - srs_authors[0] = 0; - srs_version[0] = 0; - *srs_id = 0; - *srs_pid = 0; - - int ret = ERROR_SUCCESS; - - if ((ret = srs_rtmp_connect_app(rtmp)) != ERROR_SUCCESS) { - return ret; - } - - srs_assert(rtmp != NULL); - Context* context = (Context*)rtmp; - SrsServerInfo* si = &context->si; - - snprintf(srs_server_ip, 128, "%s", si->ip.c_str()); - snprintf(srs_server, 128, "%s", si->sig.c_str()); - snprintf(srs_version, 32, "%d.%d.%d.%d", si->major, si->minor, si->revision, si->build); - - return ret; -} - -int srs_human_print_rtmp_packet(char type, uint32_t timestamp, char* data, int size) -{ - return srs_human_print_rtmp_packet3(type, timestamp, data, size, 0, 0); -} - -int srs_human_print_rtmp_packet2(char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp) -{ - return srs_human_print_rtmp_packet3(type, timestamp, data, size, pre_timestamp, 0); -} - -int srs_human_print_rtmp_packet3(char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp, int64_t pre_now) -{ - return srs_human_print_rtmp_packet4(type, timestamp, data, size, pre_timestamp, pre_now, 0, 0); -} - -int srs_human_print_rtmp_packet4(char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp, int64_t pre_now, - int64_t starttime, int64_t nb_packets -) { - char buffer[1024]; - int ret = srs_human_format_rtmp_packet2(buffer, sizeof(buffer), type, timestamp, data, size, pre_timestamp, pre_now, starttime, nb_packets); - srs_human_trace("%s", buffer); - return ret; -} - -#ifdef __cplusplus -} -#endif - diff --git a/trunk/src/libs/srs_librtmp.hpp b/trunk/src/libs/srs_librtmp.hpp deleted file mode 100644 index 9f2044647..000000000 --- a/trunk/src/libs/srs_librtmp.hpp +++ /dev/null @@ -1,1256 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2013-2020 Winlin - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SRS_LIB_RTMP_HPP -#define SRS_LIB_RTMP_HPP - -/** - * srs-librtmp is a librtmp like library, - * used to play/publish rtmp stream from/to rtmp server. - * socket: use sync and block socket to connect/recv/send data with server. - * depends: no need other libraries; depends on ssl if use srs_complex_handshake. - * thread-safe: no - */ - -// @see http://blog.csdn.net/win_lin/article/details/7912693 -#ifndef __STDC_FORMAT_MACROS - #define __STDC_FORMAT_MACROS -#endif - -/************************************************************* - ************************************************************** - * Windows SRS-LIBRTMP pre-declare - ************************************************************** - *************************************************************/ -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifdef _WIN32 -// To disable some security warnings. -#define _CRT_SECURE_NO_WARNINGS -// include windows first. -#include -// the type used by this header for windows. -#if defined(_MSC_VER) - #include -#else - typedef char int8_t; - typedef short int16_t; - typedef int int32_t; - typedef long long int64_t; -#endif -typedef unsigned long long u_int64_t; -typedef unsigned int u_int32_t; -typedef u_int32_t uint32_t; -typedef unsigned char u_int8_t; -typedef unsigned short u_int16_t; -typedef int64_t ssize_t; -struct iovec { - void *iov_base; /* Starting address */ - size_t iov_len; /* Number of bytes to transfer */ -}; - -// for pid. -typedef int pid_t; -pid_t getpid(void); -#endif - -#include -#include - -#ifdef __cplusplus -extern "C"{ -#endif - -/** - * The schema of RTMP url, the following are legal urls: - * srs_url_schema_normal: rtmp://vhost:port/app/stream - * srs_url_schema_via : rtmp://ip:port/vhost/app/stream - * srs_url_schema_vis : rtmp://ip:port/app/stream?vhost=xxx - * srs_url_schema_vis2 : rtmp://ip:port/app/stream?domain=xxx - */ -enum srs_url_schema -{ - // Forbidden. - srs_url_schema_forbidden = 0, - // Normal RTMP URL, the vhost put in host field, using DNS to resolve the server ip. - // For example, rtmp://vhost:port/app/stream - srs_url_schema_normal, - // VIA(vhost in app), the vhost put in app field. - // For example, rtmp://ip:port/vhost/app/stream - srs_url_schema_via, - // VIS(vhost in stream), the vhost put in query string, keyword use vhost=xxx. - // For example, rtmp://ip:port/app/stream?vhost=xxx - srs_url_schema_vis, - // VIS, keyword use domain=xxx. - // For example, rtmp://ip:port/app/stream?domain=xxx - srs_url_schema_vis2 -}; - -// typedefs -typedef int srs_bool; - -/************************************************************* - ************************************************************** - * srs-librtmp version - ************************************************************** - *************************************************************/ -extern int srs_version_major(); -extern int srs_version_minor(); -extern int srs_version_revision(); - -/************************************************************* - ************************************************************** - * RTMP protocol context - ************************************************************** - *************************************************************/ -// the RTMP handler. -typedef void* srs_rtmp_t; -typedef void* srs_amf0_t; - -/** - * Create a RTMP handler. - * @param url The RTMP url, for example, rtmp://localhost/live/livestream - * @remark default timeout to 30s if not set by srs_rtmp_set_timeout. - * @remark default schema to srs_url_schema_normal, use srs_rtmp_set_schema to change it. - * - * @return a rtmp handler, or NULL if error occured. - */ -extern srs_rtmp_t srs_rtmp_create(const char* url); -/** - * set socket timeout - * @param recv_timeout_ms the timeout for receiving messages in ms. - * @param send_timeout_ms the timeout for sending message in ms. - * @remark user can set timeout once srs_rtmp_create/srs_rtmp_create2, - * or before srs_rtmp_handshake or srs_rtmp_dns_resolve to connect to server. - * @remark default timeout to 30s if not set by srs_rtmp_set_timeout. - * - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_set_timeout(srs_rtmp_t rtmp, int recv_timeout_ms, int send_timeout_ms); -/** - * close and destroy the rtmp stack. - * @remark, user should never use the rtmp again. - */ -extern void srs_rtmp_destroy(srs_rtmp_t rtmp); - -/************************************************************* - ************************************************************** - * RTMP protocol stack - ************************************************************** - *************************************************************/ -/** - * connect and handshake with server - * category: publish/play - * previous: rtmp-create - * next: connect-app - * - * @return 0, success; otherswise, failed. - */ -/** - * simple handshake specifies in rtmp 1.0, - * not depends on ssl. - */ -/** - * srs_rtmp_handshake equals to invoke: - * srs_rtmp_dns_resolve() - * srs_rtmp_connect_server() - * srs_rtmp_do_simple_handshake() - * user can use these functions if needed. - */ -extern int srs_rtmp_handshake(srs_rtmp_t rtmp); -// parse uri, create socket, resolve host -extern int srs_rtmp_dns_resolve(srs_rtmp_t rtmp); -// connect socket to server -extern int srs_rtmp_connect_server(srs_rtmp_t rtmp); -// do simple handshake over socket. -extern int srs_rtmp_do_simple_handshake(srs_rtmp_t rtmp); -// do complex handshake over socket. -extern int srs_rtmp_do_complex_handshake(srs_rtmp_t rtmp); - -/** - * set the args of connect packet for rtmp. - * @param args, the extra amf0 object args. - * @remark, all params can be NULL to ignore. - * @remark, user should never free the args for we directly use it. - */ -extern int srs_rtmp_set_connect_args(srs_rtmp_t rtmp, const char* tcUrl, const char* swfUrl, const char* pageUrl, srs_amf0_t args); - -/** - * Set the schema of URL when connect to tcUrl by srs_rtmp_connect_app. - * @param schema, The schema of URL, @see srs_url_schema. - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_set_schema(srs_rtmp_t rtmp, enum srs_url_schema schema); - -/** - * Connect to RTMP tcUrl(Vhost/App), similar to flash AS3 NetConnection.connect(tcUrl). - * @remark When connected to server, user can retrieve informations from RTMP handler, - * for example, use srs_rtmp_get_server_id to get server ip/pid/cid. - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_connect_app(srs_rtmp_t rtmp); - -/** - * Retrieve server ip from RTMP handler. - * @param ip A NULL terminated string specifies the server ip. - * @param pid An int specifies the PID of server. -1 is no PID information. - * @param cid An int specifies the CID of connection. -1 is no CID information. - * @remark For SRS, ip/pid/cid is the UUID of a client. For other server, these values maybe unknown. - * @remark When connected to server by srs_rtmp_connect_app, the information is ready to be retrieved. - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_get_server_id(srs_rtmp_t rtmp, char** ip, int* pid, int* cid); - -/** - * Retrieve server signature from RTMP handler. - * @param sig A NULL terminated string specifies the server signature. - * @remark When connected to server by srs_rtmp_connect_app, the information is ready to be retrieved. - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_get_server_sig(srs_rtmp_t rtmp, char** sig); - -/** - * Retrieve server version from RTMP handler, which in major.minor.revision.build format. - * @remark When connected to server by srs_rtmp_connect_app, the information is ready to be retrieved. - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_get_server_version(srs_rtmp_t rtmp, int* major, int* minor, int* revision, int* build); - -/** - * play a live/vod stream. - * category: play - * previous: connect-app - * next: destroy - * @return 0, success; otherwise, failed. - */ -extern int srs_rtmp_play_stream(srs_rtmp_t rtmp); - -/** - * publish a live stream. - * category: publish - * previous: connect-app - * next: destroy - * @return 0, success; otherwise, failed. - */ -extern int srs_rtmp_publish_stream(srs_rtmp_t rtmp); - -/** - * do bandwidth check with srs server. - * - * bandwidth info: - * @param start_time, output the start time, in ms. - * @param end_time, output the end time, in ms. - * @param play_kbps, output the play/download kbps. - * @param publish_kbps, output the publish/upload kbps. - * @param play_bytes, output the play/download bytes. - * @param publish_bytes, output the publish/upload bytes. - * @param play_duration, output the play/download test duration, in ms. - * @param publish_duration, output the publish/upload test duration, in ms. - * - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_bandwidth_check(srs_rtmp_t rtmp, - int64_t* start_time, int64_t* end_time, - int* play_kbps, int* publish_kbps, - int* play_bytes, int* publish_bytes, - int* play_duration, int* publish_duration); - -/** - * E.4.1 FLV Tag, page 75 - */ -// 8 = audio -#define SRS_RTMP_TYPE_AUDIO 8 -// 9 = video -#define SRS_RTMP_TYPE_VIDEO 9 -// 18 = script data -#define SRS_RTMP_TYPE_SCRIPT 18 -/** - * read a audio/video/script-data packet from rtmp stream. - * @param type, output the packet type, macros: - * SRS_RTMP_TYPE_AUDIO, FlvTagAudio - * SRS_RTMP_TYPE_VIDEO, FlvTagVideo - * SRS_RTMP_TYPE_SCRIPT, FlvTagScript - * otherswise, invalid type. - * @param timestamp, in ms, overflow in 50days - * @param data, the packet data, according to type: - * FlvTagAudio, @see "E.4.2.1 AUDIODATA" - * FlvTagVideo, @see "E.4.3.1 VIDEODATA" - * FlvTagScript, @see "E.4.4.1 SCRIPTDATA" - * User can free the packet by srs_rtmp_free_packet. - * @param size, size of packet. - * @return the error code. 0 for success; otherwise, error. - * - * @remark: for read, user must free the data. - * @remark: for write, user should never free the data, even if error. - * @example /trunk/research/librtmp/srs_play.c - * @example /trunk/research/librtmp/srs_publish.c - * - * @return 0, success; otherswise, failed. - */ -extern int srs_rtmp_read_packet(srs_rtmp_t rtmp, char* type, uint32_t* timestamp, char** data, int* size); -// @param data User should never free it anymore. -extern int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, uint32_t timestamp, char* data, int size); - -/** - * Free the packet allocated by srs_rtmp_read_packet. - */ -extern void srs_rtmp_free_packet(char* data); - -/** - * whether type is script data and the data is onMetaData. - */ -extern srs_bool srs_rtmp_is_onMetaData(char type, char* data, int size); - -/************************************************************* - ************************************************************** - * audio raw codec - ************************************************************** - *************************************************************/ -/** - * write an audio raw frame to srs. - * not similar to h.264 video, the audio never aggregated, always - * encoded one frame by one, so this api is used to write a frame. - * - * @param sound_format Format of SoundData. The following values are defined: - * 0 = Linear PCM, platform endian - * 1 = ADPCM - * 2 = MP3 - * 3 = Linear PCM, little endian - * 4 = Nellymoser 16 kHz mono - * 5 = Nellymoser 8 kHz mono - * 6 = Nellymoser - * 7 = G.711 A-law logarithmic PCM - * 8 = G.711 mu-law logarithmic PCM - * 9 = reserved - * 10 = AAC - * 11 = Speex - * 14 = MP3 8 kHz - * 15 = Device-specific sound - * Formats 7, 8, 14, and 15 are reserved. - * AAC is supported in Flash Player 9,0,115,0 and higher. - * Speex is supported in Flash Player 10 and higher. - * @param sound_rate Sampling rate. The following values are defined: - * 0 = 5.5 kHz - * 1 = 11 kHz - * 2 = 22 kHz - * 3 = 44 kHz - * @param sound_size Size of each audio sample. This parameter only pertains to - * uncompressed formats. Compressed formats always decode - * to 16 bits internally. - * 0 = 8-bit samples - * 1 = 16-bit samples - * @param sound_type Mono or stereo sound - * 0 = Mono sound - * 1 = Stereo sound - * @param timestamp The timestamp of audio. - * - * @example /trunk/research/librtmp/srs_aac_raw_publish.c - * @example /trunk/research/librtmp/srs_audio_raw_publish.c - * - * @remark for aac, the frame must be in ADTS format. - * @see ISO_IEC_14496-3-AAC-2001.pdf, page 75, 1.A.2.2 ADTS - * @remark for aac, only support profile 1-4, AAC main/LC/SSR/LTP, - * @see ISO_IEC_14496-3-AAC-2001.pdf, page 23, 1.5.1.1 Audio object type - * - * @see https://github.com/ossrs/srs/issues/212 - * @see E.4.2.1 AUDIODATA of video_file_format_spec_v10_1.pdf - * - * @return 0, success; otherswise, failed. - */ -extern int srs_audio_write_raw_frame(srs_rtmp_t rtmp, - char sound_format, char sound_rate, char sound_size, char sound_type, - char* frame, int frame_size, uint32_t timestamp); - -/** - * whether aac raw data is in adts format, - * which bytes sequence matches '1111 1111 1111'B, that is 0xFFF. - * @param aac_raw_data the input aac raw data, a encoded aac frame data. - * @param ac_raw_size the size of aac raw data. - * - * @reamrk used to check whether current frame is in adts format. - * @see ISO_IEC_14496-3-AAC-2001.pdf, page 75, 1.A.2.2 ADTS - * @example /trunk/research/librtmp/srs_aac_raw_publish.c - * - * @return 0 false; otherwise, true. - */ -extern srs_bool srs_aac_is_adts(char* aac_raw_data, int ac_raw_size); - -/** - * parse the adts header to get the frame size, - * which bytes sequence matches '1111 1111 1111'B, that is 0xFFF. - * @param aac_raw_data the input aac raw data, a encoded aac frame data. - * @param ac_raw_size the size of aac raw data. - * - * @return failed when <=0 failed; otherwise, ok. - */ -extern int srs_aac_adts_frame_size(char* aac_raw_data, int ac_raw_size); - -/************************************************************* - ************************************************************** - * h264 raw codec - ************************************************************** - *************************************************************/ -/** - * write h.264 raw frame over RTMP to rtmp server. - * @param frames the input h264 raw data, encoded h.264 I/P/B frames data. - * frames can be one or more than one frame, - * each frame prefixed h.264 annexb header, by N[00] 00 00 01, where N>=0, - * for instance, frame = header(00 00 00 01) + payload(67 42 80 29 95 A0 14 01 6E 40) - * about annexb, @see ISO_IEC_14496-10-AVC-2003.pdf, page 211. - * @param frames_size the size of h264 raw data. - * assert frames_size > 0, at least has 1 bytes header. - * @param dts the dts of h.264 raw data. - * @param pts the pts of h.264 raw data. - * - * @remark, user should free the frames. - * @remark, the tbn of dts/pts is 1/1000 for RTMP, that is, in ms. - * @remark, cts = pts - dts - * @remark, use srs_h264_startswith_annexb to check whether frame is annexb format. - * @example /trunk/research/librtmp/srs_h264_raw_publish.c - * @see https://github.com/ossrs/srs/issues/66 - * - * @return 0, success; otherswise, failed. - * for dvbsp error, @see srs_h264_is_dvbsp_error(). - * for duplictated sps error, @see srs_h264_is_duplicated_sps_error(). - * for duplictated pps error, @see srs_h264_is_duplicated_pps_error(). - */ -/** - For the example file: - http://winlinvip.github.io/srs.release/3rdparty/720p.h264.raw - The data sequence is: - // SPS - 000000016742802995A014016E40 - // PPS - 0000000168CE3880 - // IFrame - 0000000165B8041014C038008B0D0D3A071..... - // PFrame - 0000000141E02041F8CDDC562BBDEFAD2F..... - User can send the SPS+PPS, then each frame: - // SPS+PPS - srs_h264_write_raw_frames('000000016742802995A014016E400000000168CE3880', size, dts, pts) - // IFrame - srs_h264_write_raw_frames('0000000165B8041014C038008B0D0D3A071......', size, dts, pts) - // PFrame - srs_h264_write_raw_frames('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts) - User also can send one by one: - // SPS - srs_h264_write_raw_frames('000000016742802995A014016E4', size, dts, pts) - // PPS - srs_h264_write_raw_frames('00000000168CE3880', size, dts, pts) - // IFrame - srs_h264_write_raw_frames('0000000165B8041014C038008B0D0D3A071......', size, dts, pts) - // PFrame - srs_h264_write_raw_frames('0000000141E02041F8CDDC562BBDEFAD2F......', size, dts, pts) - */ -extern int srs_h264_write_raw_frames(srs_rtmp_t rtmp, char* frames, int frames_size, uint32_t dts, uint32_t pts); -/** - * whether error_code is dvbsp(drop video before sps/pps/sequence-header) error. - * - * @see https://github.com/ossrs/srs/issues/203 - * @example /trunk/research/librtmp/srs_h264_raw_publish.c - * @remark why drop video? - * some encoder, for example, ipcamera, will send sps/pps before each IFrame, - * so, when error and reconnect the rtmp, the first video is not sps/pps(sequence header), - * this will cause SRS server to disable HLS. - */ -extern srs_bool srs_h264_is_dvbsp_error(int error_code); -/** - * whether error_code is duplicated sps error. - * - * @see https://github.com/ossrs/srs/issues/204 - * @example /trunk/research/librtmp/srs_h264_raw_publish.c - */ -extern srs_bool srs_h264_is_duplicated_sps_error(int error_code); -/** - * whether error_code is duplicated pps error. - * - * @see https://github.com/ossrs/srs/issues/204 - * @example /trunk/research/librtmp/srs_h264_raw_publish.c - */ -extern srs_bool srs_h264_is_duplicated_pps_error(int error_code); -/** - * whether h264 raw data starts with the annexb, - * which bytes sequence matches N[00] 00 00 01, where N>=0. - * @param h264_raw_data the input h264 raw data, a encoded h.264 I/P/B frame data. - * @paam h264_raw_size the size of h264 raw data. - * @param pnb_start_code output the size of start code, must >=3. - * NULL to ignore. - * - * @reamrk used to check whether current frame is in annexb format. - * @example /trunk/research/librtmp/srs_h264_raw_publish.c - * - * @return 0 false; otherwise, true. - */ -extern srs_bool srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code); - -/************************************************************* - ************************************************************* - * MP4 muxer and demuxer. - * @example /trunk/research/librtmp/srs_ingest_mp4.c - ************************************************************* - *************************************************************/ -typedef void* srs_mp4_t; -// The sample struct of mp4. -typedef struct { - // The handler type, it's SrsMp4HandlerType. - uint32_t handler_type; - - // The dts in milliseconds. - uint32_t dts; - // The codec id. - // video: SrsVideoCodecId. - // audio: SrsAudioCodecId. - uint16_t codec; - // The frame trait, some characteristic: - // video: SrsVideoAvcFrameTrait. - // audio: SrsAudioAacFrameTrait. - uint16_t frame_trait; - - // The video pts in milliseconds. Ignore for audio. - uint32_t pts; - // The video frame type, it's SrsVideoAvcFrameType. - uint16_t frame_type; - - // The audio sample rate, it's SrsAudioSampleRate. - uint8_t sample_rate; - // The audio sound bits, it's SrsAudioSampleBits. - uint8_t sound_bits; - // The audio sound type, it's SrsAudioChannels. - uint8_t channels; - - // The size of sample payload in bytes. - uint32_t nb_sample; - // The output sample data, user must free it by srs_mp4_free_sample. - uint8_t* sample; -} srs_mp4_sample_t; -/** - * Open mp4 file for muxer(write) or demuxer(read). - * @return A MP4 demuxer, NULL if failed. - */ -extern srs_mp4_t srs_mp4_open_read(const char* file); -/** - * Close the MP4 demuxer. - */ -extern void srs_mp4_close(srs_mp4_t mp4); -/** - * Initialize mp4 demuxer in non-seek mode. - * @remark Only support non-seek mode, that is fmp4 or moov before mdata. - * For the live streaming, we must feed stream frame by frame. - */ -extern int srs_mp4_init_demuxer(srs_mp4_t mp4); -/** - * Read a sample form mp4. - * @remark User can use srs_mp4_sample_to_flv_tag to convert mp4 sampel to flv tag. - * Use the srs_mp4_to_flv_tag_size to calc the flv tag data size to alloc. - */ -extern int srs_mp4_read_sample(srs_mp4_t mp4, srs_mp4_sample_t* sample); -/** - * Free the allocated mp4 sample. - */ -extern void srs_mp4_free_sample(srs_mp4_sample_t* sample); -/** - * Calc the size of flv tag, for the mp4 sample to convert to. - */ -extern int32_t srs_mp4_sizeof(srs_mp4_t mp4, srs_mp4_sample_t* sample); -/** - * Covert mp4 sample to flv tag. - */ -extern int srs_mp4_to_flv_tag(srs_mp4_t mp4, srs_mp4_sample_t* sample, char* type, uint32_t* time, char* data, int32_t size); -/* error code */ -/* whether the error code indicates EOF */ -extern srs_bool srs_mp4_is_eof(int error_code); - -/************************************************************* - ************************************************************** - * flv codec - * @example /trunk/research/librtmp/srs_flv_injecter.c - * @example /trunk/research/librtmp/srs_flv_parser.c - * @example /trunk/research/librtmp/srs_ingest_flv.c - * @example /trunk/research/librtmp/srs_ingest_rtmp.c - ************************************************************** - *************************************************************/ -typedef void* srs_flv_t; -/** - * Open FLV file in demux mode. - * @return A FLV demuxer, NULL if failed. - */ -extern srs_flv_t srs_flv_open_read(const char* file); -/** - * Open FlV file in mux mode. - * @return A FLV muxer, NULL if failed. - */ -extern srs_flv_t srs_flv_open_write(const char* file); -/** - * Close the FLV demuxer or muxer. - */ -extern void srs_flv_close(srs_flv_t flv); -/** - * read the flv header. 9bytes header. - * @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. - * 3bytes, signature, "FLV", - * 1bytes, version, 0x01, - * 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. - * 4bytes, dataoffset, 0x09, The length of this header in bytes - * - * @return 0, success; otherswise, failed. - * @remark, drop the 4bytes zero previous tag size. - */ -extern int srs_flv_read_header(srs_flv_t flv, char header[9]); -/** - * read the flv tag header, 1bytes tag, 3bytes data_size, - * 4bytes time, 3bytes stream id. - * @param ptype, output the type of tag, macros: - * SRS_RTMP_TYPE_AUDIO, FlvTagAudio - * SRS_RTMP_TYPE_VIDEO, FlvTagVideo - * SRS_RTMP_TYPE_SCRIPT, FlvTagScript - * @param pdata_size, output the size of tag data. - * @param ptime, output the time of tag, the dts in ms. - * - * @return 0, success; otherswise, failed. - * @remark, user must ensure the next is a tag, srs never check it. - */ -extern int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, uint32_t* ptime); -/** - * read the tag data. drop the 4bytes previous tag size - * @param data, the data to read, user alloc and free it. - * @param size, the size of data to read, get by srs_flv_read_tag_header(). - * @remark, srs will ignore and drop the 4bytes previous tag size. - */ -extern int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); -/** - * write the flv header. 9bytes header. - * @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. - * 3bytes, signature, "FLV", - * 1bytes, version, 0x01, - * 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. - * 4bytes, dataoffset, 0x09, The length of this header in bytes - * - * @return 0, success; otherswise, failed. - * @remark, auto write the 4bytes zero previous tag size. - */ -extern int srs_flv_write_header(srs_flv_t flv, char header[9]); -/** - * write the flv tag to file. - * - * @return 0, success; otherswise, failed. - * @remark, auto write the 4bytes zero previous tag size. - */ -/* write flv tag to file, auto write the 4bytes previous tag size */ -extern int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size); -/** - * get the tag size, for flv injecter to adjust offset, - * size = tag_header(11B) + data_size + previous_tag(4B) - * @return the size of tag. - */ -extern int srs_flv_size_tag(int data_size); -/* file stream */ -/* file stream tellg to get offset */ -extern int64_t srs_flv_tellg(srs_flv_t flv); -/* seek file stream, offset is form the start of file */ -extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); -/* error code */ -/* whether the error code indicates EOF */ -extern srs_bool srs_flv_is_eof(int error_code); -/* media codec */ -/** - * whether the video body is sequence header - * @param data, the data of tag, read by srs_flv_read_tag_data(). - * @param size, the size of tag, read by srs_flv_read_tag_data(). - */ -extern srs_bool srs_flv_is_sequence_header(char* data, int32_t size); -/** - * whether the video body is keyframe - * @param data, the data of tag, read by srs_flv_read_tag_data(). - * @param size, the size of tag, read by srs_flv_read_tag_data(). - */ -extern srs_bool srs_flv_is_keyframe(char* data, int32_t size); - -/************************************************************* - ************************************************************** - * amf0 codec - * @example /trunk/research/librtmp/srs_ingest_flv.c - * @example /trunk/research/librtmp/srs_ingest_rtmp.c - ************************************************************** - *************************************************************/ -/* the output handler. */ -typedef double srs_amf0_number; -/** - * parse amf0 from data. - * @param nparsed, the parsed size, NULL to ignore. - * @return the parsed amf0 object. NULL for error. - * @remark user must free the parsed or created object by srs_amf0_free. - */ -extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); -extern srs_amf0_t srs_amf0_create_string(const char* value); -extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); -extern srs_amf0_t srs_amf0_create_ecma_array(); -extern srs_amf0_t srs_amf0_create_strict_array(); -extern srs_amf0_t srs_amf0_create_object(); -extern srs_amf0_t srs_amf0_ecma_array_to_object(srs_amf0_t ecma_arr); -extern void srs_amf0_free(srs_amf0_t amf0); -/* size and to bytes */ -extern int srs_amf0_size(srs_amf0_t amf0); -extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); -/* type detecter */ -extern srs_bool srs_amf0_is_string(srs_amf0_t amf0); -extern srs_bool srs_amf0_is_boolean(srs_amf0_t amf0); -extern srs_bool srs_amf0_is_number(srs_amf0_t amf0); -extern srs_bool srs_amf0_is_null(srs_amf0_t amf0); -extern srs_bool srs_amf0_is_object(srs_amf0_t amf0); -extern srs_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); -extern srs_bool srs_amf0_is_strict_array(srs_amf0_t amf0); -/* value converter */ -extern const char* srs_amf0_to_string(srs_amf0_t amf0); -extern srs_bool srs_amf0_to_boolean(srs_amf0_t amf0); -extern srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0); -/* value setter */ -extern void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value); -/* object value converter */ -extern int srs_amf0_object_property_count(srs_amf0_t amf0); -extern const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); -extern srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); -extern srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); -extern void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); -extern void srs_amf0_object_clear(srs_amf0_t amf0); -/* ecma array value converter */ -extern int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); -extern const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); -extern srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); -extern srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); -extern void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); -/* strict array value converter */ -extern int srs_amf0_strict_array_property_count(srs_amf0_t amf0); -extern srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); -extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); - -/************************************************************* - ************************************************************** - * utilities - ************************************************************** - *************************************************************/ -/** - * get the current system time in ms. - * use gettimeofday() to get system time. - */ -extern int64_t srs_utils_time_ms(); - -/** - * get the send bytes. - */ -extern int64_t srs_utils_send_bytes(srs_rtmp_t rtmp); - -/** - * get the recv bytes. - */ -extern int64_t srs_utils_recv_bytes(srs_rtmp_t rtmp); - -/** - * parse the dts and pts by time in header and data in tag, - * or to parse the RTMP packet by srs_rtmp_read_packet(). - * - * @param time, the timestamp of tag, read by srs_flv_read_tag_header(). - * @param type, the type of tag, read by srs_flv_read_tag_header(). - * @param data, the data of tag, read by srs_flv_read_tag_data(). - * @param size, the size of tag, read by srs_flv_read_tag_header(). - * @param ppts, output the pts in ms, - * - * @return 0, success; otherswise, failed. - * @remark, the dts always equals to @param time. - * @remark, the pts=dts for audio or data. - * @remark, video only support h.264. - */ -extern int srs_utils_parse_timestamp(uint32_t time, char type, char* data, int size, uint32_t* ppts); - -/** - * whether the flv tag specified by param type is ok. - * @return true when tag is video/audio/script-data; otherwise, false. - */ -extern srs_bool srs_utils_flv_tag_is_ok(char type); -extern srs_bool srs_utils_flv_tag_is_audio(char type); -extern srs_bool srs_utils_flv_tag_is_video(char type); -extern srs_bool srs_utils_flv_tag_is_av(char type); - -/** - * get the CodecID of video tag. - * Codec Identifier. The following values are defined: - * 2 = Sorenson H.263 - * 3 = Screen video - * 4 = On2 VP6 - * 5 = On2 VP6 with alpha channel - * 6 = Screen video version 2 - * 7 = AVC - * @return the code id. 0 for error. - */ -extern char srs_utils_flv_video_codec_id(char* data, int size); - -/** - * get the AVCPacketType of video tag. - * The following values are defined: - * 0 = AVC sequence header - * 1 = AVC NALU - * 2 = AVC end of sequence (lower level NALU sequence ender is - * not required or supported) - * @return the avc packet type. -1(0xff) for error. - */ -extern char srs_utils_flv_video_avc_packet_type(char* data, int size); - -/** - * get the FrameType of video tag. - * Type of video frame. The following values are defined: - * 1 = key frame (for AVC, a seekable frame) - * 2 = inter frame (for AVC, a non-seekable frame) - * 3 = disposable inter frame (H.263 only) - * 4 = generated key frame (reserved for server use only) - * 5 = video info/command frame - * @return the frame type. 0 for error. - */ -extern char srs_utils_flv_video_frame_type(char* data, int size); - -/** - * get the SoundFormat of audio tag. - * Format of SoundData. The following values are defined: - * 0 = Linear PCM, platform endian - * 1 = ADPCM - * 2 = MP3 - * 3 = Linear PCM, little endian - * 4 = Nellymoser 16 kHz mono - * 5 = Nellymoser 8 kHz mono - * 6 = Nellymoser - * 7 = G.711 A-law logarithmic PCM - * 8 = G.711 mu-law logarithmic PCM - * 9 = reserved - * 10 = AAC - * 11 = Speex - * 14 = MP3 8 kHz - * 15 = Device-specific sound - * Formats 7, 8, 14, and 15 are reserved. - * AAC is supported in Flash Player 9,0,115,0 and higher. - * Speex is supported in Flash Player 10 and higher. - * @return the sound format. -1(0xff) for error. - */ -extern char srs_utils_flv_audio_sound_format(char* data, int size); - -/** - * get the SoundRate of audio tag. - * Sampling rate. The following values are defined: - * 0 = 5.5 kHz - * 1 = 11 kHz - * 2 = 22 kHz - * 3 = 44 kHz - * @return the sound rate. -1(0xff) for error. - */ -extern char srs_utils_flv_audio_sound_rate(char* data, int size); - -/** - * get the SoundSize of audio tag. - * Size of each audio sample. This parameter only pertains to - * uncompressed formats. Compressed formats always decode - * to 16 bits internally. - * 0 = 8-bit samples - * 1 = 16-bit samples - * @return the sound size. -1(0xff) for error. - */ -extern char srs_utils_flv_audio_sound_size(char* data, int size); - -/** - * get the SoundType of audio tag. - * Mono or stereo sound - * 0 = Mono sound - * 1 = Stereo sound - * @return the sound type. -1(0xff) for error. - */ -extern char srs_utils_flv_audio_sound_type(char* data, int size); - -/** - * get the AACPacketType of audio tag. - * The following values are defined: - * 0 = AAC sequence header - * 1 = AAC raw - * @return the aac packet type. -1(0xff) for error. - */ -extern char srs_utils_flv_audio_aac_packet_type(char* data, int size); - -/************************************************************* - ************************************************************** - * human readable print. - ************************************************************** - *************************************************************/ -/** - * human readable print - * @param pdata, output the heap data, NULL to ignore. - * user must use srs_amf0_free_bytes to free it. - * @return return the *pdata for print. NULL to ignore. - */ -extern char* srs_human_amf0_print(srs_amf0_t amf0, char** pdata, int* psize); -/** - * convert the flv tag type to string. - * SRS_RTMP_TYPE_AUDIO to "Audio" - * SRS_RTMP_TYPE_VIDEO to "Video" - * SRS_RTMP_TYPE_SCRIPT to "Data" - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_tag_type2string(char type); - -/** - * get the codec id string. - * H.263 = Sorenson H.263 - * Screen = Screen video - * VP6 = On2 VP6 - * VP6Alpha = On2 VP6 with alpha channel - * Screen2 = Screen video version 2 - * H.264 = AVC - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_video_codec_id2string(char codec_id); - -/** - * get the avc packet type string. - * SH = AVC sequence header - * Nalu = AVC NALU - * SpsPpsEnd = AVC end of sequence - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_video_avc_packet_type2string(char avc_packet_type); - -/** - * get the frame type string. - * I = key frame (for AVC, a seekable frame) - * P/B = inter frame (for AVC, a non-seekable frame) - * DI = disposable inter frame (H.263 only) - * GI = generated key frame (reserved for server use only) - * VI = video info/command frame - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_video_frame_type2string(char frame_type); - -/** - * get the SoundFormat string. - * Format of SoundData. The following values are defined: - * LinearPCM = Linear PCM, platform endian - * ADPCM = ADPCM - * MP3 = MP3 - * LinearPCMLe = Linear PCM, little endian - * NellymoserKHz16 = Nellymoser 16 kHz mono - * NellymoserKHz8 = Nellymoser 8 kHz mono - * Nellymoser = Nellymoser - * G711APCM = G.711 A-law logarithmic PCM - * G711MuPCM = G.711 mu-law logarithmic PCM - * Reserved = reserved - * AAC = AAC - * Speex = Speex - * MP3KHz8 = MP3 8 kHz - * DeviceSpecific = Device-specific sound - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_audio_sound_format2string(char sound_format); - -/** - * get the SoundRate of audio tag. - * Sampling rate. The following values are defined: - * 5.5KHz = 5.5 kHz - * 11KHz = 11 kHz - * 22KHz = 22 kHz - * 44KHz = 44 kHz - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_audio_sound_rate2string(char sound_rate); - -/** - * get the SoundSize of audio tag. - * Size of each audio sample. This parameter only pertains to - * uncompressed formats. Compressed formats always decode - * to 16 bits internally. - * 8bit = 8-bit samples - * 16bit = 16-bit samples - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_audio_sound_size2string(char sound_size); - -/** - * get the SoundType of audio tag. - * Mono or stereo sound - * Mono = Mono sound - * Stereo = Stereo sound - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_audio_sound_type2string(char sound_type); - -/** - * get the AACPacketType of audio tag. - * The following values are defined: - * SH = AAC sequence header - * Raw = AAC raw - * otherwise, "Unknown" - * @remark user never free the return char*, - * it's static shared const string. - */ -extern const char* srs_human_flv_audio_aac_packet_type2string(char aac_packet_type); - -/** - * Format the RTMP packet to human readable buffer. - * @return Whether parse RTMP packet ok. 0, success; otherwise, failed. - */ -extern int srs_human_format_rtmp_packet(char* buffer, int nb_buffer, char type, uint32_t timestamp, char* data, int size); -extern int srs_human_format_rtmp_packet2(char* buffer, int nb_buffer, char type, uint32_t timestamp, char* data, int size, - uint32_t pre_timestamp, int64_t pre_now, int64_t starttime, int64_t nb_packets); - -/** - * Format current time to human readable string. - * @return A NULL terminated string. - */ -extern const char* srs_human_format_time(); - -#ifndef _WIN32 -// for getpid. -#include -#endif -// The log function for librtmp. -// User can disable it by define macro SRS_DISABLE_LOG. -// Or user can directly use them, or define the alias by: -// #define trace(msg, ...) srs_human_trace(msg, ##__VA_ARGS__) -// #define warn(msg, ...) srs_human_warn(msg, ##__VA_ARGS__) -// #define error(msg, ...) srs_human_error(msg, ##__VA_ARGS__) -#ifdef SRS_DISABLE_LOG -#define srs_human_trace(msg, ...) (void)0 -#define srs_human_warn(msg, ...) (void)0 -#define srs_human_error(msg, ...) (void)0 -#define srs_human_verbose(msg, ...) (void)0 -#define srs_human_raw(msg, ...) (void)0 -#else -#include -#include -#define srs_human_trace(msg, ...) \ -fprintf(stdout, "[T][%d][%s] ", getpid(), srs_human_format_time());\ -fprintf(stdout, msg, ##__VA_ARGS__); fprintf(stdout, "\n") -#define srs_human_warn(msg, ...) \ -fprintf(stdout, "[W][%d][%s][%d] ", getpid(), srs_human_format_time(), errno); \ -fprintf(stdout, msg, ##__VA_ARGS__); \ -fprintf(stdout, "\n") -#define srs_human_error(msg, ...) \ -fprintf(stderr, "[E][%d][%s][%d] ", getpid(), srs_human_format_time(), errno);\ -fprintf(stderr, msg, ##__VA_ARGS__); \ -fprintf(stderr, " (%s)\n", strerror(errno)) -#define srs_human_verbose(msg, ...) (void)0 -#define srs_human_raw(msg, ...) printf(msg, ##__VA_ARGS__) -#endif - -/************************************************************* - ************************************************************** - * IO hijack, use your specified io functions. - ************************************************************** - *************************************************************/ -// the void* will convert to your handler for io hijack. -typedef void* srs_hijack_io_t; -#ifdef SRS_HIJACK_IO -#ifndef _WIN32 -// for iovec. -#include -#endif -/** - * get the hijack io object in rtmp protocol sdk. - * @remark, user should never provides this method, srs-librtmp provides it. - */ -extern srs_hijack_io_t srs_hijack_io_get(srs_rtmp_t rtmp); -#endif -// define the following macro and functions in your module to hijack the io. -// the example @see https://github.com/ossrs/srs-bench -// which use librtmp but use its own io(use st also). -#ifdef SRS_HIJACK_IO -/** - * create hijack. - * @return NULL for error; otherwise, ok. - */ -extern srs_hijack_io_t srs_hijack_io_create(); -/** - * destroy the context, user must close the socket. - */ -extern void srs_hijack_io_destroy(srs_hijack_io_t ctx); -/** - * create socket, not connect yet. - * @param owner, the rtmp context which create this socket. - * @return 0, success; otherswise, failed. - * TODO: FIXME: Incompatible API for https://github.com/ossrs/srs/blob/2.0release/trunk/src/libs/srs_librtmp.hpp#L989 - */ -extern int srs_hijack_io_create_socket(srs_hijack_io_t ctx, srs_rtmp_t owner); -/** - * connect socket at server_ip:port. - * @return 0, success; otherswise, failed. - */ -extern int srs_hijack_io_connect(srs_hijack_io_t ctx, const char* server_ip, int port); -/** - * read from socket. - * @return 0, success; otherswise, failed. - */ -extern int srs_hijack_io_read(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread); -/** - * set the socket recv timeout in ms. - * @return 0, success; otherswise, failed. - */ -extern int srs_hijack_io_set_recv_timeout(srs_hijack_io_t ctx, int64_t tm); -/** - * get the socket recv timeout. - * @return 0, success; otherswise, failed. - */ -extern int64_t srs_hijack_io_get_recv_timeout(srs_hijack_io_t ctx); -/** - * get the socket recv bytes. - * @return 0, success; otherswise, failed. - */ -extern int64_t srs_hijack_io_get_recv_bytes(srs_hijack_io_t ctx); -/** - * set the socket send timeout in ms. - * @return 0, success; otherswise, failed. - */ -extern int srs_hijack_io_set_send_timeout(srs_hijack_io_t ctx, int64_t tm); -/** - * get the socket send timeout. - * @return 0, success; otherswise, failed. - */ -extern int64_t srs_hijack_io_get_send_timeout(srs_hijack_io_t ctx); -/** - * get the socket send bytes. - * @return 0, success; otherswise, failed. - */ -extern int64_t srs_hijack_io_get_send_bytes(srs_hijack_io_t ctx); -/** - * writev of socket. - * @return 0, success; otherswise, failed. - * @remark We assume that the writev always write all data to peer, like what ST or block-socket done. - */ -extern int srs_hijack_io_writev(srs_hijack_io_t ctx, const iovec *iov, int iov_size, ssize_t* nwrite); -/** - * whether the timeout is never timeout in ms. - * @return 0, with timeout specified; otherwise, never timeout. - * TODO: FIXME: Incompatible API for https://github.com/ossrs/srs/blob/2.0release/trunk/src/libs/srs_librtmp.hpp#L1039 - */ -extern int srs_hijack_io_is_never_timeout(srs_hijack_io_t ctx, int64_t tm); -/** - * read fully, fill the buf exactly size bytes. - * @return 0, success; otherswise, failed. - */ -extern int srs_hijack_io_read_fully(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nread); -/** - * write bytes to socket. - * @return 0, success; otherswise, failed. - * @remark We assume that the write always write all data to peer, like what ST or block-socket done. - */ -extern int srs_hijack_io_write(srs_hijack_io_t ctx, void* buf, size_t size, ssize_t* nwrite); -#endif - -/************************************************************* - ************************************************************** - * Windows SRS-LIBRTMP solution - ************************************************************** - *************************************************************/ -// for srs-librtmp, @see https://github.com/ossrs/srs/issues/213 -#ifdef _WIN32 -#include -int gettimeofday(struct timeval* tv, struct timezone* tz); -#define PRId64 "lld" - -// for inet helpers. -typedef int socklen_t; -const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); - -// for mkdir(). -#include - -// for open(). -typedef int mode_t; -#define S_IRUSR 0 -#define S_IWUSR 0 -#define S_IXUSR 0 -#define S_IRGRP 0 -#define S_IWGRP 0 -#define S_IXGRP 0 -#define S_IROTH 0 -#define S_IXOTH 0 - -// for file seek. -#include -#include -#define open _open -#define close _close -#define lseek _lseek - -// for socket. -ssize_t writev(int fd, const struct iovec *iov, int iovcnt); -typedef int64_t useconds_t; -int usleep(useconds_t usec); -int socket_setup(); -int socket_cleanup(); - -// others. -#define snprintf _snprintf -#endif - -/************************************************************* - ************************************************************* - * Deprecated APIs, maybe removed in future versions. - ************************************************************* - *************************************************************/ -/** - * Deprecated, for bandwidth test check only. - */ -extern srs_rtmp_t srs_rtmp_create2(const char* url); - -/** - * Deprecated, use seperate function to retrieve information from rtmp, - * for example, use srs_rtmp_get_server_ip to get server ip. - */ -extern int srs_rtmp_connect_app2(srs_rtmp_t rtmp, - char srs_server_ip[128], char srs_server[128], - char srs_primary[128], char srs_authors[128], - char srs_version[32], int* srs_id, int* srs_pid); - -/** - * Deprecated, use srs_human_format_rtmp_packet instead. - */ -extern int srs_human_print_rtmp_packet(char type, uint32_t timestamp, char* data, int size); -extern int srs_human_print_rtmp_packet2(char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp); -extern int srs_human_print_rtmp_packet3(char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp, int64_t pre_now); -extern int srs_human_print_rtmp_packet4(char type, uint32_t timestamp, char* data, int size, uint32_t pre_timestamp, int64_t pre_now, - int64_t starttime, int64_t nb_packets); - -#ifdef __cplusplus -} -#endif - -#endif -