├── 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 | [](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 |
--------------------------------------------------------------------------------