diff --git a/trunk/configure b/trunk/configure index 6d3da2bff..c939a96c4 100755 --- a/trunk/configure +++ b/trunk/configure @@ -257,7 +257,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_edge" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" "srs_app_http_static" "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" - "srs_app_mpegts_udp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" + "srs_app_mpegts_udp" "srs_app_rtp" "srs_app_rtc_conn" "srs_app_dtls" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call" "srs_app_caster_flv" "srs_app_process" "srs_app_ng_exec" "srs_app_hourglass" "srs_app_dash" "srs_app_fragment" "srs_app_dvr" "srs_app_coworkers" "srs_app_hybrid") diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index bfc5c09f4..97f640f33 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -47,14 +47,14 @@ static bool is_stun(const char* data, const int size) return data != NULL && size > 0 && (data[0] == 0 || data[0] == 1); } -static bool is_rtp_or_rtcp(const char* data, const int size) +static bool is_dtls(const char* data, size_t len) { - return data != NULL && size > 0 && (data[0] >= 128 && data[0] <= 191); + return (len >= 13 && (data[0] > 19 && data[0] < 64)); } -static bool is_dtls(const char* data, const int size) +static bool is_rtp_or_rtcp(const char* data, size_t len) { - return data != NULL && size > 0 && (data[0] >= 20 && data[0] <= 64); + return (len >= 12 && (data[0] & 0xC0) == 0x80); } static string gen_random_str(int len) diff --git a/trunk/src/app/srs_app_rtp.cpp b/trunk/src/app/srs_app_rtp.cpp new file mode 100644 index 000000000..015141f84 --- /dev/null +++ b/trunk/src/app/srs_app_rtp.cpp @@ -0,0 +1,285 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len); +static string dump_string_hex(const std::string& str, const int& max_len = 128) +{ + return dump_string_hex(str.c_str(), str.size(), max_len); +} + +static string dump_string_hex(const char* buf, const int nb_buf, const int& max_len = 128) +{ + char tmp_buf[1024*16]; + int len = 0; + + for (int i = 0; i < nb_buf && i < max_len; ++i) { + int nb = snprintf(tmp_buf + len, sizeof(tmp_buf) - len - 1, "%02X ", (uint8_t)buf[i]); + if (nb <= 0) + break; + + len += nb; + } + tmp_buf[len] = '\0'; + + return string(tmp_buf, len); +} + + +SrsRtpRawFrame::SrsRtpRawFrame(char* buf, int len) +{ + if (buf && len > 0) { + payload = new char[len]; + size = len; + memcpy(payload, buf, len); + } else { + payload = NULL; + size = 0; + } +} + +SrsRtpRawFrame::~SrsRtpRawFrame() +{ + if (payload) { + delete [] payload; + payload = NULL; + size = 0; + } +} + +srs_error_t SrsRtpRawFrame::avcc_to_annexb() +{ + srs_error_t err = srs_success; + + if (! (payload[0] == 0x00 && payload[1] == 0x00 && payload[2] == 0x00 && payload[3] == 0x01)) { + } + + return err; +} + +srs_error_t SrsRtpRawFrame::frame_to_packet() +{ + srs_error_t err = srs_success; + if (payload == NULL || size <= 4) { + return srs_error_wrap(err, "invalid rtp raw frame"); + } + + avcc_to_annexb(); + + char buf[1500] = {0}; + SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf)); +} + +SrsRtpMuxer::SrsRtpMuxer() +{ +} + +SrsRtpMuxer::~SrsRtpMuxer() +{ +} + +srs_error_t SrsRtpMuxer::video_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (shared_video->size < 5) { + return srs_error_wrap(err, "invalid video size:%d", shared_video->size); + } + + SrsRtpRawFrame* rtp_raw_frame = new SrsRtpRawFrame(shared_video->payload + 5, shared_video->size - 5); + SrsAutoFree(SrsRtpRawFrame, rtp_raw_frame); + + rtp_raw_frame->frame_to_packet(); + + srs_trace("video dump=%s", dump_string_hex(shared_video->payload, shared_video->size).c_str()); + + //srs_avcc_to_annexb(raw, raw_len); + + return err; +} + +srs_error_t SrsRtpMuxer::audio_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format) +{ + srs_error_t err = srs_success; + + return err; +} + +SrsRtp::SrsRtp() +{ + req = NULL; + hub = NULL; + + enabled = false; + disposable = false; + last_update_time = 0; +} + +SrsRtp::~SrsRtp() +{ +} + +void SrsRtp::dispose() +{ + if (enabled) { + on_unpublish(); + } +} + +srs_error_t SrsRtp::cycle() +{ + srs_error_t err = srs_success; + + return err; +} + +srs_error_t SrsRtp::initialize(SrsOriginHub* h, SrsRequest* r) +{ + srs_error_t err = srs_success; + + hub = h; + req = r; + + rtp_muxer = new SrsRtpMuxer(); + + return err; +} + +srs_error_t SrsRtp::on_publish() +{ + srs_error_t err = srs_success; + + // update the hls time, for hls_dispose. + last_update_time = srs_get_system_time(); + + // support multiple publish. + if (enabled) { + return err; + } + + // if enabled, open the muxer. + enabled = true; + + // ok, the hls can be dispose, or need to be dispose. + disposable = true; + + return err; +} + +void SrsRtp::on_unpublish() +{ + srs_error_t err = srs_success; + + // support multiple unpublish. + if (!enabled) { + return; + } + + enabled = false; +} + +srs_error_t SrsRtp::on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (!enabled) { + return err; + } + + // Ignore if no format->acodec, it means the codec is not parsed, or unknown codec. + // @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474 + if (!format->acodec) { + return err; + } + + // update the hls time, for hls_dispose. + last_update_time = srs_get_system_time(); + + SrsSharedPtrMessage* audio = shared_audio->copy(); + SrsAutoFree(SrsSharedPtrMessage, audio); + + // ts support audio codec: aac/mp3 + SrsAudioCodecId acodec = format->acodec->id; + if (acodec != SrsAudioCodecIdAAC && acodec != SrsAudioCodecIdMP3) { + return err; + } + + // ignore sequence header + srs_assert(format->audio); + + return rtp_muxer->audio_frame_to_packet(audio, format); +} + +srs_error_t SrsRtp::on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format) +{ + srs_error_t err = srs_success; + + if (!enabled) { + return err; + } + + // Ignore if no format->vcodec, it means the codec is not parsed, or unknown codec. + // @issue https://github.com/ossrs/srs/issues/1506#issuecomment-562079474 + if (!format->vcodec) { + return err; + } + + // update the hls time, for hls_dispose. + last_update_time = srs_get_system_time(); + + SrsSharedPtrMessage* video = shared_video->copy(); + SrsAutoFree(SrsSharedPtrMessage, video); + + // ignore info frame, + // @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909 + srs_assert(format->video); + return rtp_muxer->video_frame_to_packet(video, format); +} diff --git a/trunk/src/app/srs_app_rtp.hpp b/trunk/src/app/srs_app_rtp.hpp new file mode 100644 index 000000000..097d2a8a6 --- /dev/null +++ b/trunk/src/app/srs_app_rtp.hpp @@ -0,0 +1,87 @@ +/** + * 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_APP_RTP_HPP +#define SRS_APP_RTP_HPP + +#include + +#include +#include +#include + +class SrsFormat; +class SrsSharedPtrMessage; +class SrsRequest; +class SrsOriginHub; + +class SrsRtpRawFrame +{ +public: + int64_t timestamp; + char* payload; + int size; +public: + SrsRtpRawFrame(char* buf, int len); + virtual ~SrsRtpRawFrame(); +public: + srs_error_t avcc_to_annexb(); + srs_error_t frame_to_packet(); +}; + +class SrsRtpMuxer +{ +private: + std::map packet_queue; +public: + SrsRtpMuxer(); + virtual ~SrsRtpMuxer(); +public: + srs_error_t video_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); + srs_error_t audio_frame_to_packet(SrsSharedPtrMessage* shared_video, SrsFormat* format); +}; + +class SrsRtp +{ +private: + SrsRequest* req; + bool enabled; + bool disposable; + srs_utime_t last_update_time; + SrsRtpMuxer* rtp_muxer; + SrsOriginHub* hub; +public: + SrsRtp(); + virtual ~SrsRtp(); +public: + virtual void dispose(); + virtual srs_error_t cycle(); +public: + virtual srs_error_t initialize(SrsOriginHub* h, SrsRequest* r); + virtual srs_error_t on_publish(); + virtual void on_unpublish(); + virtual srs_error_t on_audio(SrsSharedPtrMessage* shared_audio, SrsFormat* format); + virtual srs_error_t on_video(SrsSharedPtrMessage* shared_video, SrsFormat* format); +}; + +#endif diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f5acb05da..f30eb0163 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -32,6 +32,7 @@ using namespace std; #include #include #include +#include #include #include #include @@ -824,6 +825,7 @@ SrsOriginHub::SrsOriginHub() dash = new SrsDash(); dvr = new SrsDvr(); encoder = new SrsEncoder(); + rtp = new SrsRtp(); #ifdef SRS_AUTO_HDS hds = new SrsHds(); #endif @@ -868,6 +870,10 @@ srs_error_t SrsOriginHub::initialize(SrsSource* s, SrsRequest* r) return srs_error_wrap(err, "format initialize"); } + if ((err = rtp->initialize(this, req)) != srs_success) { + return srs_error_wrap(err, "rtp initialize"); + } + if ((err = hls->initialize(this, req)) != srs_success) { return srs_error_wrap(err, "hls initialize"); } @@ -965,6 +971,12 @@ srs_error_t SrsOriginHub::on_audio(SrsSharedPtrMessage* shared_audio) flv_sample_sizes[c->sound_size], flv_sound_types[c->sound_type], srs_flv_srates[c->sound_rate]); } + + if ((err = rtp->on_audio(msg, format)) != srs_success) { + srs_warn("rtp: ignore audio error %s", srs_error_desc(err).c_str()); + srs_error_reset(err); + rtp->on_unpublish(); + } if ((err = hls->on_audio(msg, format)) != srs_success) { // apply the error strategy for hls. @@ -1058,6 +1070,12 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se if (format->vcodec && !format->vcodec->is_avc_codec_ok()) { return err; } + + if ((err = rtp->on_video(msg, format)) != srs_success) { + srs_warn("rtp: ignore video error %s", srs_error_desc(err).c_str()); + srs_error_reset(err); + rtp->on_unpublish(); + } if ((err = hls->on_video(msg, format)) != srs_success) { // apply the error strategy for hls. @@ -1126,6 +1144,10 @@ srs_error_t SrsOriginHub::on_publish() return srs_error_wrap(err, "encoder publish"); } + if ((err = rtp->on_publish()) != srs_success) { + return srs_error_wrap(err, "rtp publish"); + } + if ((err = hls->on_publish()) != srs_success) { return srs_error_wrap(err, "hls publish"); } @@ -1163,6 +1185,7 @@ void SrsOriginHub::on_unpublish() destroy_forwarders(); encoder->on_unpublish(); + rtp->on_unpublish(); hls->on_unpublish(); dash->on_unpublish(); dvr->on_unpublish(); @@ -2224,7 +2247,7 @@ srs_error_t SrsSource::on_video(SrsCommonMessage* shared_video) return srs_error_wrap(err, "create message"); } - // directly process the audio message. + // directly process the video message. if (!mix_correct) { return on_video_imp(&msg); } diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 8cb79f478..674ffc99e 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -54,6 +54,7 @@ class SrsNgExec; class SrsConnection; class SrsMessageHeader; class SrsHls; +class SrsRtp; class SrsDvr; class SrsDash; class SrsEncoder; @@ -335,6 +336,8 @@ private: private: // The format, codec information. SrsRtmpFormat* format; + // rtp handler + SrsRtp* rtp; // hls handler. SrsHls* hls; // The DASH encoder.