├── nginx.conf ├── .gitignore ├── LICENSE ├── README.md ├── live.h ├── janus-gateway-live.patch └── live.c /nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | #user nobody; 3 | worker_processes 1; 4 | 5 | #error_log logs/error.log; 6 | #error_log logs/error.log notice; 7 | error_log logs/error.log debug; 8 | 9 | #pid logs/nginx.pid; 10 | 11 | 12 | events { 13 | worker_connections 1024; 14 | } 15 | 16 | 17 | rtmp { 18 | 19 | server { 20 | 21 | listen 1935; 22 | 23 | # chunk_size 4000; 24 | 25 | # TV mode: one publisher, many subscribers 26 | application qixi { 27 | live on; 28 | 29 | # enable live streaming 30 | } 31 | 32 | } 33 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Mac 55 | .vscode/ 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Bepartofyou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Janus-gateway live 2 | 3 | [![janus-gateway-live compliant](https://img.shields.io/badge/rtmp%20live-janus--gateway-brightgreen.svg)](https://github.com/Bepartofyou/janus-gateway-live) 4 | 5 | > Make janus-gateway more useful 6 | 7 | This repository may be used in the scenarios: ?Your client rtmp living is not stable because of the not stable network; ?You may use janus-gateway's plugins, and want a standard rtmp/http-flv/hls for sharing. 8 | 9 | This repository support now: 10 | 11 | * [x] ~~webrtc(opus + h264) ------(push)------> rtmp (only h264)~~ 12 | * [x] webrtc(opus + h264) ------(push)------> rtmp (aac + h264) 13 | * [ ] webrtc(opus + h264) <------(pull)------- rtmp (aac + h264) 14 | * [ ] webrtc(opus + h264) ---(multi mix + push)---> rtmp (aac + h264) 15 | 16 | 17 | ## Table of Contents 18 | 19 | - [Janus-gateway live](#janus-gateway-live) 20 | - [Table of Contents](#table-of-contents) 21 | - [Background](#background) 22 | - [Install](#install) 23 | - [Preparation](#preparation) 24 | - [Patch](#patch) 25 | - [RTMP server or CDN](#rtmp-server-or-cdn) 26 | - [Usage](#usage) 27 | - [RTMP pubslish](#rtmp-pubslish) 28 | - [Maintainers](#maintainers) 29 | - [Contributing](#contributing) 30 | - [License](#license) 31 | 32 | ## Background 33 | 34 | Janus-gateway is a wonderful webrtc gateway with many media scenarios, such as sip,videoroom,record and so on. Plugin record has record/playback api, so we can use the api for rtmp publish/play like record's record/playback. 35 | 36 | > Proposal: Don't make rtp2rtmp as a plugin, because any plugin may use the function just like record 37 | 38 | 39 | The goals for this repository are: 40 | 41 | 1. **An example**. May help someone for project using. 42 | 2. **Purpose** Make more thing happen using janus. 43 | 44 | 45 | ## Install 46 | 47 | ### Preparation 48 | 49 | First you should make sure that you can install the original [janus-gateway](https://github.com/meetecho/janus-gateway) successfully with `--enable-post-processing`. Because if `enable-post-processing` works, representing your ENV has `Opus` and `FFmpeg`, which will be used later. 50 | 51 | ```sh 52 | # My environment is macOS High Sierra(version 10.13.6) 53 | $ git clone https://github.com/meetecho/janus-gateway.git 54 | $ git checkout a7d7991a 55 | 56 | # make some janus-gateway prebuild for janus-gateway README.md 57 | 58 | $ ./autogen.sh 59 | $ ./configure --prefix=/your/path/janus PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig --enable-post-processing 60 | $ make -j8 && make install && make configs 61 | 62 | # Then you can use janus-gateway's record plugin for record and play testing. 63 | ``` 64 | 65 | ### Patch 66 | 67 | Patch the `janus-gateway-live.patch`, plugin `recordplay` can publish video to **RTMP server or CDN**. 68 | 69 | ```sh 70 | $ cp live.h live.c janus-gateway-live.patch /your/janus/source/path 71 | $ cd /your/janus/source/path 72 | $ patch -p1 < janus-gateway-live.patch 73 | $ ./configure --prefix=/your/path/janus PKG_CONFIG_PATH=/usr/local/opt/openssl/lib/pkgconfig --enable-post-processing 74 | $ make -j8 && make install && make configs 75 | ``` 76 | 77 | ### RTMP server or CDN 78 | 79 | In the `janus-gateway-live.patch`, I use local RTMP server for video publish. You can modify the RTMP server yourself in `conf/janus.plugin.recordplay.jcfg.sample.in` with **CDN**. If you just want to use local RTMP server for testing, here it is: 80 | 81 | ```sh 82 | $ git clone https://github.com/nginx/nginx.git 83 | $ git clone https://github.com/arut/nginx-rtmp-module.git 84 | $ git clone https://github.com/openssl/openssl.git 85 | $ cd nginx && ./auto/configure --prefix=/path/nginx --with-debug --add-module=/path/nginx-rtmp-module --with-openssl=/path/openssl 86 | $ make -j8 && make install 87 | $ cp nginx.conf /path/nginx/conf && cp /path/nginx && ./sbin/nginx -c conf/nginx.conf 88 | ``` 89 | 90 | ## Usage 91 | 92 | Use python SimpleHTTPServer for html web server: 93 | 94 | ```sh 95 | $ cd /install/janus/path/share/janus/demos && nohup python -m SimpleHTTPServer 8888 & 96 | $ /path/janus -C /path/janus.jcfg -p /path/janus.pid -L /path/janus.log -l -R -b -D -d 7 -e -B 50 97 | ``` 98 | 99 | ### RTMP pubslish 100 | 101 | Open the [demo](http://localhost:8888/)`http://localhost:8888/` , Record start!
Then you can play the rtmp url with `ffplay rtmp://localhost:1935/qixi/recording-id` 102 | 103 | 104 | ## Maintainers 105 | 106 | [@Bepartofyou](https://github.com/Bepartofyou). 107 | 108 | ## Contributing 109 | 110 | Feel free to dive in! [Open an issue](https://github.com/Bepartofyou/janus-gateway-live/issues/new) or submit PRs. 111 | 112 | Standard Readme follows the [Contributor Covenant](http://contributor-covenant.org/version/1/3/0/) Code of Conduct. 113 | 114 | 115 | ## License 116 | 117 | [MIT](LICENSE) Bepartofyou (七曦) 118 | -------------------------------------------------------------------------------- /live.h: -------------------------------------------------------------------------------- 1 | #ifndef _JANUS_LIVE_H 2 | #define _JANUS_LIVE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "mutex.h" 14 | #include "refcount.h" 15 | 16 | #define LIBAVCODEC_VER_AT_LEAST(major, minor) \ 17 | (LIBAVCODEC_VERSION_MAJOR > major || \ 18 | (LIBAVCODEC_VERSION_MAJOR == major && \ 19 | LIBAVCODEC_VERSION_MINOR >= minor)) 20 | 21 | #if LIBAVCODEC_VER_AT_LEAST(51, 42) 22 | #define PIX_FMT_YUV420P AV_PIX_FMT_YUV420P 23 | #endif 24 | 25 | #if LIBAVCODEC_VER_AT_LEAST(56, 56) 26 | #ifndef CODEC_FLAG_GLOBAL_HEADER 27 | #define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER 28 | #endif 29 | #ifndef FF_INPUT_BUFFER_PADDING_SIZE 30 | #define FF_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE 31 | #endif 32 | #endif 33 | 34 | #if LIBAVCODEC_VER_AT_LEAST(57, 14) 35 | #define USE_CODECPAR 36 | #endif 37 | 38 | #define AUDIO_MIN_SEQUENTIAL 2 39 | #define AUDIO_MAX_MISORDER 50 40 | /* Mixer settings */ 41 | #define AUDIO_DEFAULT_PREBUFFERING 6 42 | /* Opus settings */ 43 | #define AUDIO_BUFFER_SAMPLES 8000 44 | #define AUDIO_OPUS_SAMPLES 960 45 | #define AUDIO_DEFAULT_COMPLEXITY 4 46 | 47 | #define JANUS_LIVE_BUFFER_MAX 2 * 1024 * 1024 48 | #define htonll(x) ((1==htonl(1)) ? (x) : ((gint64)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 49 | #define ntohll(x) ((1==ntohl(1)) ? (x) : ((gint64)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 50 | 51 | typedef struct janus_rtp_jb janus_rtp_jb; 52 | typedef struct janus_live_pub janus_live_pub; 53 | typedef struct janus_live_el janus_live_el; 54 | 55 | 56 | typedef struct janus_adecoder_opus { 57 | uint8_t channels; 58 | uint32_t sampling_rate; /* Sampling rate (e.g., 16000 for wideband; can be 8, 12, 16, 24 or 48kHz) */ 59 | OpusDecoder *decoder; /* Opus decoder instance */ 60 | 61 | gboolean fec; /* Opus FEC status */ 62 | uint16_t expected_seq; /* Expected sequence number */ 63 | uint16_t probation; /* Used to determine new ssrc validity */ 64 | uint32_t last_timestamp; /* Last in seq timestamp */ 65 | 66 | janus_rtp_jb *jb; 67 | } janus_adecoder_opus; 68 | 69 | 70 | typedef struct janus_aencoder_fdkaac { 71 | int sample_rate; 72 | int channels; 73 | int bitrate; 74 | AVFrame *aframe; 75 | AVPacket *apacket; 76 | AVCodec *acodec; 77 | AVCodecContext *actx; 78 | 79 | int nb_samples; 80 | int buflen; 81 | char *buffer; 82 | janus_rtp_jb *jb; 83 | } janus_aencoder_fdkaac; 84 | 85 | 86 | typedef struct janus_frame_packet { 87 | char *data; /* data */ 88 | uint16_t len; /* Length of the data */ 89 | uint16_t seq; /* RTP Sequence number */ 90 | uint64_t ts; /* RTP Timestamp */ 91 | 92 | gboolean video; 93 | uint32_t ssrc; 94 | gint64 created; 95 | int keyFrame; 96 | 97 | int pt; /* Payload type of the data */ 98 | int skip; /* Bytes to skip, besides the RTP header */ 99 | int audiolevel; /* Value of audio level in RTP extension, if parsed */ 100 | int rotation; /* Value of rotation in RTP extension, if parsed */ 101 | uint8_t drop; /* Whether this packet can be dropped (e.g., padding)*/ 102 | struct janus_frame_packet *next; 103 | struct janus_frame_packet *prev; 104 | } janus_frame_packet; 105 | 106 | 107 | typedef struct janus_rtp_jb { 108 | uint32_t last_ts; 109 | uint32_t reset; 110 | uint32_t ssrc; 111 | uint16_t last_seq; 112 | uint16_t last_seq_out; 113 | int times_resetted; 114 | int post_reset_pkts; 115 | 116 | uint32_t tb; 117 | uint64_t start_ts; 118 | gint64 start_sys; 119 | 120 | gboolean keyframe_found; 121 | int keyFrame; 122 | int frameLen; 123 | int buflen; 124 | uint8_t *received_frame; 125 | uint64_t ts; 126 | janus_live_pub *pub; 127 | janus_adecoder_opus *adecoder; 128 | janus_aencoder_fdkaac *aencoder; 129 | uint32_t lastts; 130 | uint32_t offset; 131 | 132 | uint32_t size; 133 | janus_frame_packet *list; 134 | janus_frame_packet *last; 135 | } janus_rtp_jb; 136 | 137 | 138 | typedef struct janus_live_pub { 139 | char *url; 140 | char *acodec; 141 | char *vcodec; 142 | gint64 created; 143 | volatile gboolean closed; 144 | 145 | janus_rtp_jb *audio_jb; 146 | janus_rtp_jb *video_jb; 147 | 148 | GSource *jb_src; 149 | GSource *pub_src; 150 | janus_live_el *jb_loop; 151 | janus_live_el *pub_loop; 152 | 153 | int audio_level_extmap_id; 154 | int video_orient_extmap_id; 155 | 156 | uint32_t size; 157 | janus_frame_packet *list; 158 | janus_frame_packet *last; 159 | uint32_t start_ts; 160 | gint64 start_sys; 161 | 162 | int max_width; 163 | int max_height; 164 | gboolean init_flag; 165 | AVFormatContext *fctx; 166 | AVStream *vStream; 167 | AVStream *aStream; 168 | #ifdef USE_CODECPAR 169 | AVCodecContext *vEncoder; 170 | AVCodecContext *aEncoder; 171 | #endif 172 | AVBitStreamFilterContext *aacbsf; 173 | uint32_t lastts; 174 | 175 | janus_mutex mutex; 176 | janus_mutex mutex_live; 177 | volatile gint destroyed; 178 | janus_refcount ref; 179 | } janus_live_pub; 180 | 181 | 182 | typedef struct janus_live_el { 183 | int id; 184 | char *name; 185 | GThread *thread; 186 | GMainLoop *mainloop; 187 | GMainContext *mainctx; 188 | janus_live_pub *pub; 189 | } janus_live_el; 190 | 191 | 192 | janus_live_pub *janus_live_pub_create(const char *url, const char *acodec, const char *vcodec); 193 | int janus_live_pub_save_frame(janus_live_pub *pub, char *buffer, uint length, gboolean video, int slot); 194 | int janus_live_pub_close(janus_live_pub *pub); 195 | void janus_live_pub_destroy(janus_live_pub *pub); 196 | 197 | 198 | #endif /* _JANUS_LIVE_H */ -------------------------------------------------------------------------------- /janus-gateway-live.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile.am b/Makefile.am 2 | index 85d6bee6..1249f8f4 100644 3 | --- a/Makefile.am 4 | +++ b/Makefile.am 5 | @@ -104,6 +104,8 @@ janus_SOURCES = \ 6 | mutex.h \ 7 | record.c \ 8 | record.h \ 9 | + live.c \ 10 | + live.h \ 11 | refcount.h \ 12 | rtcp.c \ 13 | rtcp.h \ 14 | @@ -141,12 +143,16 @@ janus_CFLAGS = \ 15 | -DEVENTDIR=\"$(eventdir)\" \ 16 | -DCONFDIR=\"$(confdir)\" \ 17 | $(BORINGSSL_CFLAGS) \ 18 | + $(POST_PROCESSING_CFLAGS) \ 19 | + $(OPUS_CFLAGS) \ 20 | $(NULL) 21 | 22 | janus_LDADD = \ 23 | $(BORINGSSL_LIBS) \ 24 | $(JANUS_LIBS) \ 25 | $(JANUS_MANUAL_LIBS) \ 26 | + $(POST_PROCESSING_LIBS) \ 27 | + $(OPUS_LIBS) \ 28 | $(NULL) 29 | 30 | dist_man1_MANS = janus.1 31 | diff --git a/conf/janus.plugin.recordplay.jcfg.sample.in b/conf/janus.plugin.recordplay.jcfg.sample.in 32 | index a15d1b6c..77d30232 100644 33 | --- a/conf/janus.plugin.recordplay.jcfg.sample.in 34 | +++ b/conf/janus.plugin.recordplay.jcfg.sample.in 35 | @@ -2,6 +2,7 @@ 36 | # events = true|false, whether events should be sent to event handlers 37 | 38 | general: { 39 | + rtmp = "rtmp://localhost:1935/qixi" 40 | path = "@recordingsdir@" 41 | #events = false 42 | } 43 | diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c 44 | index 1c0e4507..73a8abbf 100644 45 | --- a/plugins/janus_recordplay.c 46 | +++ b/plugins/janus_recordplay.c 47 | @@ -265,6 +265,7 @@ 48 | #include "../config.h" 49 | #include "../mutex.h" 50 | #include "../record.h" 51 | +#include "../live.h" 52 | #include "../sdp-utils.h" 53 | #include "../rtp.h" 54 | #include "../rtcp.h" 55 | @@ -412,6 +413,7 @@ typedef struct janus_recordplay_session { 56 | janus_recordplay_recording *recording; 57 | janus_recorder *arc; /* Audio recorder */ 58 | janus_recorder *vrc; /* Video recorder */ 59 | + janus_live_pub *pub; /* live pub */ 60 | janus_mutex rec_mutex; /* Mutex to protect the recorders from race conditions */ 61 | janus_recordplay_frame_packet *aframes; /* Audio frames (for playout) */ 62 | janus_recordplay_frame_packet *vframes; /* Video frames (for playout) */ 63 | @@ -466,6 +468,7 @@ static void janus_recordplay_recording_free(const janus_refcount *recording_ref) 64 | 65 | 66 | static char *recordings_path = NULL; 67 | +static char *rtmp_path = NULL; 68 | void janus_recordplay_update_recordings_list(void); 69 | static void *janus_recordplay_playout_thread(void *data); 70 | 71 | @@ -704,6 +707,9 @@ int janus_recordplay_init(janus_callbacks *callback, const char *config_path) { 72 | janus_config_item *path = janus_config_get(config, config_general, janus_config_type_item, "path"); 73 | if(path && path->value) 74 | recordings_path = g_strdup(path->value); 75 | + janus_config_item *rtmp = janus_config_get(config, config_general, janus_config_type_item, "rtmp"); 76 | + if(rtmp && rtmp->value) 77 | + rtmp_path = g_strdup(rtmp->value); 78 | janus_config_item *events = janus_config_get(config, config_general, janus_config_type_item, "events"); 79 | if(events != NULL && events->value != NULL) 80 | notify_events = janus_is_true(events->value); 81 | @@ -996,6 +1002,7 @@ struct janus_plugin_result *janus_recordplay_handle_message(janus_plugin_session 82 | json_t *video_keyframe_interval= json_object_get(root, "video-keyframe-interval"); 83 | if(video_keyframe_interval) { 84 | session->video_keyframe_interval = json_integer_value(video_keyframe_interval); 85 | + session->video_keyframe_interval = 1000; 86 | JANUS_LOG(LOG_VERB, "Video keyframe interval has been set to %u\n", session->video_keyframe_interval); 87 | } 88 | response = json_object(); 89 | @@ -1120,6 +1127,7 @@ void janus_recordplay_send_rtcp_feedback(janus_plugin_session *handle, int video 90 | gint64 interval = (gint64)(session->video_keyframe_interval / 1000) * G_USEC_PER_SEC; 91 | 92 | if(elapsed >= interval) { 93 | + JANUS_LOG(LOG_INFO, "send pli and fir\n"); 94 | /* Send both a FIR and a PLI, just to be sure */ 95 | janus_rtcp_fir((char *)&rtcpbuf, 20, &session->video_fir_seq); 96 | gateway->relay_rtcp(handle, video, rtcpbuf, 20); 97 | @@ -1173,6 +1181,7 @@ void janus_recordplay_incoming_rtp(janus_plugin_session *handle, int video, char 98 | session->rec_vssrc = g_random_int(); 99 | header->ssrc = htonl(session->rec_vssrc); 100 | janus_recorder_save_frame(session->vrc, buf, len); 101 | + janus_live_pub_save_frame(session->pub, buf, len, TRUE, 1); 102 | /* Restore header or core statistics will be messed up */ 103 | header->ssrc = htonl(ssrc); 104 | header->timestamp = htonl(timestamp); 105 | @@ -1180,6 +1189,7 @@ void janus_recordplay_incoming_rtp(janus_plugin_session *handle, int video, char 106 | } else { 107 | /* Save the frame if we're recording */ 108 | janus_recorder_save_frame(video ? session->vrc : session->arc, buf, len); 109 | + janus_live_pub_save_frame(session->pub, buf, len, video, 1); 110 | } 111 | 112 | janus_recordplay_send_rtcp_feedback(handle, video, buf, len); 113 | @@ -1264,6 +1274,13 @@ static void janus_recordplay_hangup_media_internal(janus_plugin_session *handle) 114 | JANUS_LOG(LOG_INFO, "Closed video recording %s\n", rc->filename ? rc->filename : "??"); 115 | janus_recorder_destroy(rc); 116 | } 117 | + if(session->pub) { 118 | + janus_live_pub *pub = session->pub; 119 | + session->pub = NULL; 120 | + janus_live_pub_close(pub); 121 | + JANUS_LOG(LOG_INFO, "Closed rtmp living %s\n", pub->url ? pub->url : "??"); 122 | + janus_live_pub_destroy(pub); 123 | + } 124 | janus_mutex_unlock(&session->rec_mutex); 125 | if(session->recorder) { 126 | if(session->recording) { 127 | @@ -1479,6 +1496,7 @@ static void *janus_recordplay_handler(void *data) { 128 | /* Check which codec we should record for audio and/or video */ 129 | const char *acodec = NULL, *vcodec = NULL; 130 | janus_sdp_find_preferred_codecs(offer, &acodec, &vcodec); 131 | + vcodec = "h264"; 132 | rec->acodec = janus_audiocodec_from_name(acodec); 133 | rec->vcodec = janus_videocodec_from_name(vcodec); 134 | /* We found preferred codecs: let's just make sure the direction is what we need */ 135 | @@ -1533,6 +1551,10 @@ static void *janus_recordplay_handler(void *data) { 136 | rec->vrc_file = g_strdup(filename); 137 | session->vrc = janus_recorder_create(recordings_path, janus_videocodec_name(rec->vcodec), rec->vrc_file); 138 | } 139 | + char rtmpurl[1024]; 140 | + rtmpurl[0] = '\0'; 141 | + g_snprintf(rtmpurl, 1024, "%s/%"SCNu64"", rtmp_path, rec->id); 142 | + session->pub = janus_live_pub_create(rtmpurl, janus_audiocodec_name(rec->acodec), janus_audiocodec_name(rec->vcodec)); 143 | session->recorder = TRUE; 144 | session->recording = rec; 145 | session->sdp_version = 1; /* This needs to be increased when it changes */ 146 | -------------------------------------------------------------------------------- /live.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "rtp.h" 10 | #include "live.h" 11 | #include "debug.h" 12 | #include "utils.h" 13 | 14 | static int post_reset_trigger = 200; 15 | 16 | 17 | static void janus_live_event_loop_init(janus_live_pub *pub, janus_live_el **el, int id, char* name); 18 | static void *janus_live_event_loop_thread(void *data); 19 | static gboolean janus_live_send_handle(gpointer user_data); 20 | static gboolean janus_rtp_jb_handle(gpointer user_data); 21 | 22 | static int janus_live_ffmpeg_init(janus_live_pub *pub); 23 | static int janus_live_ffmpeg_free(janus_live_pub *pub); 24 | static void janus_rtp_jb_free(janus_live_pub *pub); 25 | static janus_frame_packet *janus_packet_alloc(int data_len); 26 | static void janus_packet_free(janus_frame_packet *pkt); 27 | static void janus_live_pub_free(const janus_refcount *pub_ref); 28 | 29 | static int janus_live_rtp_header_extension_parse_audio_level(char *buf,int len, int id, int *level); 30 | static int janus_live_rtp_header_extension_parse_video_orientation(char *buf, int len, int id, int *rotation); 31 | static void janus_live_h264_parse_sps(char *buffer, int *width, int *height); 32 | static void janus_live_rtp_unpack(janus_rtp_jb *jb, janus_frame_packet *packet, gboolean video); 33 | static int janus_live_packet_insert(janus_live_pub *pub, janus_frame_packet *p); 34 | 35 | static janus_adecoder_opus *janus_live_opus_decoder_create(uint32_t samplerate, int channels, gboolean fec); 36 | static void janus_live_opus_decoder_destory(janus_adecoder_opus *dc); 37 | static void janus_live_opus_decoder_decode(janus_adecoder_opus *dc, char *buf, int len); 38 | static janus_aencoder_fdkaac *janus_live_fdkaac_encoder_create(int sample_rate, int channels, int bitrate); 39 | static void janus_live_fdkaac_encoder_destory(janus_aencoder_fdkaac *ec); 40 | static void janus_live_fdkaac_encoder_encode(janus_aencoder_fdkaac *ec, char *data, int len, uint32_t pts); 41 | static void janus_live_fdkaac_encoder_encode_inernal(janus_aencoder_fdkaac *ec, char *data, int len, uint32_t pts); 42 | 43 | 44 | janus_live_pub * 45 | janus_live_pub_create(const char *url, const char *acodec, const char *vcodec) 46 | { 47 | if(url == NULL) { 48 | JANUS_LOG(LOG_ERR, "Missing live url information\n"); 49 | return NULL; 50 | } 51 | if(acodec == NULL && vcodec == NULL) { 52 | JANUS_LOG(LOG_ERR, "Audio Video must have one\n"); 53 | return NULL; 54 | } 55 | /* Create the live pub */ 56 | janus_live_pub *pub = g_malloc0(sizeof(janus_live_pub)); 57 | pub->url = g_strdup(url); 58 | JANUS_LOG(LOG_INFO, "rtmp url:%s\n", pub->url); 59 | if(acodec) 60 | pub->acodec = g_strdup(acodec); 61 | if(vcodec) 62 | pub->vcodec = g_strdup(vcodec); 63 | pub->created = janus_get_real_time(); 64 | pub->init_flag = FALSE; 65 | pub->closed = FALSE; 66 | 67 | if(pub->acodec) { 68 | pub->audio_jb = g_malloc0(sizeof(janus_rtp_jb)); 69 | pub->audio_jb->tb = 48000; 70 | pub->audio_jb->pub = pub; 71 | pub->audio_jb->adecoder = janus_live_opus_decoder_create(48000, 2, TRUE); 72 | pub->audio_jb->adecoder->jb = pub->audio_jb; 73 | pub->audio_jb->aencoder = janus_live_fdkaac_encoder_create(48000, 2, 128); 74 | pub->audio_jb->aencoder->jb = pub->audio_jb; 75 | } 76 | if(pub->vcodec) { 77 | pub->video_jb = g_malloc0(sizeof(janus_rtp_jb)); 78 | pub->video_jb->tb = 90000; 79 | pub->video_jb->pub = pub; 80 | pub->video_jb->buflen = JANUS_LIVE_BUFFER_MAX; 81 | pub->video_jb->received_frame = g_malloc0(pub->video_jb->buflen); 82 | } 83 | 84 | /* thread start */ 85 | int id; 86 | char tname[32]; 87 | GError *error = NULL; 88 | 89 | id = 1; 90 | memset(tname, 0, 32); 91 | g_snprintf(tname, sizeof(tname), "jitter event loop, id:%d", id); 92 | janus_live_event_loop_init(pub, &pub->jb_loop, id, tname); 93 | if(pub->jb_loop){ 94 | pub->jb_src = g_timeout_source_new(50); 95 | g_source_set_priority(pub->jb_src, G_PRIORITY_DEFAULT); 96 | g_source_set_callback(pub->jb_src, janus_rtp_jb_handle, pub, NULL); 97 | g_source_attach(pub->jb_src, pub->jb_loop->mainctx); 98 | } 99 | 100 | id = 2; 101 | memset(tname, 0, 32); 102 | g_snprintf(tname, sizeof(tname), "rtmp send event loop, id:%d", id); 103 | janus_live_event_loop_init(pub, &pub->pub_loop, id, tname); 104 | if(pub->pub_loop){ 105 | pub->pub_src = g_timeout_source_new(50); 106 | g_source_set_priority(pub->pub_src, G_PRIORITY_DEFAULT); 107 | g_source_set_callback(pub->pub_src, janus_live_send_handle, pub, NULL); 108 | g_source_attach(pub->pub_src, pub->pub_loop->mainctx); 109 | } 110 | 111 | janus_mutex_init(&pub->mutex); 112 | janus_mutex_init(&pub->mutex_live); 113 | /* Done */ 114 | g_atomic_int_set(&pub->destroyed, 0); 115 | janus_refcount_init(&pub->ref, janus_live_pub_free); 116 | return pub; 117 | } 118 | 119 | 120 | void 121 | janus_live_event_loop_init(janus_live_pub *pub, janus_live_el **el, int id, char* name) 122 | { 123 | GError *error = NULL; 124 | janus_live_el *loop = NULL; 125 | 126 | loop = g_malloc0(sizeof(janus_live_el)); 127 | loop->id = id; 128 | loop->mainctx = g_main_context_new(); 129 | loop->mainloop = g_main_loop_new(loop->mainctx, FALSE); 130 | loop->name = g_strdup(name); 131 | loop->pub = pub; 132 | loop->thread = g_thread_try_new(loop->name, 133 | &janus_live_event_loop_thread,loop, &error); 134 | if(error != NULL) { 135 | g_free(loop->name); 136 | loop->name = NULL; 137 | loop->pub = NULL; 138 | g_main_loop_unref(loop->mainloop); 139 | g_main_context_unref(loop->mainctx); 140 | g_free(loop); 141 | JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch a new event loop thread,id:%d,name:%s\n", 142 | error->code, error->message ? error->message : "??", id, name); 143 | *el = NULL; 144 | return; 145 | } 146 | 147 | *el = loop; 148 | return; 149 | } 150 | 151 | 152 | int 153 | janus_live_pub_save_frame(janus_live_pub *pub, char *buffer, uint length, gboolean video, int slot) 154 | { 155 | if(!pub) 156 | return -1; 157 | if(!buffer || length < 1) { 158 | return -2; 159 | } 160 | if(!pub->url) { 161 | return -3; 162 | } 163 | 164 | janus_rtp_jb *jb = video ? pub->video_jb : pub->audio_jb; 165 | if(!jb){ 166 | return -4; 167 | } 168 | /* Write frame header */ 169 | uint64_t max32 = UINT32_MAX; 170 | int skip = 0; 171 | int audiolevel = 0, rotation = 0, last_rotation = -1, rotated = -1; 172 | janus_rtp_header *rtp = (janus_rtp_header *)buffer; 173 | JANUS_LOG(LOG_INFO, "%s RTP packet, ssrc:%u, type:%d, sequence:%d, timestamp:%u, ext:%d\n", 174 | video ? "Video" : "Audio", ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp)*1000/jb->tb, rtp->extension); 175 | 176 | if(rtp->csrccount) { 177 | JANUS_LOG(LOG_VERB, " -- -- Skipping CSRC list\n"); 178 | skip += rtp->csrccount*4; 179 | } 180 | audiolevel = -1; 181 | rotation = -1; 182 | if(rtp->extension) { 183 | janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buffer+12+skip); 184 | JANUS_LOG(LOG_VERB, " -- -- RTP extension (type=0x%"PRIX16", length=%"SCNu16")\n", 185 | ntohs(ext->type), ntohs(ext->length)); 186 | skip += 4 + ntohs(ext->length)*4; 187 | if(pub->audio_level_extmap_id > 0) 188 | janus_live_rtp_header_extension_parse_audio_level(buffer, length, pub->audio_level_extmap_id, &audiolevel); 189 | if(pub->video_orient_extmap_id > 0) { 190 | janus_live_rtp_header_extension_parse_video_orientation(buffer, length, pub->video_orient_extmap_id, &rotation); 191 | if(rotation != -1 && rotation != last_rotation) { 192 | last_rotation = rotation; 193 | rotated++; 194 | } 195 | } 196 | } 197 | if(jb->ssrc == 0) { 198 | jb->ssrc = ntohl(rtp->ssrc); 199 | JANUS_LOG(LOG_INFO, "SSRC detected: %"SCNu32"\n", jb->ssrc); 200 | } 201 | if(jb->ssrc != ntohl(rtp->ssrc)) { 202 | JANUS_LOG(LOG_WARN, "Dropping packet with unexpected SSRC: %"SCNu32" != %"SCNu32"\n", 203 | ntohl(rtp->ssrc), jb->ssrc); 204 | return -5; 205 | } 206 | 207 | /* Generate frame packet and insert in the ordered list */ 208 | janus_frame_packet *p = janus_packet_alloc(length); 209 | p->created = janus_get_real_time(); 210 | memcpy(p->data, buffer, length); 211 | p->video = video; 212 | p->ssrc = ntohl(rtp->ssrc); 213 | p->seq = ntohs(rtp->seq_number); 214 | p->pt = rtp->type; 215 | //p->len = length; 216 | p->drop = 0; 217 | /* Due to resets, we need to mess a bit with the original timestamps */ 218 | if(jb->last_ts == 0 && jb->start_ts == 0 && jb->start_sys == 0) { 219 | /* Simple enough... */ 220 | p->ts = ntohl(rtp->timestamp); 221 | jb->start_ts = ntohl(rtp->timestamp); 222 | jb->start_sys = janus_get_real_time(); 223 | } else { 224 | /* Is the new timestamp smaller than the next one, and if so, is it a timestamp reset or simply out of order? */ 225 | gboolean late_pkt = FALSE; 226 | if(ntohl(rtp->timestamp) < jb->last_ts && (jb->last_ts-ntohl(rtp->timestamp) > 2*1000*1000*1000)) { 227 | if(jb->post_reset_pkts > post_reset_trigger) { 228 | jb->reset = ntohl(rtp->timestamp); 229 | JANUS_LOG(LOG_WARN, "Timestamp reset: %"SCNu32"\n", jb->reset); 230 | jb->times_resetted++; 231 | jb->post_reset_pkts = 0; 232 | } 233 | } else if(ntohl(rtp->timestamp) > jb->reset && ntohl(rtp->timestamp) > jb->last_ts && 234 | (ntohl(rtp->timestamp)-jb->last_ts > 2*1000*1000*1000)) { 235 | if(jb->post_reset_pkts < post_reset_trigger) { 236 | JANUS_LOG(LOG_WARN, "Late pre-reset packet after a timestamp reset: %"SCNu32"\n", ntohl(rtp->timestamp)); 237 | late_pkt = TRUE; 238 | jb->times_resetted--; 239 | } 240 | } else if(ntohl(rtp->timestamp) < jb->reset) { 241 | if(jb->post_reset_pkts < post_reset_trigger) { 242 | JANUS_LOG(LOG_WARN, "Updating latest timestamp reset: %"SCNu32" (was %"SCNu32")\n", ntohl(rtp->timestamp), jb->reset); 243 | jb->reset = ntohl(rtp->timestamp); 244 | } else { 245 | jb->reset = ntohl(rtp->timestamp); 246 | JANUS_LOG(LOG_WARN, "Timestamp reset: %"SCNu32"\n", jb->reset); 247 | jb->times_resetted++; 248 | jb->post_reset_pkts = 0; 249 | } 250 | } 251 | /* Take into account the number of resets when setting the internal, 64-bit, timestamp */ 252 | p->ts = (jb->times_resetted*max32)+ntohl(rtp->timestamp); 253 | if(late_pkt) 254 | jb->times_resetted++; 255 | } 256 | if(rtp->padding) { 257 | /* There's padding data, let's check the last byte to see how much data we should skip */ 258 | uint8_t padlen = (uint8_t)buffer[length - 1]; 259 | JANUS_LOG(LOG_VERB, "Padding at sequence number %hu: %d/%d\n", 260 | ntohs(rtp->seq_number), padlen, length); 261 | p->len -= padlen; 262 | if((p->len - skip - 12) <= 0) { 263 | /* Only padding, take note that we should drop the packet later */ 264 | p->drop = 1; 265 | JANUS_LOG(LOG_VERB, " -- All padding, marking packet as dropped\n"); 266 | } 267 | } 268 | if(p->len <= 12) { 269 | /* Only header? take note that we should drop the packet later */ 270 | p->drop = 1; 271 | JANUS_LOG(LOG_VERB, " -- Only RTP header, marking packet as dropped\n"); 272 | } 273 | jb->last_ts = ntohl(rtp->timestamp); 274 | if(ntohs(rtp->seq_number) != jb->last_seq + 1){ 275 | JANUS_LOG(LOG_VERB, "input %d sequence unorder, last:%d, curr:%d\n", video ? "Video" : "Audio", jb->last_seq, ntohs(rtp->seq_number)); 276 | } 277 | jb->last_seq = ntohs(rtp->seq_number); 278 | jb->post_reset_pkts++; 279 | /* Fill in the rest of the details */ 280 | p->skip = skip; 281 | p->audiolevel = audiolevel; 282 | p->rotation = rotation; 283 | p->next = NULL; 284 | p->prev = NULL; 285 | 286 | if(video) 287 | JANUS_LOG(LOG_VERB, "janus_live_pub_save_frame video ts: %"SCNu64"\n", p->ts); 288 | 289 | janus_mutex_lock_nodebug(&pub->mutex); 290 | if(jb->list == NULL) { 291 | /* First element becomes the list itself (and the last item), at least for now */ 292 | jb->list = p; 293 | jb->last = p; 294 | } else if(!p->drop) { 295 | /* Check where we should insert this, starting from the end */ 296 | int added = 0; 297 | janus_frame_packet *tmp = jb->last; 298 | while(tmp) { 299 | if(tmp->ts < p->ts) { 300 | /* The new timestamp is greater than the last one we have, append */ 301 | added = 1; 302 | if(tmp->next != NULL) { 303 | /* We're inserting */ 304 | tmp->next->prev = p; 305 | p->next = tmp->next; 306 | } else { 307 | /* Update the last packet */ 308 | jb->last = p; 309 | } 310 | tmp->next = p; 311 | p->prev = tmp; 312 | break; 313 | } else if(tmp->ts == p->ts) { 314 | /* Same timestamp, check the sequence number */ 315 | if(tmp->seq < p->seq && (abs(tmp->seq - p->seq) < 10000)) { 316 | /* The new sequence number is greater than the last one we have, append */ 317 | added = 1; 318 | if(tmp->next != NULL) { 319 | /* We're inserting */ 320 | tmp->next->prev = p; 321 | p->next = tmp->next; 322 | } else { 323 | /* Update the last packet */ 324 | jb->last = p; 325 | } 326 | tmp->next = p; 327 | p->prev = tmp; 328 | break; 329 | } else if(tmp->seq > p->seq && (abs(tmp->seq - p->seq) > 10000)) { 330 | /* The new sequence number (resetted) is greater than the last one we have, append */ 331 | added = 1; 332 | if(tmp->next != NULL) { 333 | /* We're inserting */ 334 | tmp->next->prev = p; 335 | p->next = tmp->next; 336 | } else { 337 | /* Update the last packet */ 338 | jb->last = p; 339 | } 340 | tmp->next = p; 341 | p->prev = tmp; 342 | break; 343 | } else if(tmp->seq == p->seq) { 344 | /* Maybe a retransmission? Skip */ 345 | JANUS_LOG(LOG_WARN, "Skipping duplicate packet (seq=%"SCNu16")\n", p->seq); 346 | p->drop = 1; 347 | break; 348 | } 349 | } 350 | /* If either the timestamp ot the sequence number we just got is smaller, keep going back */ 351 | tmp = tmp->prev; 352 | } 353 | if(p->drop) { 354 | /* We don't need this */ 355 | janus_packet_free(p); 356 | } else if(!added) { 357 | /* We reached the start */ 358 | p->next = jb->list; 359 | jb->list->prev = p; 360 | jb->list = p; 361 | } 362 | } 363 | /* list size add */ 364 | if(!p->drop) 365 | jb->size++; 366 | /* Done */ 367 | janus_mutex_unlock_nodebug(&pub->mutex); 368 | return 0; 369 | } 370 | 371 | 372 | void * 373 | janus_live_event_loop_thread(void *data) 374 | { 375 | janus_live_el *loop = data; 376 | janus_live_pub *pub = (janus_live_pub *)loop->pub; 377 | 378 | JANUS_LOG(LOG_VERB, "[loop#%d] Event loop [%s] thread started\n", loop->id, loop->name); 379 | if(loop->mainloop == NULL) { 380 | JANUS_LOG(LOG_ERR, "[loop#%d] Invalid loop...\n", loop->id); 381 | g_thread_unref(g_thread_self()); 382 | return NULL; 383 | } 384 | JANUS_LOG(LOG_DBG, "[loop#%d] Looping...\n", loop->id); 385 | g_main_loop_run(loop->mainloop); 386 | /* When the loop quits, we can unref it */ 387 | g_main_loop_unref(loop->mainloop); 388 | g_main_context_unref(loop->mainctx); 389 | JANUS_LOG(LOG_VERB, "[loop#%d] Event loop [%s] thread ended!\n", loop->id, loop->name); 390 | return NULL; 391 | } 392 | 393 | 394 | gboolean 395 | janus_rtp_jb_handle(gpointer user_data) 396 | { 397 | janus_live_pub *pub = (janus_live_pub *)user_data; 398 | gint64 now = janus_get_real_time(); 399 | janus_frame_packet *tmp = NULL, *head = NULL; 400 | janus_rtp_jb *jb = NULL; 401 | 402 | /*audio */ 403 | janus_mutex_lock_nodebug(&pub->mutex); 404 | head = pub->audio_jb->list; 405 | while(head){ 406 | jb = pub->audio_jb; 407 | gint64 gap = (now - jb->start_sys) - (1000 * (head->ts - jb->start_ts)*1000/jb->tb); 408 | gint64 timetout = now - head->created; 409 | if(now - head->created > G_USEC_PER_SEC){ 410 | tmp = head->next; 411 | 412 | if(tmp){ 413 | tmp->prev = NULL; 414 | } 415 | head->next = NULL; 416 | pub->audio_jb->size--; 417 | 418 | JANUS_LOG(LOG_INFO, "janus_rtp_jb_handle, audio sequence:%d, gap:%"SCNu64", timeout:%"SCNu64"\n", head->seq, gap/1000, timetout/1000); 419 | if(head->seq != pub->audio_jb->last_seq_out + 1){ 420 | JANUS_LOG(LOG_WARN, "output %d sequence unorder, last:%d, curr:%d\n", "Audio", pub->audio_jb->last_seq_out, head->seq); 421 | } 422 | pub->audio_jb->last_seq_out = head->seq; 423 | 424 | /* opus unpack */ 425 | int len = 0; 426 | char *buffer = janus_rtp_payload(head->data, head->len, &len); 427 | JANUS_LOG(LOG_INFO, "audio frame len: %d\n", len); 428 | if(jb->adecoder){ 429 | janus_live_opus_decoder_decode(jb->adecoder, head->data, head->len); 430 | } 431 | 432 | janus_packet_free(head); 433 | head = tmp; 434 | }else{ 435 | break; 436 | } 437 | } 438 | pub->audio_jb->list = head; 439 | janus_mutex_unlock_nodebug(&pub->mutex); 440 | 441 | /*video */ 442 | janus_mutex_lock_nodebug(&pub->mutex); 443 | head = pub->video_jb->list; 444 | while(head){ 445 | jb = pub->video_jb; 446 | gint64 gap = (now - jb->start_sys) - (1000 * (head->ts - jb->start_ts)*1000/jb->tb); 447 | gint64 timetout = now - head->created; 448 | if(now - head->created > G_USEC_PER_SEC){ 449 | tmp = head->next; 450 | 451 | if(tmp){ 452 | tmp->prev = NULL; 453 | } 454 | head->next = NULL; 455 | pub->video_jb->size--; 456 | 457 | JANUS_LOG(LOG_INFO, "janus_rtp_jb_handle, video sequence:%d, gap:%"SCNu64", timeout:%"SCNu64"\n", head->seq, gap/1000, timetout/1000); 458 | if(head->seq != pub->video_jb->last_seq_out + 1){ 459 | JANUS_LOG(LOG_WARN, "output %d sequence unorder, last:%d, curr:%d\n", "Video", pub->video_jb->last_seq_out, head->seq); 460 | } 461 | pub->video_jb->last_seq_out = head->seq; 462 | 463 | /* h264 unpack */ 464 | if(!head->drop){ 465 | if(pub->video_jb->ts != head->ts && pub->video_jb->frameLen) { 466 | uint8_t type = *(pub->video_jb->received_frame + 3) & 0x1F; 467 | 468 | janus_frame_packet *p = janus_packet_alloc(pub->video_jb->frameLen + FF_INPUT_BUFFER_PADDING_SIZE); 469 | p->created = now; 470 | memcpy(p->data, pub->video_jb->received_frame, pub->video_jb->frameLen); 471 | p->video = TRUE; 472 | p->keyFrame = pub->video_jb->keyFrame; 473 | p->ts = pub->video_jb->ts *1000/jb->tb; 474 | JANUS_LOG(LOG_INFO, "video frame len: %d, nalu type:%d, rtpts:%"SCNu64", ts:%"SCNu64"\n", 475 | pub->video_jb->frameLen, type, pub->video_jb->ts, p->ts); 476 | 477 | janus_live_packet_insert(pub, p); 478 | pub->video_jb->frameLen = 0; 479 | pub->video_jb->keyFrame = 0; 480 | } 481 | 482 | janus_live_rtp_unpack(pub->video_jb, head, TRUE); 483 | pub->video_jb->ts = head->ts; 484 | } 485 | janus_packet_free(head); 486 | head = tmp; 487 | }else{ 488 | break; 489 | } 490 | } 491 | pub->video_jb->list = head; 492 | janus_mutex_unlock_nodebug(&pub->mutex); 493 | 494 | JANUS_LOG(LOG_INFO, "janus_rtp_jb_handle, ajb:%d, vjb:%d\n", pub->audio_jb->size, pub->video_jb->size); 495 | return G_SOURCE_CONTINUE; 496 | } 497 | 498 | 499 | int 500 | janus_live_packet_insert(janus_live_pub *pub, janus_frame_packet *p) 501 | { 502 | janus_mutex_lock_nodebug(&pub->mutex_live); 503 | if(pub->start_ts == 0 && pub->start_sys == 0) { 504 | pub->start_ts = p->ts; 505 | pub->start_sys = janus_get_real_time(); 506 | } 507 | JANUS_LOG(LOG_INFO, "janus_live_packet_insert, ts:%"SCNu64", len:%d, size:%d\n", p->ts, p->len, pub->size); 508 | if(pub->list == NULL) { 509 | /* First element becomes the list itself (and the last item), at least for now */ 510 | pub->list = p; 511 | pub->last = p; 512 | } else if(!p->drop) { 513 | /* Check where we should insert this, starting from the end */ 514 | int added = 0; 515 | janus_frame_packet *tmp = pub->last; 516 | while(tmp) { 517 | if(tmp->ts <= p->ts) { 518 | /* The new timestamp is greater than the last one we have, append */ 519 | added = 1; 520 | if(tmp->next != NULL) { 521 | /* We're inserting */ 522 | tmp->next->prev = p; 523 | p->next = tmp->next; 524 | } else { 525 | /* Update the last packet */ 526 | pub->last = p; 527 | } 528 | tmp->next = p; 529 | p->prev = tmp; 530 | break; 531 | } 532 | /* If either the timestamp ot the sequence number we just got is smaller, keep going back */ 533 | tmp = tmp->prev; 534 | } 535 | if(!added) { 536 | /* We reached the start */ 537 | p->next = pub->list; 538 | pub->list->prev = p; 539 | pub->list = p; 540 | } 541 | } 542 | /* list size add */ 543 | pub->size++; 544 | janus_mutex_unlock_nodebug(&pub->mutex_live); 545 | } 546 | 547 | 548 | void 549 | janus_live_rtp_unpack(janus_rtp_jb *jb, janus_frame_packet *packet, gboolean video) 550 | { 551 | janus_live_pub *pub = jb->pub; 552 | int len = 0; 553 | char *buffer = janus_rtp_payload(packet->data, packet->len, &len); 554 | if(len < 1) { 555 | return; 556 | } 557 | 558 | if((buffer[0] & 0x1F) == 7) { 559 | /* SPS, see if we can extract the width/height as well */ 560 | int width = 0, height = 0; 561 | janus_live_h264_parse_sps(buffer, &width, &height); 562 | JANUS_LOG(LOG_VERB, "Parsing width/height: %dx%d\n", width, height); 563 | if(width > pub->max_width) 564 | pub->max_width = width; 565 | if(height > pub->max_height) 566 | pub->max_height = height; 567 | } else if((buffer[0] & 0x1F) == 24) { 568 | /* May we find an SPS in this STAP-A? */ 569 | JANUS_LOG(LOG_HUGE, "Parsing STAP-A...\n"); 570 | char *buf = buffer; 571 | buf++; 572 | int tot = len-1; 573 | uint16_t psize = 0; 574 | while(tot > 0) { 575 | memcpy(&psize, buf, 2); 576 | psize = ntohs(psize); 577 | buf += 2; 578 | tot -= 2; 579 | int nal = *buf & 0x1F; 580 | JANUS_LOG(LOG_HUGE, " -- NALU of size %u: %d\n", psize, nal); 581 | if(nal == 7) { 582 | int width = 0, height = 0; 583 | janus_live_h264_parse_sps(buf, &width, &height); 584 | JANUS_LOG(LOG_VERB, "Parsing width/height: %dx%d\n", width, height); 585 | if(width > pub->max_width) 586 | pub->max_width = width; 587 | if(height > pub->max_height) 588 | pub->max_height = height; 589 | } 590 | buf += psize; 591 | tot -= psize; 592 | } 593 | } 594 | 595 | if(!pub->init_flag && pub->max_width && pub->max_height) { 596 | int rc = janus_live_ffmpeg_init(pub); 597 | if(rc == 0) 598 | pub->init_flag = TRUE; 599 | } 600 | 601 | /* H.264 depay */ 602 | int jump = 0; 603 | uint8_t fragment = *buffer & 0x1F; 604 | uint8_t nal = *(buffer+1) & 0x1F; 605 | uint8_t start_bit = *(buffer+1) & 0x80; 606 | uint8_t end_bit = *(buffer+1) & 0x40; 607 | if(fragment == 28 || fragment == 29) 608 | JANUS_LOG(LOG_HUGE, "%s Fragment=%d, NAL=%d, Start=%d End=%d (len=%d, frameLen=%d)\n", 609 | video ? "video" : "audio", fragment, nal, start_bit, end_bit, len, jb->frameLen); 610 | else 611 | JANUS_LOG(LOG_HUGE, "%s Fragment=%d (len=%d, frameLen=%d)\n", video ? "video" : "audio", fragment, len, jb->frameLen); 612 | if(fragment == 5 || 613 | ((fragment == 28 || fragment == 29) && nal == 5 && start_bit == 128)) { 614 | JANUS_LOG(LOG_VERB, "(seq=%"SCNu16", ts=%"SCNu64") Key frame\n", packet->seq, packet->ts); 615 | jb->keyFrame = 1; 616 | /* Is this the first keyframe we find? */ 617 | if(!jb->keyframe_found) { 618 | jb->keyframe_found = TRUE; 619 | JANUS_LOG(LOG_INFO, "First keyframe: %"SCNu64"\n", packet->ts - jb->start_ts); 620 | } 621 | } 622 | /* Frame manipulation */ 623 | if((fragment > 0) && (fragment < 24)) { /* Add a start code */ 624 | uint8_t *temp = jb->received_frame + jb->frameLen; 625 | memset(temp, 0x00, 1); 626 | memset(temp + 1, 0x00, 1); 627 | memset(temp + 2, 0x01, 1); 628 | jb->frameLen += 3; 629 | } else if(fragment == 24) { /* STAP-A */ 630 | /* De-aggregate the NALs and write each of them separately */ 631 | buffer++; 632 | int tot = len-1; 633 | uint16_t psize = 0; 634 | while(tot > 0) { 635 | memcpy(&psize, buffer, 2); 636 | psize = ntohs(psize); 637 | buffer += 2; 638 | tot -= 2; 639 | /* Now we have a single NAL */ 640 | uint8_t *temp = jb->received_frame + jb->frameLen; 641 | memset(temp, 0x00, 1); 642 | memset(temp + 1, 0x00, 1); 643 | memset(temp + 2, 0x01, 1); 644 | // memset(temp + 3, 0x01, 1); 645 | jb->frameLen += 3; 646 | memcpy(jb->received_frame + jb->frameLen, buffer, psize); 647 | jb->frameLen += psize; 648 | /* Go on */ 649 | buffer += psize; 650 | tot -= psize; 651 | } 652 | return; 653 | 654 | } else if((fragment == 28) || (fragment == 29)) { /* FIXME true fr FU-A, not FU-B */ 655 | uint8_t indicator = *buffer; 656 | uint8_t header = *(buffer+1); 657 | jump = 2; 658 | len -= 2; 659 | if(header & 0x80) { 660 | /* First part of fragmented packet (S bit set) */ 661 | uint8_t *temp = jb->received_frame + jb->frameLen; 662 | memset(temp, 0x00, 1); 663 | memset(temp + 1, 0x00, 1); 664 | memset(temp + 2, 0x01, 1); 665 | memset(temp + 3, (indicator & 0xE0) | (header & 0x1F), 1); 666 | jb->frameLen += 4; 667 | } else if (header & 0x40) { 668 | /* Last part of fragmented packet (E bit set) */ 669 | } 670 | } 671 | memcpy(jb->received_frame + jb->frameLen, buffer+jump, len); 672 | jb->frameLen += len; 673 | if(len == 0){ 674 | JANUS_LOG(LOG_ERR, "nalu is null\n"); 675 | } 676 | } 677 | 678 | 679 | gboolean 680 | janus_live_send_handle(gpointer user_data) 681 | { 682 | janus_live_pub *pub = (janus_live_pub *)user_data; 683 | gint64 now = janus_get_real_time(); 684 | janus_frame_packet *tmp = NULL, *head = NULL; 685 | /*audio */ 686 | janus_mutex_lock_nodebug(&pub->mutex_live); 687 | head = pub->list; 688 | while(head){ 689 | gint64 gap = (now - pub->start_sys) - (1000 * (head->ts - pub->start_ts)); 690 | gint64 timetout = now - head->created; 691 | if(now - head->created > G_USEC_PER_SEC) { 692 | tmp = head->next; 693 | 694 | if(tmp){ 695 | tmp->prev = NULL; 696 | } 697 | head->next = NULL; 698 | pub->size--; 699 | 700 | JANUS_LOG(LOG_INFO, "janus_live_send_handle, %s packet len:%d," 701 | " ts:%"SCNu64", gap:%"SCNu64", timeout:%"SCNu64", list:%d\n", 702 | head->video ? "video":"audio",head->len,head->ts, 703 | gap/1000, timetout/1000, pub->size); 704 | 705 | if(head->len > 0) { 706 | if(head->video){ 707 | /* Save the frame */ 708 | AVPacket *packet = av_packet_alloc(); 709 | av_init_packet(packet); 710 | packet->stream_index = 0; 711 | packet->data = head->data; 712 | packet->size = head->len; 713 | if(head->keyFrame) 714 | packet->flags |= AV_PKT_FLAG_KEY; 715 | 716 | packet->dts = (uint32_t)head->ts; 717 | packet->pts = (uint32_t)head->ts; 718 | if(pub->fctx) { 719 | int res = av_interleaved_write_frame(pub->fctx, packet); 720 | if(res < 0) { 721 | JANUS_LOG(LOG_ERR, "Error writing video frame to file... (error %d)\n", res); 722 | } 723 | } 724 | av_packet_free(&packet); 725 | JANUS_LOG(LOG_INFO, "rtmp video packet (len:%d) tb:%d pts:%d listsize:%d\n", head->len, pub->vStream->time_base.den, head->ts, pub->size); 726 | }else{ 727 | AVPacket *packet = av_packet_alloc(); 728 | av_init_packet(packet); 729 | packet->stream_index = 1; 730 | packet->data = head->data; 731 | packet->size = head->len; 732 | packet->dts = (uint32_t)head->ts; 733 | packet->pts = (uint32_t)head->ts; 734 | av_bitstream_filter_filter(pub->aacbsf, pub->aStream->codec, NULL, &packet->data, &packet->size, packet->data, packet->size, 0); 735 | if(pub->fctx) { 736 | int res = av_write_frame(pub->fctx, packet); 737 | if(res < 0) { 738 | JANUS_LOG(LOG_ERR, "Error writing audio frame to file... (error %d)\n", res); 739 | } 740 | } 741 | av_free(packet->data); /* https://blog.csdn.net/bikeytang/article/details/60883987# */ 742 | av_packet_free(&packet); 743 | JANUS_LOG(LOG_INFO, "rtmp audio packet (len:%d) tb:%d pts:%d listsize:%d\n", head->len, pub->aStream->time_base.den, head->ts, pub->size); 744 | } 745 | } 746 | 747 | janus_packet_free(head); 748 | head = tmp; 749 | }else{ 750 | break; 751 | } 752 | } 753 | pub->list = head; 754 | janus_mutex_unlock_nodebug(&pub->mutex_live); 755 | 756 | return G_SOURCE_CONTINUE; 757 | } 758 | 759 | int 760 | janus_live_ffmpeg_free(janus_live_pub *pub) 761 | { 762 | if(pub->fctx != NULL) 763 | av_write_trailer(pub->fctx); 764 | 765 | #ifdef USE_CODECPAR 766 | if(pub->vEncoder != NULL) 767 | avcodec_close(pub->vEncoder); 768 | if(pub->aEncoder != NULL) 769 | avcodec_close(pub->aEncoder); 770 | #else 771 | if(pub->vStream != NULL && pub->vStream->codec != NULL) 772 | avcodec_close(pub->vStream->codec); 773 | #endif 774 | 775 | if(pub->fctx != NULL && pub->fctx->streams[0] != NULL) { 776 | #ifndef USE_CODECPAR 777 | av_free(pub->fctx->streams[0]->codec); 778 | #endif 779 | av_free(pub->fctx->streams[0]); 780 | av_free(pub->fctx->streams[1]); 781 | } 782 | 783 | if(pub->fctx != NULL) { 784 | avio_close(pub->fctx->pb); 785 | av_free(pub->fctx); 786 | } 787 | if(pub->aacbsf != NULL) { 788 | av_bitstream_filter_close(pub->aacbsf); 789 | pub->aacbsf = NULL; 790 | } 791 | return 0; 792 | } 793 | 794 | 795 | int 796 | janus_live_ffmpeg_init(janus_live_pub *pub) 797 | { 798 | /* Setup FFmpeg */ 799 | av_register_all(); 800 | /* Adjust logging to match the postprocessor's */ 801 | av_log_set_level(janus_log_level <= LOG_NONE ? AV_LOG_QUIET : 802 | (janus_log_level == LOG_FATAL ? AV_LOG_FATAL : 803 | (janus_log_level == LOG_ERR ? AV_LOG_ERROR : 804 | (janus_log_level == LOG_WARN ? AV_LOG_WARNING : 805 | (janus_log_level == LOG_INFO ? AV_LOG_INFO : 806 | (janus_log_level == LOG_VERB ? AV_LOG_VERBOSE : AV_LOG_DEBUG)))))); 807 | pub->aacbsf = av_bitstream_filter_init("aac_adtstoasc"); 808 | if(pub->aacbsf == NULL) { 809 | JANUS_LOG(LOG_ERR, "Error allocating aac_adtstoasc\n"); 810 | return -1; 811 | } 812 | /* rtmp output */ 813 | pub->fctx = avformat_alloc_context(); 814 | if(pub->fctx == NULL) { 815 | JANUS_LOG(LOG_ERR, "Error allocating context\n"); 816 | return -1; 817 | } 818 | const char* metadata = "bepartfoyou (七曦)"; 819 | /* We save the metadata part as a comment (see #1189) */ 820 | if(metadata) 821 | av_dict_set(&pub->fctx->metadata, "comment", metadata, 0); 822 | pub->fctx->oformat = av_guess_format("flv", NULL, NULL); 823 | if(pub->fctx->oformat == NULL) { 824 | JANUS_LOG(LOG_ERR, "Error guessing format\n"); 825 | return -1; 826 | } 827 | snprintf(pub->fctx->filename, sizeof(pub->fctx->filename), "%s", pub->url); 828 | #ifdef USE_CODECPAR 829 | /*video */ 830 | AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264); 831 | if(!codec) { 832 | /* Error opening video codec */ 833 | JANUS_LOG(LOG_ERR, "Encoder not available\n"); 834 | return -1; 835 | } 836 | pub->fctx->video_codec = codec; 837 | pub->fctx->oformat->video_codec = codec->id; 838 | pub->vStream = avformat_new_stream(pub->fctx, codec); 839 | // pub->vStream->id = pub->fctx->nb_streams - 1; 840 | pub->vStream->id = 0; 841 | pub->vEncoder = avcodec_alloc_context3(codec); 842 | pub->vEncoder->width = pub->max_width; 843 | pub->vEncoder->height = pub->max_height; 844 | pub->vEncoder->time_base = (AVRational){ 1, 25 }; 845 | pub->vEncoder->pix_fmt = AV_PIX_FMT_YUV420P; 846 | pub->vEncoder->flags |= CODEC_FLAG_GLOBAL_HEADER; 847 | if(avcodec_open2(pub->vEncoder, codec, NULL) < 0) { 848 | /* Error opening video codec */ 849 | JANUS_LOG(LOG_ERR, "Encoder error\n"); 850 | return -1; 851 | } 852 | avcodec_parameters_from_context(pub->vStream->codecpar, pub->vEncoder); 853 | 854 | /*audio */ 855 | AVCodec *acodec = avcodec_find_encoder_by_name("libfdk_aac"); 856 | if(!acodec) { 857 | /* Error opening video codec */ 858 | JANUS_LOG(LOG_ERR, "Encoder not available\n"); 859 | return -1; 860 | } 861 | pub->fctx->audio_codec = acodec; 862 | pub->fctx->oformat->audio_codec = acodec->id; 863 | pub->aStream = avformat_new_stream(pub->fctx, acodec); 864 | //pub->vStream->id = pub->fctx->nb_streams-1; 865 | pub->aStream->id = 1; 866 | pub->aEncoder = avcodec_alloc_context3(acodec); 867 | pub->aEncoder->codec_type = AVMEDIA_TYPE_AUDIO; 868 | pub->aEncoder->sample_rate = 48000; 869 | pub->aEncoder->bit_rate = 128 * 1000; 870 | pub->aEncoder->bit_rate_tolerance = 128 * 1000 * 3 / 2; 871 | pub->aEncoder->channels = 2; 872 | pub->aEncoder->channel_layout = AV_CH_LAYOUT_STEREO; 873 | pub->aEncoder->time_base.num = 1; 874 | pub->aEncoder->time_base.den = pub->aEncoder->sample_rate; 875 | pub->aEncoder->sample_fmt = AV_SAMPLE_FMT_S16; 876 | pub->aEncoder->flags |= CODEC_FLAG_GLOBAL_HEADER; 877 | if(avcodec_open2(pub->aEncoder, acodec, NULL) < 0) { 878 | /* Error opening video codec */ 879 | JANUS_LOG(LOG_ERR, "Encoder error\n"); 880 | return -1; 881 | } 882 | avcodec_parameters_from_context(pub->aStream->codecpar, pub->aEncoder); 883 | #else 884 | 885 | pub->vStream = avformat_new_stream(pub->fctx, 0); 886 | if(pub->vStream == NULL) { 887 | JANUS_LOG(LOG_ERR, "Error adding stream\n"); 888 | return -1; 889 | } 890 | #if LIBAVCODEC_VER_AT_LEAST(53, 21) 891 | avcodec_get_context_defaults3(pub->vStream->codec, AVMEDIA_TYPE_VIDEO); 892 | #else 893 | avcodec_get_context_defaults2(pub->vStream->codec, AVMEDIA_TYPE_VIDEO); 894 | #endif 895 | #if LIBAVCODEC_VER_AT_LEAST(54, 25) 896 | pub->vStream->codec->codec_id = AV_CODEC_ID_H264; 897 | #else 898 | pub->vStream->codec->codec_id = CODEC_ID_H264; 899 | #endif 900 | pub->vStream->codec->codec_type = AVMEDIA_TYPE_VIDEO; 901 | pub->vStream->codec->time_base = (AVRational){1, 25}; 902 | pub->vStream->time_base = (AVRational){1, 90000}; 903 | pub->vStream->codec->width = pub->max_width; 904 | pub->vStream->codec->height = pub->max_height; 905 | pub->vStream->codec->pix_fmt = PIX_FMT_YUV420P; 906 | //~ if (fctx->flags & AVFMT_GLOBALHEADER) 907 | pub->vStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 908 | #endif 909 | if(avio_open(&pub->fctx->pb, pub->fctx->filename, AVIO_FLAG_WRITE) < 0) { 910 | JANUS_LOG(LOG_ERR, "Error opening file for output\n"); 911 | return -1; 912 | } 913 | if(avformat_write_header(pub->fctx, NULL) < 0) { 914 | JANUS_LOG(LOG_ERR, "Error writing header\n"); 915 | return -1; 916 | } 917 | 918 | JANUS_LOG(LOG_ERR, "ffmpeg init success .....\n"); 919 | return 0; 920 | } 921 | 922 | 923 | void 924 | janus_rtp_jb_free(janus_live_pub *pub) 925 | { 926 | janus_mutex_lock_nodebug(&pub->mutex); 927 | janus_frame_packet *tmp = NULL, *head = NULL; 928 | /*audio */ 929 | head = pub->audio_jb->list; 930 | while(head){ 931 | tmp = head->next; 932 | if(tmp){ 933 | tmp->prev = NULL; 934 | } 935 | head->next = NULL; 936 | pub->audio_jb->size--; 937 | janus_packet_free(head); 938 | head = tmp; 939 | } 940 | pub->audio_jb->list = head; 941 | 942 | /*video */ 943 | head = pub->video_jb->list; 944 | while(head){ 945 | tmp = head->next; 946 | if(tmp){ 947 | tmp->prev = NULL; 948 | } 949 | head->next = NULL; 950 | pub->video_jb->size--; 951 | janus_packet_free(head); 952 | head = tmp; 953 | } 954 | pub->video_jb->list = head; 955 | if(pub->video_jb->received_frame){ 956 | g_free(pub->video_jb->received_frame); 957 | pub->video_jb->received_frame = NULL; 958 | } 959 | janus_mutex_unlock_nodebug(&pub->mutex); 960 | } 961 | 962 | 963 | janus_frame_packet * 964 | janus_packet_alloc(int data_len) 965 | { 966 | janus_frame_packet *pkt = g_malloc0(sizeof(janus_frame_packet)); 967 | memset(pkt, 0, sizeof(janus_frame_packet)); 968 | pkt->len = data_len; 969 | pkt->data = g_malloc0(pkt->len); 970 | 971 | return pkt; 972 | } 973 | 974 | 975 | void 976 | janus_packet_free(janus_frame_packet *pkt) 977 | { 978 | if(!pkt) 979 | return; 980 | if(pkt->data){ 981 | g_free(pkt->data); 982 | pkt->data = NULL; 983 | } 984 | g_free(pkt); 985 | pkt = NULL; 986 | } 987 | 988 | 989 | /* Static helper to quickly find the extension data */ 990 | static int 991 | janus_live_rtp_header_extension_find(char *buf, int len, int id, 992 | uint8_t *byte, uint32_t *word, char **ref) 993 | { 994 | if(!buf || len < 12) 995 | return -1; 996 | janus_rtp_header *rtp = (janus_rtp_header *)buf; 997 | int hlen = 12; 998 | if(rtp->csrccount) /* Skip CSRC if needed */ 999 | hlen += rtp->csrccount*4; 1000 | if(rtp->extension) { 1001 | janus_rtp_header_extension *ext = (janus_rtp_header_extension *)(buf+hlen); 1002 | int extlen = ntohs(ext->length)*4; 1003 | hlen += 4; 1004 | if(len > (hlen + extlen)) { 1005 | /* 1-Byte extension */ 1006 | if(ntohs(ext->type) == 0xBEDE) { 1007 | const uint8_t padding = 0x00, reserved = 0xF; 1008 | uint8_t extid = 0, idlen; 1009 | int i = 0; 1010 | while(i < extlen) { 1011 | extid = buf[hlen+i] >> 4; 1012 | if(extid == reserved) { 1013 | break; 1014 | } else if(extid == padding) { 1015 | i++; 1016 | continue; 1017 | } 1018 | idlen = (buf[hlen+i] & 0xF)+1; 1019 | if(extid == id) { 1020 | /* Found! */ 1021 | if(byte) 1022 | *byte = buf[hlen+i+1]; 1023 | if(word) 1024 | *word = ntohl(*(uint32_t *)(buf+hlen+i)); 1025 | if(ref) 1026 | *ref = &buf[hlen+i]; 1027 | return 0; 1028 | } 1029 | i += 1 + idlen; 1030 | } 1031 | } 1032 | hlen += extlen; 1033 | } 1034 | } 1035 | return -1; 1036 | } 1037 | 1038 | int 1039 | janus_live_rtp_header_extension_parse_audio_level(char *buf, int len, int id, int *level) 1040 | { 1041 | uint8_t byte = 0; 1042 | if(janus_live_rtp_header_extension_find(buf, len, id, &byte, NULL, NULL) < 0) 1043 | return -1; 1044 | /* a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level */ 1045 | int value = byte & 0x7F; 1046 | if(level) 1047 | *level = value; 1048 | return 0; 1049 | } 1050 | 1051 | 1052 | int 1053 | janus_live_rtp_header_extension_parse_video_orientation(char *buf, int len, int id, int *rotation) 1054 | { 1055 | uint8_t byte = 0; 1056 | if(janus_live_rtp_header_extension_find(buf, len, id, &byte, NULL, NULL) < 0) 1057 | return -1; 1058 | /* a=extmap:4 urn:3gpp:video-orientation */ 1059 | gboolean r1bit = (byte & 0x02) >> 1; 1060 | gboolean r0bit = byte & 0x01; 1061 | if(rotation) { 1062 | if(!r0bit && !r1bit) 1063 | *rotation = 0; 1064 | else if(r0bit && !r1bit) 1065 | *rotation = 90; 1066 | else if(!r0bit && r1bit) 1067 | *rotation = 180; 1068 | else if(r0bit && r1bit) 1069 | *rotation = 270; 1070 | } 1071 | return 0; 1072 | } 1073 | 1074 | 1075 | void 1076 | janus_live_pub_free(const janus_refcount *pub_ref) 1077 | { 1078 | janus_frame_packet *tmp = NULL, *head = NULL; 1079 | janus_live_pub *pub = janus_refcount_containerof(pub_ref, janus_live_pub, ref); 1080 | /* This pub can be destroyed, free all the resources */ 1081 | if(!pub->closed) 1082 | janus_live_pub_close(pub); 1083 | 1084 | g_free(pub->url); 1085 | pub->url = NULL; 1086 | if(pub->acodec){ 1087 | g_free(pub->acodec); 1088 | pub->acodec = NULL; 1089 | } 1090 | if(pub->vcodec){ 1091 | g_free(pub->vcodec); 1092 | pub->vcodec = NULL; 1093 | } 1094 | 1095 | janus_rtp_jb_free(pub); 1096 | janus_live_ffmpeg_free(pub); 1097 | head = pub->list; 1098 | while(head){ 1099 | tmp = head->next; 1100 | if(tmp){ 1101 | tmp->prev = NULL; 1102 | } 1103 | head->next = NULL; 1104 | pub->size--; 1105 | janus_packet_free(head); 1106 | head = tmp; 1107 | } 1108 | JANUS_LOG(LOG_WARN, "janus live pusblish release, list:%d\n", pub->size); 1109 | g_free(pub); 1110 | } 1111 | 1112 | 1113 | int 1114 | janus_live_pub_close(janus_live_pub *pub) 1115 | { 1116 | if(!pub) 1117 | return -1; 1118 | janus_mutex_lock_nodebug(&pub->mutex); 1119 | // jb thead stop 1120 | if(pub->jb_loop && pub->jb_loop->mainloop != NULL && 1121 | g_main_loop_is_running(pub->jb_loop->mainloop)){ 1122 | g_main_loop_quit(pub->jb_loop->mainloop); 1123 | 1124 | if(pub->jb_src) { 1125 | g_source_destroy(pub->jb_src); 1126 | g_source_unref(pub->jb_src); 1127 | pub->jb_src = NULL; 1128 | } 1129 | g_free(pub->jb_loop->name); 1130 | pub->jb_loop->name = NULL; 1131 | pub->jb_loop->pub = NULL; 1132 | g_main_loop_unref(pub->jb_loop->mainloop); 1133 | g_main_context_unref(pub->jb_loop->mainctx); 1134 | 1135 | pub->jb_loop->mainloop = NULL; 1136 | g_thread_join(pub->jb_loop->thread); 1137 | } 1138 | g_free(pub->jb_loop); 1139 | pub->jb_loop = NULL; 1140 | janus_mutex_unlock_nodebug(&pub->mutex); 1141 | 1142 | janus_mutex_lock_nodebug(&pub->mutex_live); 1143 | // live send thread stop 1144 | if(pub->pub_loop && pub->pub_loop->mainloop != NULL && 1145 | g_main_loop_is_running(pub->pub_loop->mainloop)){ 1146 | g_main_loop_quit(pub->pub_loop->mainloop); 1147 | 1148 | if(pub->pub_src) { 1149 | g_source_destroy(pub->pub_src); 1150 | g_source_unref(pub->pub_src); 1151 | pub->pub_src = NULL; 1152 | } 1153 | g_free(pub->pub_loop->name); 1154 | pub->pub_loop->name = NULL; 1155 | pub->pub_loop->pub = NULL; 1156 | g_main_loop_unref(pub->pub_loop->mainloop); 1157 | g_main_context_unref(pub->pub_loop->mainctx); 1158 | 1159 | pub->pub_loop->mainloop = NULL; 1160 | g_thread_join(pub->pub_loop->thread); 1161 | } 1162 | g_free(pub->pub_loop); 1163 | pub->pub_loop = NULL; 1164 | janus_mutex_unlock_nodebug(&pub->mutex_live); 1165 | 1166 | pub->closed = TRUE; 1167 | JANUS_LOG(LOG_WARN, "janus live pusblish event thread closed\n"); 1168 | return 0; 1169 | } 1170 | 1171 | 1172 | void 1173 | janus_live_pub_destroy(janus_live_pub *pub) 1174 | { 1175 | if(!pub || !g_atomic_int_compare_and_exchange(&pub->destroyed, 0, 1)) 1176 | return; 1177 | janus_refcount_decrease(&pub->ref); 1178 | } 1179 | 1180 | 1181 | /* Helpers to decode Exp-Golomb */ 1182 | static uint32_t 1183 | janus_pp_h264_eg_getbit(uint8_t *base, uint32_t offset) 1184 | { 1185 | return ((*(base + (offset >> 0x3))) >> (0x7 - (offset & 0x7))) & 0x1; 1186 | } 1187 | 1188 | 1189 | static uint32_t 1190 | janus_pp_h264_eg_decode(uint8_t *base, uint32_t *offset) 1191 | { 1192 | uint32_t zeros = 0; 1193 | while(janus_pp_h264_eg_getbit(base, (*offset)++) == 0) 1194 | zeros++; 1195 | uint32_t res = 1 << zeros; 1196 | int32_t i = 0; 1197 | for(i=zeros-1; i>=0; i--) { 1198 | res |= janus_pp_h264_eg_getbit(base, (*offset)++) << i; 1199 | } 1200 | return res-1; 1201 | } 1202 | 1203 | 1204 | /* Helper to parse a SPS (only to get the video resolution) */ 1205 | void 1206 | janus_live_h264_parse_sps(char *buffer, int *width, int *height) 1207 | { 1208 | /* Let's check if it's the right profile, first */ 1209 | int index = 1; 1210 | int profile_idc = *(buffer+index); 1211 | if(profile_idc != 66) { 1212 | JANUS_LOG(LOG_WARN, "Profile is not baseline (%d != 66)\n", profile_idc); 1213 | } 1214 | /* Then let's skip 2 bytes and evaluate/skip the rest */ 1215 | index += 3; 1216 | uint32_t offset = 0; 1217 | uint8_t *base = (uint8_t *)(buffer+index); 1218 | /* Skip seq_parameter_set_id */ 1219 | janus_pp_h264_eg_decode(base, &offset); 1220 | if(profile_idc >= 100) { 1221 | /* Skip chroma_format_idc */ 1222 | janus_pp_h264_eg_decode(base, &offset); 1223 | /* Skip bit_depth_luma_minus8 */ 1224 | janus_pp_h264_eg_decode(base, &offset); 1225 | /* Skip bit_depth_chroma_minus8 */ 1226 | janus_pp_h264_eg_decode(base, &offset); 1227 | /* Skip qpprime_y_zero_transform_bypass_flag */ 1228 | janus_pp_h264_eg_getbit(base, offset++); 1229 | /* Skip seq_scaling_matrix_present_flag */ 1230 | janus_pp_h264_eg_getbit(base, offset++); 1231 | } 1232 | /* Skip log2_max_frame_num_minus4 */ 1233 | janus_pp_h264_eg_decode(base, &offset); 1234 | /* Evaluate pic_order_cnt_type */ 1235 | int pic_order_cnt_type = janus_pp_h264_eg_decode(base, &offset); 1236 | if(pic_order_cnt_type == 0) { 1237 | /* Skip log2_max_pic_order_cnt_lsb_minus4 */ 1238 | janus_pp_h264_eg_decode(base, &offset); 1239 | } else if(pic_order_cnt_type == 1) { 1240 | /* Skip delta_pic_order_always_zero_flag, offset_for_non_ref_pic, 1241 | * offset_for_top_to_bottom_field and num_ref_frames_in_pic_order_cnt_cycle */ 1242 | janus_pp_h264_eg_getbit(base, offset++); 1243 | janus_pp_h264_eg_decode(base, &offset); 1244 | janus_pp_h264_eg_decode(base, &offset); 1245 | int num_ref_frames_in_pic_order_cnt_cycle = janus_pp_h264_eg_decode(base, &offset); 1246 | int i = 0; 1247 | for(i=0; ichannels = channels; 1291 | dc->sampling_rate = samplerate; 1292 | dc->fec = FALSE; 1293 | dc->expected_seq = 0; 1294 | dc->probation = 0; 1295 | dc->last_timestamp = 0; 1296 | dc->decoder = opus_decoder_create(dc->sampling_rate, dc->channels, &error); 1297 | if(error != OPUS_OK) { 1298 | JANUS_LOG(LOG_ERR, "Error create Opus decoder...\n"); 1299 | g_free(dc); 1300 | return NULL; 1301 | } 1302 | 1303 | if(fec){ 1304 | dc->fec = TRUE; 1305 | dc->probation = AUDIO_MIN_SEQUENTIAL; 1306 | } 1307 | 1308 | return dc; 1309 | } 1310 | 1311 | 1312 | void 1313 | janus_live_opus_decoder_destory(janus_adecoder_opus *dc) 1314 | { 1315 | if(dc){ 1316 | opus_decoder_destroy(dc); 1317 | g_free(dc); 1318 | } 1319 | } 1320 | 1321 | 1322 | void 1323 | janus_live_opus_decoder_decode(janus_adecoder_opus *dc, char *buf, int len) 1324 | { 1325 | janus_rtp_header *rtp = (janus_rtp_header *)buf; 1326 | uint32_t ssrc = ntohl(rtp->ssrc); 1327 | uint32_t timestamp = ntohl(rtp->timestamp); 1328 | uint16_t seq_number = ntohs(rtp->seq_number); 1329 | /* First check if probation period */ 1330 | if(dc->probation == AUDIO_MIN_SEQUENTIAL) { 1331 | dc->probation--; 1332 | dc->expected_seq = seq_number + 1; 1333 | JANUS_LOG(LOG_INFO, "Probation started with ssrc = %"SCNu32", seq = %"SCNu16" \n", ssrc, seq_number); 1334 | return; 1335 | } else if(dc->probation != 0) { 1336 | /* Decrease probation */ 1337 | dc->probation--; 1338 | if(!dc->probation){ 1339 | /* Probation is ended */ 1340 | JANUS_LOG(LOG_INFO, "Probation ended with ssrc = %"SCNu32", seq = %"SCNu16" \n",ssrc, seq_number); 1341 | } 1342 | dc->expected_seq = seq_number + 1; 1343 | return; 1344 | } 1345 | 1346 | int plen = 0; 1347 | const unsigned char *payload = (const unsigned char *)janus_rtp_payload(buf, len, &plen); 1348 | if(!payload) { 1349 | JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error accessing the RTP payload\n"); 1350 | return; 1351 | } 1352 | 1353 | gint length = 0; 1354 | char data[AUDIO_BUFFER_SAMPLES*2]; 1355 | memset(data, 0, AUDIO_BUFFER_SAMPLES*2); 1356 | /* Check sequence number received, verify if it's relevant to the expected one */ 1357 | if(seq_number == dc->expected_seq) { 1358 | /* Regular decode */ 1359 | length = opus_decode(dc->decoder, payload, plen, (opus_int16 *)data, AUDIO_BUFFER_SAMPLES, 0); 1360 | /* Update last_timestamp */ 1361 | dc->last_timestamp = timestamp; 1362 | /* Increment according to previous seq_number */ 1363 | dc->expected_seq = seq_number + 1; 1364 | } else if(seq_number > dc->expected_seq) { 1365 | /* Sequence(s) losts */ 1366 | uint16_t gap = seq_number - dc->expected_seq; 1367 | JANUS_LOG(LOG_HUGE, "%"SCNu16" sequence(s) lost, sequence = %"SCNu16", expected seq = %"SCNu16" \n", 1368 | gap, seq_number, dc->expected_seq); 1369 | 1370 | /* Use FEC if sequence lost < DEFAULT_PREBUFFERING */ 1371 | uint16_t start_lost_seq = dc->expected_seq; 1372 | if(dc->fec && gap < AUDIO_DEFAULT_PREBUFFERING) { 1373 | uint8_t i=0; 1374 | for(i=1; i<=gap ; i++) { 1375 | int32_t output_samples; 1376 | uint32_t timestamp_tmp = dc->last_timestamp + (i * AUDIO_OPUS_SAMPLES); 1377 | uint16_t seq_number_tmp = start_lost_seq++; 1378 | length = 0; 1379 | if(i == gap) { 1380 | /* Attempt to decode with in-band FEC from next packet */ 1381 | opus_decoder_ctl(dc->decoder, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); 1382 | length = opus_decode(dc->decoder, payload, plen, (opus_int16 *)data, output_samples, 1); 1383 | } else { 1384 | opus_decoder_ctl(dc->decoder, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); 1385 | length = opus_decode(dc->decoder, NULL, plen, (opus_int16 *)data, output_samples, 1); 1386 | } 1387 | if(length < 0) { 1388 | JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", length, opus_strerror(length)); 1389 | return; 1390 | } 1391 | JANUS_LOG(LOG_HUGE, "[Opus] decoding Opus frame len: %d, fec\n", length*dc->channels); 1392 | janus_live_fdkaac_encoder_encode(dc->jb->aencoder, data, length * dc->channels * sizeof(opus_int16), timestamp_tmp/(dc->jb->tb/1000)); 1393 | } 1394 | } 1395 | /* Then go with the regular decode (no FEC) */ 1396 | length = opus_decode(dc->decoder, payload, plen, (opus_int16 *)data, AUDIO_BUFFER_SAMPLES, 0); 1397 | /* Increment according to previous seq_number */ 1398 | dc->expected_seq = seq_number + 1; 1399 | } else { 1400 | /* In late sequence or sequence wrapped */ 1401 | if((dc->expected_seq - seq_number) > AUDIO_MAX_MISORDER){ 1402 | JANUS_LOG(LOG_HUGE, "SN WRAPPED seq = %"SCNu16", expected_seq = %"SCNu16" \n", seq_number, dc->expected_seq); 1403 | dc->expected_seq = seq_number + 1; 1404 | } else { 1405 | JANUS_LOG(LOG_HUGE, "IN LATE SN seq = %"SCNu16", expected_seq = %"SCNu16" \n", seq_number, dc->expected_seq); 1406 | } 1407 | return; 1408 | } 1409 | if(length < 0) { 1410 | JANUS_LOG(LOG_ERR, "[Opus] Ops! got an error decoding the Opus frame: %d (%s)\n", length, opus_strerror(length)); 1411 | return; 1412 | } 1413 | JANUS_LOG(LOG_VERB, "[Opus] decoding Opus frame len: %d\n", length*dc->channels); 1414 | janus_live_fdkaac_encoder_encode(dc->jb->aencoder, data, length * dc->channels * sizeof(opus_int16), timestamp/(dc->jb->tb/1000)); 1415 | } 1416 | 1417 | 1418 | janus_aencoder_fdkaac * 1419 | janus_live_fdkaac_encoder_create(int sample_rate, int channels, int bitrate) 1420 | { 1421 | janus_aencoder_fdkaac *ec = g_malloc0(sizeof(janus_aencoder_fdkaac)); 1422 | ec->sample_rate = sample_rate; 1423 | ec->channels = channels; 1424 | ec->bitrate = bitrate; 1425 | 1426 | AVDictionary *audio_opt_p = NULL; 1427 | ec->acodec = avcodec_find_encoder_by_name("libfdk_aac"); 1428 | if (ec->acodec == NULL) { 1429 | JANUS_LOG(LOG_ERR, "init audio encoder avcodec_find_encoder_by_name aac error\n"); 1430 | return NULL; 1431 | } 1432 | ec->actx = avcodec_alloc_context3(ec->acodec); 1433 | ec->actx->codec_type = AVMEDIA_TYPE_AUDIO; 1434 | ec->actx->sample_rate = ec->sample_rate; 1435 | ec->actx->bit_rate = ec->bitrate * 1000; 1436 | ec->actx->bit_rate_tolerance = ec->bitrate * 1000 * 3 / 2; 1437 | ec->actx->channels = ec->channels; 1438 | ec->actx->channel_layout = AV_CH_LAYOUT_STEREO; 1439 | 1440 | if (ec->actx->channels == 2) { 1441 | ec->actx->channel_layout = AV_CH_LAYOUT_STEREO; 1442 | } 1443 | if (ec->actx->channels == 6) { 1444 | ec->actx->channel_layout = AV_CH_LAYOUT_5POINT1_BACK; 1445 | } 1446 | if (ec->actx->channels == 8) { 1447 | ec->actx->channel_layout = AV_CH_LAYOUT_7POINT1; 1448 | } 1449 | ec->actx->time_base.num = 1; 1450 | ec->actx->time_base.den = ec->sample_rate; 1451 | ec->actx->sample_fmt = AV_SAMPLE_FMT_S16; 1452 | 1453 | av_dict_set(&audio_opt_p, "profile", "aac_low", 0); 1454 | av_dict_set(&audio_opt_p, "threads", "1", 0); 1455 | int ret = 0; 1456 | if ((ret = avcodec_open2(ec->actx, ec->acodec, &audio_opt_p)) < 0) { 1457 | av_dict_free(&audio_opt_p); 1458 | JANUS_LOG(LOG_ERR, "init audio encoder open audio encoder failed. ret=%d\n", ret); 1459 | return NULL; 1460 | } 1461 | av_dict_free(&audio_opt_p); 1462 | 1463 | ec->nb_samples = 1024; 1464 | ec->aframe = av_frame_alloc(); 1465 | ec->aframe->nb_samples = ec->nb_samples; 1466 | ec->aframe->channel_layout = 3; 1467 | ec->aframe->format = AV_SAMPLE_FMT_S16; 1468 | 1469 | ret = av_frame_get_buffer(ec->aframe, 32); 1470 | if (ret != 0) { 1471 | JANUS_LOG(LOG_ERR, "init audio frame failed. nb_samples=%d, channel_layout=%d, ret=%d\n", 1472 | ec->nb_samples,ec->aframe->channel_layout, ret); 1473 | } 1474 | JANUS_LOG(LOG_ERR, "init audio frame failed. nb_samples=%d, channels=%d, format=%d, linesize0=%d\n", 1475 | ec->aframe->nb_samples, ec->aframe->channels, ec->aframe->format, ec->aframe->linesize[0]); 1476 | 1477 | ec->buflen = 0; 1478 | JANUS_LOG(LOG_ERR, "fdkaac frame buffer len:%d\n", ec->nb_samples * ec->aframe->channels * 2); 1479 | ec->buffer = g_malloc0(ec->nb_samples * ec->aframe->channels * 2); 1480 | 1481 | return ec; 1482 | } 1483 | 1484 | 1485 | void 1486 | janus_live_fdkaac_encoder_destory(janus_aencoder_fdkaac *ec) 1487 | { 1488 | if (ec->aframe) { 1489 | av_frame_free(&ec->aframe); 1490 | ec->aframe = NULL; 1491 | } 1492 | if(ec->actx) { 1493 | avcodec_close(ec->actx); 1494 | av_free(ec->actx); 1495 | ec->actx = NULL; 1496 | ec->acodec = NULL; 1497 | } 1498 | if(ec->buffer){ 1499 | g_free(ec->buffer); 1500 | ec->buffer = NULL; 1501 | } 1502 | g_free(ec); 1503 | } 1504 | 1505 | 1506 | void 1507 | janus_live_fdkaac_encoder_encode_inernal(janus_aencoder_fdkaac *ec, char *data, int len, uint32_t pts) 1508 | { 1509 | if(!data || !len) 1510 | return; 1511 | gint64 now = janus_get_real_time(); 1512 | JANUS_LOG(LOG_HUGE, "fdkaac encode len:%d, pts:%d\n", len, pts); 1513 | if(pts > 0 && ec->jb->lastts > 0 && pts < ec->jb->lastts && ec->jb->lastts - pts > 500){ 1514 | JANUS_LOG(LOG_WARN, "fdkaac offset reset, last:%d, now:%d\n", ec->jb->offset, ec->jb->lastts); 1515 | ec->jb->offset = ec->jb->lastts; 1516 | } 1517 | ec->jb->lastts = pts; 1518 | 1519 | ec->aframe->pts = pts + ec->jb->offset; 1520 | memcpy((unsigned char *)ec->aframe->data[0], data, len); 1521 | 1522 | int got_pic = 0; 1523 | int ret_enc = 0; 1524 | AVPacket* enc_pkt_p = av_packet_alloc(); 1525 | av_init_packet(enc_pkt_p); 1526 | 1527 | ret_enc = avcodec_encode_audio2(ec->actx, enc_pkt_p, ec->aframe, &got_pic); 1528 | if (ret_enc < 0) { 1529 | JANUS_LOG(LOG_ERR, "audio encode error ret:%d\n", ret_enc); 1530 | } 1531 | if ((ret_enc >= 0) && got_pic) { 1532 | 1533 | if(enc_pkt_p->pts != enc_pkt_p->dts){ 1534 | JANUS_LOG(LOG_WARN, "audio encode erroraudio pts:%d != dts:%d\n", enc_pkt_p->pts, enc_pkt_p->dts); 1535 | } 1536 | if(AV_NOPTS_VALUE == enc_pkt_p->pts || enc_pkt_p->pts < 0){ 1537 | JANUS_LOG(LOG_WARN, "audio pts unnormal dts:%d, pts:%d\n", enc_pkt_p->dts, enc_pkt_p->pts); 1538 | enc_pkt_p->pts = 0; 1539 | enc_pkt_p->dts = 0; 1540 | } 1541 | JANUS_LOG(LOG_HUGE, "audio pts dts:%d, pts:%d src pts:%d\n", enc_pkt_p->dts, enc_pkt_p->pts, pts); 1542 | 1543 | //janus_frame_packet *p = janus_packet_alloc(enc_pkt_p->size + FF_INPUT_BUFFER_PADDING_SIZE); 1544 | janus_frame_packet *p = janus_packet_alloc(enc_pkt_p->size); 1545 | p->created = now; 1546 | memcpy(p->data, enc_pkt_p->data, enc_pkt_p->size); 1547 | p->video = FALSE; 1548 | p->ts = enc_pkt_p->dts; 1549 | janus_live_packet_insert(ec->jb->pub, p); 1550 | } 1551 | av_packet_free(&enc_pkt_p); 1552 | } 1553 | 1554 | 1555 | void 1556 | janus_live_fdkaac_encoder_encode(janus_aencoder_fdkaac *ec, char *data, int len, uint32_t pts) 1557 | { 1558 | if(!data || !len) 1559 | return; 1560 | 1561 | int total = ec->nb_samples * ec->aframe->channels * 2; 1562 | int left = 0; 1563 | if(ec->buflen + len < total){ 1564 | memcpy(ec->buffer + ec->buflen, data, len); 1565 | ec->buflen += len; 1566 | } else{ 1567 | left = len - (total - ec->buflen); 1568 | memcpy(ec->buffer + ec->buflen, data, total - ec->buflen); 1569 | janus_live_fdkaac_encoder_encode_inernal(ec, ec->buffer, total, pts); 1570 | ec->buflen = 0; 1571 | 1572 | if(left > 0){ 1573 | memcpy(ec->buffer + ec->buflen, &data[len - left], left); 1574 | ec->buflen += left; 1575 | } 1576 | } 1577 | JANUS_LOG(LOG_HUGE, "fdkaac cache buflen:%d, len:%d, pts:%d, left:%d\n", ec->buflen, len, pts, left); 1578 | } 1579 | --------------------------------------------------------------------------------