Mercurial > libavformat.hg
annotate rtmpproto.c @ 6085:72c7c3d5c4e9 libavformat
matroskaenc: Mux clusters better
Start them on keyframes when reasonable, and delay writing audio packets
to help ensure that there's audio samples available for the first frame in
clusters.
Patch by James Zern <jzern at google>
author | conrad |
---|---|
date | Fri, 04 Jun 2010 22:40:50 +0000 |
parents | 7fdda2416684 |
children | bd851edc58ac |
rev | line source |
---|---|
5123 | 1 /* |
2 * RTMP network protocol | |
3 * Copyright (c) 2009 Kostya Shishkov | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 /** | |
5969
178de7695c6c
Remove explicit filename from Doxygen @file commands.
diego
parents:
5837
diff
changeset
|
23 * @file |
5123 | 24 * RTMP protocol |
25 */ | |
26 | |
27 #include "libavcodec/bytestream.h" | |
28 #include "libavutil/avstring.h" | |
29 #include "libavutil/lfg.h" | |
30 #include "libavutil/sha.h" | |
31 #include "avformat.h" | |
5837
d605f589f0be
move ff_url_split() and ff_url_join() declarations to internal.h
aurel
parents:
5776
diff
changeset
|
32 #include "internal.h" |
5123 | 33 |
34 #include "network.h" | |
35 | |
36 #include "flv.h" | |
37 #include "rtmp.h" | |
38 #include "rtmppkt.h" | |
39 | |
40 /* we can't use av_log() with URLContext yet... */ | |
41 #if LIBAVFORMAT_VERSION_MAJOR < 53 | |
42 #define LOG_CONTEXT NULL | |
43 #else | |
44 #define LOG_CONTEXT s | |
45 #endif | |
46 | |
5432 | 47 //#define DEBUG |
48 | |
5123 | 49 /** RTMP protocol handler state */ |
50 typedef enum { | |
51 STATE_START, ///< client has not done anything yet | |
52 STATE_HANDSHAKED, ///< client has performed handshake | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
53 STATE_RELEASING, ///< client releasing stream before publish it (for output) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
54 STATE_FCPUBLISH, ///< client FCPublishing stream (for output) |
5123 | 55 STATE_CONNECTING, ///< client connected to server successfully |
56 STATE_READY, ///< client has sent all needed commands and waits for server reply | |
57 STATE_PLAYING, ///< client has started receiving multimedia data from server | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
58 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output) |
5430
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
59 STATE_STOPPED, ///< the broadcast has been stopped |
5123 | 60 } ClientState; |
61 | |
62 /** protocol handler context */ | |
63 typedef struct RTMPContext { | |
64 URLContext* stream; ///< TCP stream used in interactions with RTMP server | |
65 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets | |
66 int chunk_size; ///< size of the chunks RTMP packets are divided into | |
5407 | 67 int is_input; ///< input/output flag |
5123 | 68 char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix) |
5411 | 69 char app[128]; ///< application |
5123 | 70 ClientState state; ///< current state |
71 int main_channel_id; ///< an additional channel ID which is used for some invocations | |
72 uint8_t* flv_data; ///< buffer with data for demuxer | |
73 int flv_size; ///< current buffer size | |
74 int flv_off; ///< number of bytes read from current buffer | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
75 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output) |
5668 | 76 uint32_t client_report_size; ///< number of bytes after which client should report to server |
77 uint32_t bytes_read; ///< number of bytes read from server | |
78 uint32_t last_bytes_read; ///< number of bytes read last reported to server | |
5123 | 79 } RTMPContext; |
80 | |
81 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing | |
82 /** Client key used for digest signing */ | |
83 static const uint8_t rtmp_player_key[] = { | |
84 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', | |
85 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1', | |
86 | |
87 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, | |
88 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, | |
89 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE | |
90 }; | |
91 | |
92 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing | |
93 /** Key used for RTMP server digest signing */ | |
94 static const uint8_t rtmp_server_key[] = { | |
95 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', | |
96 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ', | |
97 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1', | |
98 | |
99 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02, | |
100 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8, | |
101 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE | |
102 }; | |
103 | |
104 /** | |
105 * Generates 'connect' call and sends it to the server. | |
106 */ | |
107 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto, | |
5411 | 108 const char *host, int port) |
5123 | 109 { |
110 RTMPPacket pkt; | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
111 uint8_t ver[64], *p; |
5123 | 112 char tcurl[512]; |
113 | |
5412
95bc775d22ff
Send connect() and createStream() in RTMP system channel, not video channel.
kostya
parents:
5411
diff
changeset
|
114 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096); |
5123 | 115 p = pkt.data; |
116 | |
5756
7c7fe75728dd
Use ff_url_join for assembling URLs, instead of snprintf
mstorsjo
parents:
5668
diff
changeset
|
117 ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app); |
5123 | 118 ff_amf_write_string(&p, "connect"); |
119 ff_amf_write_number(&p, 1.0); | |
120 ff_amf_write_object_start(&p); | |
121 ff_amf_write_field_name(&p, "app"); | |
5411 | 122 ff_amf_write_string(&p, rt->app); |
5123 | 123 |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
124 if (rt->is_input) { |
5417 | 125 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, |
126 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
127 } else { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
128 snprintf(ver, sizeof(ver), "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
129 ff_amf_write_field_name(&p, "type"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
130 ff_amf_write_string(&p, "nonprivate"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
131 } |
5123 | 132 ff_amf_write_field_name(&p, "flashVer"); |
133 ff_amf_write_string(&p, ver); | |
134 ff_amf_write_field_name(&p, "tcUrl"); | |
135 ff_amf_write_string(&p, tcurl); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
136 if (rt->is_input) { |
5417 | 137 ff_amf_write_field_name(&p, "fpad"); |
138 ff_amf_write_bool(&p, 0); | |
139 ff_amf_write_field_name(&p, "capabilities"); | |
140 ff_amf_write_number(&p, 15.0); | |
141 ff_amf_write_field_name(&p, "audioCodecs"); | |
142 ff_amf_write_number(&p, 1639.0); | |
143 ff_amf_write_field_name(&p, "videoCodecs"); | |
144 ff_amf_write_number(&p, 252.0); | |
145 ff_amf_write_field_name(&p, "videoFunction"); | |
146 ff_amf_write_number(&p, 1.0); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
147 } |
5123 | 148 ff_amf_write_object_end(&p); |
149 | |
150 pkt.data_size = p - pkt.data; | |
151 | |
152 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); | |
5431
b0eb87793222
5l trocadero: don't forget to free packet in gen_connect()
kostya
parents:
5430
diff
changeset
|
153 ff_rtmp_packet_destroy(&pkt); |
5123 | 154 } |
155 | |
156 /** | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
157 * Generates 'releaseStream' call and sends it to the server. It should make |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
158 * the server release some channel for media streams. |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
159 */ |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
160 static void gen_release_stream(URLContext *s, RTMPContext *rt) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
161 { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
162 RTMPPacket pkt; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
163 uint8_t *p; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
164 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
165 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
166 29 + strlen(rt->playpath)); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
167 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
168 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Releasing stream...\n"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
169 p = pkt.data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
170 ff_amf_write_string(&p, "releaseStream"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
171 ff_amf_write_number(&p, 2.0); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
172 ff_amf_write_null(&p); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
173 ff_amf_write_string(&p, rt->playpath); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
174 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
175 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
176 ff_rtmp_packet_destroy(&pkt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
177 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
178 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
179 /** |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
180 * Generates 'FCPublish' call and sends it to the server. It should make |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
181 * the server preapare for receiving media streams. |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
182 */ |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
183 static void gen_fcpublish_stream(URLContext *s, RTMPContext *rt) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
184 { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
185 RTMPPacket pkt; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
186 uint8_t *p; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
187 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
188 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
189 25 + strlen(rt->playpath)); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
190 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
191 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "FCPublish stream...\n"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
192 p = pkt.data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
193 ff_amf_write_string(&p, "FCPublish"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
194 ff_amf_write_number(&p, 3.0); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
195 ff_amf_write_null(&p); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
196 ff_amf_write_string(&p, rt->playpath); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
197 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
198 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
199 ff_rtmp_packet_destroy(&pkt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
200 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
201 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
202 /** |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
203 * Generates 'FCUnpublish' call and sends it to the server. It should make |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
204 * the server destroy stream. |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
205 */ |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
206 static void gen_fcunpublish_stream(URLContext *s, RTMPContext *rt) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
207 { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
208 RTMPPacket pkt; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
209 uint8_t *p; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
210 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
211 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
212 27 + strlen(rt->playpath)); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
213 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
214 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "UnPublishing stream...\n"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
215 p = pkt.data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
216 ff_amf_write_string(&p, "FCUnpublish"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
217 ff_amf_write_number(&p, 5.0); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
218 ff_amf_write_null(&p); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
219 ff_amf_write_string(&p, rt->playpath); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
220 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
221 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
222 ff_rtmp_packet_destroy(&pkt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
223 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
224 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
225 /** |
5123 | 226 * Generates 'createStream' call and sends it to the server. It should make |
227 * the server allocate some channel for media streams. | |
228 */ | |
229 static void gen_create_stream(URLContext *s, RTMPContext *rt) | |
230 { | |
231 RTMPPacket pkt; | |
232 uint8_t *p; | |
233 | |
234 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Creating stream...\n"); | |
5412
95bc775d22ff
Send connect() and createStream() in RTMP system channel, not video channel.
kostya
parents:
5411
diff
changeset
|
235 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 25); |
5123 | 236 |
237 p = pkt.data; | |
238 ff_amf_write_string(&p, "createStream"); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
239 ff_amf_write_number(&p, rt->is_input ? 3.0 : 4.0); |
5123 | 240 ff_amf_write_null(&p); |
241 | |
242 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); | |
243 ff_rtmp_packet_destroy(&pkt); | |
244 } | |
245 | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
246 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
247 /** |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
248 * Generates 'deleteStream' call and sends it to the server. It should make |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
249 * the server remove some channel for media streams. |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
250 */ |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
251 static void gen_delete_stream(URLContext *s, RTMPContext *rt) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
252 { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
253 RTMPPacket pkt; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
254 uint8_t *p; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
255 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
256 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Deleting stream...\n"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
257 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 34); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
258 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
259 p = pkt.data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
260 ff_amf_write_string(&p, "deleteStream"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
261 ff_amf_write_number(&p, 0.0); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
262 ff_amf_write_null(&p); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
263 ff_amf_write_number(&p, rt->main_channel_id); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
264 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
265 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
266 ff_rtmp_packet_destroy(&pkt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
267 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
268 |
5123 | 269 /** |
270 * Generates 'play' call and sends it to the server, then pings the server | |
271 * to start actual playing. | |
272 */ | |
273 static void gen_play(URLContext *s, RTMPContext *rt) | |
274 { | |
275 RTMPPacket pkt; | |
276 uint8_t *p; | |
277 | |
278 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath); | |
279 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, | |
5295
08ec48911f20
Last parameter in RTMP "play" call was optional and some servers seem not to
kostya
parents:
5214
diff
changeset
|
280 20 + strlen(rt->playpath)); |
5123 | 281 pkt.extra = rt->main_channel_id; |
282 | |
283 p = pkt.data; | |
284 ff_amf_write_string(&p, "play"); | |
285 ff_amf_write_number(&p, 0.0); | |
286 ff_amf_write_null(&p); | |
287 ff_amf_write_string(&p, rt->playpath); | |
288 | |
289 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); | |
290 ff_rtmp_packet_destroy(&pkt); | |
291 | |
292 // set client buffer time disguised in ping packet | |
293 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10); | |
294 | |
295 p = pkt.data; | |
296 bytestream_put_be16(&p, 3); | |
297 bytestream_put_be32(&p, 1); | |
298 bytestream_put_be32(&p, 256); //TODO: what is a good value here? | |
299 | |
300 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); | |
301 ff_rtmp_packet_destroy(&pkt); | |
302 } | |
303 | |
304 /** | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
305 * Generates 'publish' call and sends it to the server. |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
306 */ |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
307 static void gen_publish(URLContext *s, RTMPContext *rt) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
308 { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
309 RTMPPacket pkt; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
310 uint8_t *p; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
311 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
312 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
313 ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE, 0, |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
314 30 + strlen(rt->playpath)); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
315 pkt.extra = rt->main_channel_id; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
316 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
317 p = pkt.data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
318 ff_amf_write_string(&p, "publish"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
319 ff_amf_write_number(&p, 0.0); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
320 ff_amf_write_null(&p); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
321 ff_amf_write_string(&p, rt->playpath); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
322 ff_amf_write_string(&p, "live"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
323 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
324 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
325 ff_rtmp_packet_destroy(&pkt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
326 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
327 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
328 /** |
5123 | 329 * Generates ping reply and sends it to the server. |
330 */ | |
331 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt) | |
332 { | |
333 RTMPPacket pkt; | |
334 uint8_t *p; | |
335 | |
336 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6); | |
337 p = pkt.data; | |
338 bytestream_put_be16(&p, 7); | |
5465
4ee5aa5e013c
Reply to RTMP ping with the same value as received by client.
kostya
parents:
5432
diff
changeset
|
339 bytestream_put_be32(&p, AV_RB32(ppkt->data+2)); |
5123 | 340 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
341 ff_rtmp_packet_destroy(&pkt); | |
342 } | |
343 | |
5668 | 344 /** |
345 * Generates report on bytes read so far and sends it to the server. | |
346 */ | |
347 static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts) | |
348 { | |
349 RTMPPacket pkt; | |
350 uint8_t *p; | |
351 | |
352 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4); | |
353 p = pkt.data; | |
354 bytestream_put_be32(&p, rt->bytes_read); | |
355 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); | |
356 ff_rtmp_packet_destroy(&pkt); | |
357 } | |
358 | |
5123 | 359 //TODO: Move HMAC code somewhere. Eventually. |
360 #define HMAC_IPAD_VAL 0x36 | |
361 #define HMAC_OPAD_VAL 0x5C | |
362 | |
363 /** | |
364 * Calculates HMAC-SHA2 digest for RTMP handshake packets. | |
365 * | |
366 * @param src input buffer | |
367 * @param len input buffer length (should be 1536) | |
368 * @param gap offset in buffer where 32 bytes should not be taken into account | |
369 * when calculating digest (since it will be used to store that digest) | |
370 * @param key digest key | |
371 * @param keylen digest key length | |
372 * @param dst buffer where calculated digest will be stored (32 bytes) | |
373 */ | |
374 static void rtmp_calc_digest(const uint8_t *src, int len, int gap, | |
375 const uint8_t *key, int keylen, uint8_t *dst) | |
376 { | |
377 struct AVSHA *sha; | |
378 uint8_t hmac_buf[64+32] = {0}; | |
379 int i; | |
380 | |
381 sha = av_mallocz(av_sha_size); | |
382 | |
383 if (keylen < 64) { | |
384 memcpy(hmac_buf, key, keylen); | |
385 } else { | |
386 av_sha_init(sha, 256); | |
387 av_sha_update(sha,key, keylen); | |
388 av_sha_final(sha, hmac_buf); | |
389 } | |
390 for (i = 0; i < 64; i++) | |
391 hmac_buf[i] ^= HMAC_IPAD_VAL; | |
392 | |
393 av_sha_init(sha, 256); | |
394 av_sha_update(sha, hmac_buf, 64); | |
395 if (gap <= 0) { | |
396 av_sha_update(sha, src, len); | |
397 } else { //skip 32 bytes used for storing digest | |
398 av_sha_update(sha, src, gap); | |
399 av_sha_update(sha, src + gap + 32, len - gap - 32); | |
400 } | |
401 av_sha_final(sha, hmac_buf + 64); | |
402 | |
403 for (i = 0; i < 64; i++) | |
404 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad | |
405 av_sha_init(sha, 256); | |
406 av_sha_update(sha, hmac_buf, 64+32); | |
407 av_sha_final(sha, dst); | |
408 | |
409 av_free(sha); | |
410 } | |
411 | |
412 /** | |
413 * Puts HMAC-SHA2 digest of packet data (except for the bytes where this digest | |
414 * will be stored) into that packet. | |
415 * | |
416 * @param buf handshake data (1536 bytes) | |
417 * @return offset to the digest inside input data | |
418 */ | |
419 static int rtmp_handshake_imprint_with_digest(uint8_t *buf) | |
420 { | |
421 int i, digest_pos = 0; | |
422 | |
423 for (i = 8; i < 12; i++) | |
424 digest_pos += buf[i]; | |
425 digest_pos = (digest_pos % 728) + 12; | |
426 | |
427 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos, | |
428 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN, | |
429 buf + digest_pos); | |
430 return digest_pos; | |
431 } | |
432 | |
433 /** | |
434 * Verifies that the received server response has the expected digest value. | |
435 * | |
436 * @param buf handshake data received from the server (1536 bytes) | |
437 * @param off position to search digest offset from | |
438 * @return 0 if digest is valid, digest position otherwise | |
439 */ | |
440 static int rtmp_validate_digest(uint8_t *buf, int off) | |
441 { | |
442 int i, digest_pos = 0; | |
443 uint8_t digest[32]; | |
444 | |
445 for (i = 0; i < 4; i++) | |
446 digest_pos += buf[i + off]; | |
447 digest_pos = (digest_pos % 728) + off + 4; | |
448 | |
449 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos, | |
450 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN, | |
451 digest); | |
452 if (!memcmp(digest, buf + digest_pos, 32)) | |
453 return digest_pos; | |
454 return 0; | |
455 } | |
456 | |
457 /** | |
458 * Performs handshake with the server by means of exchanging pseudorandom data | |
459 * signed with HMAC-SHA2 digest. | |
460 * | |
461 * @return 0 if handshake succeeds, negative value otherwise | |
462 */ | |
463 static int rtmp_handshake(URLContext *s, RTMPContext *rt) | |
464 { | |
465 AVLFG rnd; | |
466 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = { | |
467 3, // unencrypted data | |
468 0, 0, 0, 0, // client uptime | |
469 RTMP_CLIENT_VER1, | |
470 RTMP_CLIENT_VER2, | |
471 RTMP_CLIENT_VER3, | |
472 RTMP_CLIENT_VER4, | |
473 }; | |
474 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE]; | |
475 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1]; | |
476 int i; | |
477 int server_pos, client_pos; | |
478 uint8_t digest[32]; | |
479 | |
480 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n"); | |
481 | |
482 av_lfg_init(&rnd, 0xDEADC0DE); | |
483 // generate handshake packet - 1536 bytes of pseudorandom data | |
484 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++) | |
485 tosend[i] = av_lfg_get(&rnd) >> 24; | |
486 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1); | |
487 | |
488 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1); | |
489 i = url_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1); | |
490 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) { | |
491 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n"); | |
492 return -1; | |
493 } | |
494 i = url_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE); | |
495 if (i != RTMP_HANDSHAKE_PACKET_SIZE) { | |
496 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n"); | |
497 return -1; | |
498 } | |
499 | |
500 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n", | |
501 serverdata[5], serverdata[6], serverdata[7], serverdata[8]); | |
502 | |
5523 | 503 if (rt->is_input && serverdata[5] >= 3) { |
5417 | 504 server_pos = rtmp_validate_digest(serverdata + 1, 772); |
5123 | 505 if (!server_pos) { |
5417 | 506 server_pos = rtmp_validate_digest(serverdata + 1, 8); |
507 if (!server_pos) { | |
508 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n"); | |
509 return -1; | |
510 } | |
511 } | |
512 | |
513 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, | |
514 rtmp_server_key, sizeof(rtmp_server_key), | |
515 digest); | |
516 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0, | |
517 digest, 32, | |
518 digest); | |
519 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) { | |
520 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n"); | |
5123 | 521 return -1; |
522 } | |
523 | |
5417 | 524 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++) |
525 tosend[i] = av_lfg_get(&rnd) >> 24; | |
526 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0, | |
527 rtmp_player_key, sizeof(rtmp_player_key), | |
528 digest); | |
529 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0, | |
530 digest, 32, | |
531 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32); | |
5123 | 532 |
5417 | 533 // write reply back to the server |
534 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
535 } else { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
536 url_write(rt->stream, serverdata+1, RTMP_HANDSHAKE_PACKET_SIZE); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
537 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
538 |
5123 | 539 return 0; |
540 } | |
541 | |
542 /** | |
543 * Parses received packet and may perform some action depending on | |
544 * the packet contents. | |
545 * @return 0 for no errors, negative values for serious errors which prevent | |
546 * further communications, positive values for uncritical errors | |
547 */ | |
548 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt) | |
549 { | |
550 int i, t; | |
551 const uint8_t *data_end = pkt->data + pkt->data_size; | |
552 | |
5432 | 553 #ifdef DEBUG |
554 ff_rtmp_packet_dump(LOG_CONTEXT, pkt); | |
555 #endif | |
556 | |
5123 | 557 switch (pkt->type) { |
558 case RTMP_PT_CHUNK_SIZE: | |
559 if (pkt->data_size != 4) { | |
560 av_log(LOG_CONTEXT, AV_LOG_ERROR, | |
561 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size); | |
562 return -1; | |
563 } | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
564 if (!rt->is_input) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
565 ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size, rt->prev_pkt[1]); |
5123 | 566 rt->chunk_size = AV_RB32(pkt->data); |
567 if (rt->chunk_size <= 0) { | |
568 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size); | |
569 return -1; | |
570 } | |
571 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size); | |
572 break; | |
573 case RTMP_PT_PING: | |
574 t = AV_RB16(pkt->data); | |
575 if (t == 6) | |
576 gen_pong(s, rt, pkt); | |
577 break; | |
5668 | 578 case RTMP_PT_CLIENT_BW: |
579 if (pkt->data_size < 4) { | |
580 av_log(LOG_CONTEXT, AV_LOG_ERROR, | |
581 "Client bandwidth report packet is less than 4 bytes long (%d)\n", | |
582 pkt->data_size); | |
583 return -1; | |
584 } | |
585 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data)); | |
586 rt->client_report_size = AV_RB32(pkt->data) >> 1; | |
587 break; | |
5123 | 588 case RTMP_PT_INVOKE: |
589 //TODO: check for the messages sent for wrong state? | |
590 if (!memcmp(pkt->data, "\002\000\006_error", 9)) { | |
591 uint8_t tmpstr[256]; | |
592 | |
593 if (!ff_amf_get_field_value(pkt->data + 9, data_end, | |
594 "description", tmpstr, sizeof(tmpstr))) | |
595 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr); | |
596 return -1; | |
597 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) { | |
598 switch (rt->state) { | |
599 case STATE_HANDSHAKED: | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
600 if (!rt->is_input) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
601 gen_release_stream(s, rt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
602 gen_fcpublish_stream(s, rt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
603 rt->state = STATE_RELEASING; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
604 } else { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
605 rt->state = STATE_CONNECTING; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
606 } |
5123 | 607 gen_create_stream(s, rt); |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
608 break; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
609 case STATE_FCPUBLISH: |
5123 | 610 rt->state = STATE_CONNECTING; |
611 break; | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
612 case STATE_RELEASING: |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
613 rt->state = STATE_FCPUBLISH; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
614 /* hack for Wowza Media Server, it does not send result for |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
615 * releaseStream and FCPublish calls */ |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
616 if (!pkt->data[10]) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
617 int pkt_id = (int) av_int2dbl(AV_RB64(pkt->data + 11)); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
618 if (pkt_id == 4) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
619 rt->state = STATE_CONNECTING; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
620 } |
5420
62329840eb7c
cosmetics: insert space between codeword and left parenthesis
kostya
parents:
5419
diff
changeset
|
621 if (rt->state != STATE_CONNECTING) |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
622 break; |
5123 | 623 case STATE_CONNECTING: |
624 //extract a number from the result | |
625 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) { | |
626 av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n"); | |
627 } else { | |
628 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21)); | |
629 } | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
630 if (rt->is_input) { |
5417 | 631 gen_play(s, rt); |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
632 } else { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
633 gen_publish(s, rt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
634 } |
5123 | 635 rt->state = STATE_READY; |
636 break; | |
637 } | |
638 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) { | |
639 const uint8_t* ptr = pkt->data + 11; | |
640 uint8_t tmpstr[256]; | |
641 | |
642 for (i = 0; i < 2; i++) { | |
643 t = ff_amf_tag_size(ptr, data_end); | |
644 if (t < 0) | |
645 return 1; | |
646 ptr += t; | |
647 } | |
648 t = ff_amf_get_field_value(ptr, data_end, | |
649 "level", tmpstr, sizeof(tmpstr)); | |
650 if (!t && !strcmp(tmpstr, "error")) { | |
651 if (!ff_amf_get_field_value(ptr, data_end, | |
652 "description", tmpstr, sizeof(tmpstr))) | |
653 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr); | |
654 return -1; | |
655 } | |
656 t = ff_amf_get_field_value(ptr, data_end, | |
657 "code", tmpstr, sizeof(tmpstr)); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
658 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING; |
5430
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
659 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED; |
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
660 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED; |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
661 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING; |
5123 | 662 } |
663 break; | |
664 } | |
665 return 0; | |
666 } | |
667 | |
668 /** | |
669 * Interacts with the server by receiving and sending RTMP packets until | |
670 * there is some significant data (media data or expected status notification). | |
671 * | |
672 * @param s reading context | |
5367 | 673 * @param for_header non-zero value tells function to work until it |
674 * gets notification from the server that playing has been started, | |
675 * otherwise function will work until some media data is received (or | |
676 * an error happens) | |
5123 | 677 * @return 0 for successful operation, negative value in case of error |
678 */ | |
679 static int get_packet(URLContext *s, int for_header) | |
680 { | |
681 RTMPContext *rt = s->priv_data; | |
682 int ret; | |
5524
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
683 uint8_t *p; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
684 const uint8_t *next; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
685 uint32_t data_size; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
686 uint32_t ts, cts, pts=0; |
5123 | 687 |
5430
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
688 if (rt->state == STATE_STOPPED) |
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
689 return AVERROR_EOF; |
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
690 |
5420
62329840eb7c
cosmetics: insert space between codeword and left parenthesis
kostya
parents:
5419
diff
changeset
|
691 for (;;) { |
5123 | 692 RTMPPacket rpkt; |
693 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt, | |
5606
2023dcca33ff
another 10l: forgot to change parent condition as well
kostya
parents:
5605
diff
changeset
|
694 rt->chunk_size, rt->prev_pkt[0])) <= 0) { |
5605
32fe8ab7e6b6
10l trocadero: now return value of ff_rtmp_packet_read() has different meaning
kostya
parents:
5524
diff
changeset
|
695 if (ret == 0) { |
5123 | 696 return AVERROR(EAGAIN); |
697 } else { | |
698 return AVERROR(EIO); | |
699 } | |
700 } | |
5668 | 701 rt->bytes_read += ret; |
702 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) { | |
703 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending bytes read report\n"); | |
704 gen_bytes_read(s, rt, rpkt.timestamp + 1); | |
705 rt->last_bytes_read = rt->bytes_read; | |
706 } | |
5123 | 707 |
708 ret = rtmp_parse_result(s, rt, &rpkt); | |
709 if (ret < 0) {//serious error in current packet | |
710 ff_rtmp_packet_destroy(&rpkt); | |
711 return -1; | |
712 } | |
5430
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
713 if (rt->state == STATE_STOPPED) { |
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
714 ff_rtmp_packet_destroy(&rpkt); |
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
715 return AVERROR_EOF; |
bbfed6be7f29
Do not try to interact with RTMP server after "stop" command was received.
kostya
parents:
5420
diff
changeset
|
716 } |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
717 if (for_header && (rt->state == STATE_PLAYING || rt->state == STATE_PUBLISHING)) { |
5123 | 718 ff_rtmp_packet_destroy(&rpkt); |
719 return 0; | |
720 } | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
721 if (!rpkt.data_size || !rt->is_input) { |
5123 | 722 ff_rtmp_packet_destroy(&rpkt); |
723 continue; | |
724 } | |
725 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO || | |
5376 | 726 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) { |
5524
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
727 ts = rpkt.timestamp; |
5123 | 728 |
729 // generate packet header and put data into buffer for FLV demuxer | |
730 rt->flv_off = 0; | |
731 rt->flv_size = rpkt.data_size + 15; | |
732 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size); | |
733 bytestream_put_byte(&p, rpkt.type); | |
734 bytestream_put_be24(&p, rpkt.data_size); | |
735 bytestream_put_be24(&p, ts); | |
736 bytestream_put_byte(&p, ts >> 24); | |
737 bytestream_put_be24(&p, 0); | |
738 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size); | |
739 bytestream_put_be32(&p, 0); | |
740 ff_rtmp_packet_destroy(&rpkt); | |
741 return 0; | |
742 } else if (rpkt.type == RTMP_PT_METADATA) { | |
743 // we got raw FLV data, make it available for FLV demuxer | |
744 rt->flv_off = 0; | |
745 rt->flv_size = rpkt.data_size; | |
746 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size); | |
5524
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
747 /* rewrite timestamps */ |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
748 next = rpkt.data; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
749 ts = rpkt.timestamp; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
750 while (next - rpkt.data < rpkt.data_size - 11) { |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
751 next++; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
752 data_size = bytestream_get_be24(&next); |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
753 p=next; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
754 cts = bytestream_get_be24(&next); |
6055
1e49d06baf93
24l trocadero: RTMP reader forgot to shift high byte of timestamp to its
kostya
parents:
5969
diff
changeset
|
755 cts |= bytestream_get_byte(&next) << 24; |
5524
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
756 if (pts==0) |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
757 pts=cts; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
758 ts += cts - pts; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
759 pts = cts; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
760 bytestream_put_be24(&p, ts); |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
761 bytestream_put_byte(&p, ts >> 24); |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
762 next += data_size + 3 + 4; |
043b36cefe89
Correct timestamps inside FLV data received by RTMP.
kostya
parents:
5523
diff
changeset
|
763 } |
5123 | 764 memcpy(rt->flv_data, rpkt.data, rpkt.data_size); |
765 ff_rtmp_packet_destroy(&rpkt); | |
766 return 0; | |
767 } | |
768 ff_rtmp_packet_destroy(&rpkt); | |
769 } | |
770 return 0; | |
771 } | |
772 | |
773 static int rtmp_close(URLContext *h) | |
774 { | |
775 RTMPContext *rt = h->priv_data; | |
776 | |
5420
62329840eb7c
cosmetics: insert space between codeword and left parenthesis
kostya
parents:
5419
diff
changeset
|
777 if (!rt->is_input) { |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
778 rt->flv_data = NULL; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
779 if (rt->out_pkt.data_size) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
780 ff_rtmp_packet_destroy(&rt->out_pkt); |
5419
006c95a7a3d2
Do not send invokes to RTMP server if we are not connected to it.
kostya
parents:
5417
diff
changeset
|
781 if (rt->state > STATE_FCPUBLISH) |
006c95a7a3d2
Do not send invokes to RTMP server if we are not connected to it.
kostya
parents:
5417
diff
changeset
|
782 gen_fcunpublish_stream(h, rt); |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
783 } |
5419
006c95a7a3d2
Do not send invokes to RTMP server if we are not connected to it.
kostya
parents:
5417
diff
changeset
|
784 if (rt->state > STATE_HANDSHAKED) |
006c95a7a3d2
Do not send invokes to RTMP server if we are not connected to it.
kostya
parents:
5417
diff
changeset
|
785 gen_delete_stream(h, rt); |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
786 |
5123 | 787 av_freep(&rt->flv_data); |
788 url_close(rt->stream); | |
789 av_free(rt); | |
790 return 0; | |
791 } | |
792 | |
793 /** | |
794 * Opens RTMP connection and verifies that the stream can be played. | |
795 * | |
796 * URL syntax: rtmp://server[:port][/app][/playpath] | |
797 * where 'app' is first one or two directories in the path | |
798 * (e.g. /ondemand/, /flash/live/, etc.) | |
799 * and 'playpath' is a file name (the rest of the path, | |
800 * may be prefixed with "mp4:") | |
801 */ | |
802 static int rtmp_open(URLContext *s, const char *uri, int flags) | |
803 { | |
804 RTMPContext *rt; | |
5411 | 805 char proto[8], hostname[256], path[1024], *fname; |
5123 | 806 uint8_t buf[2048]; |
5407 | 807 int port; |
5123 | 808 int ret; |
809 | |
810 rt = av_mallocz(sizeof(RTMPContext)); | |
811 if (!rt) | |
812 return AVERROR(ENOMEM); | |
813 s->priv_data = rt; | |
5407 | 814 rt->is_input = !(flags & URL_WRONLY); |
5123 | 815 |
5775 | 816 ff_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, |
5776 | 817 path, sizeof(path), s->filename); |
5123 | 818 |
819 if (port < 0) | |
820 port = RTMP_DEFAULT_PORT; | |
5756
7c7fe75728dd
Use ff_url_join for assembling URLs, instead of snprintf
mstorsjo
parents:
5668
diff
changeset
|
821 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); |
5123 | 822 |
5377
9313acce85fc
Print error when RTMP protocol can't open connection
kostya
parents:
5376
diff
changeset
|
823 if (url_open(&rt->stream, buf, URL_RDWR) < 0) { |
9313acce85fc
Print error when RTMP protocol can't open connection
kostya
parents:
5376
diff
changeset
|
824 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot open connection %s\n", buf); |
5123 | 825 goto fail; |
5377
9313acce85fc
Print error when RTMP protocol can't open connection
kostya
parents:
5376
diff
changeset
|
826 } |
5123 | 827 |
5417 | 828 rt->state = STATE_START; |
829 if (rtmp_handshake(s, rt)) | |
830 return -1; | |
5123 | 831 |
5417 | 832 rt->chunk_size = 128; |
833 rt->state = STATE_HANDSHAKED; | |
834 //extract "app" part from path | |
835 if (!strncmp(path, "/ondemand/", 10)) { | |
836 fname = path + 10; | |
837 memcpy(rt->app, "ondemand", 9); | |
838 } else { | |
839 char *p = strchr(path + 1, '/'); | |
840 if (!p) { | |
841 fname = path + 1; | |
842 rt->app[0] = '\0'; | |
5123 | 843 } else { |
5417 | 844 char *c = strchr(p + 1, ':'); |
845 fname = strchr(p + 1, '/'); | |
846 if (!fname || c < fname) { | |
847 fname = p + 1; | |
848 av_strlcpy(rt->app, path + 1, p - path); | |
5123 | 849 } else { |
5417 | 850 fname++; |
851 av_strlcpy(rt->app, path + 1, fname - path - 1); | |
5123 | 852 } |
853 } | |
5417 | 854 } |
855 if (!strchr(fname, ':') && | |
856 (!strcmp(fname + strlen(fname) - 4, ".f4v") || | |
857 !strcmp(fname + strlen(fname) - 4, ".mp4"))) { | |
858 memcpy(rt->playpath, "mp4:", 5); | |
859 } else { | |
860 rt->playpath[0] = 0; | |
861 } | |
862 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5); | |
5123 | 863 |
5668 | 864 rt->client_report_size = 1048576; |
865 rt->bytes_read = 0; | |
866 rt->last_bytes_read = 0; | |
867 | |
5417 | 868 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n", |
869 proto, path, rt->app, rt->playpath); | |
870 gen_connect(s, rt, proto, hostname, port); | |
5123 | 871 |
5417 | 872 do { |
873 ret = get_packet(s, 1); | |
874 } while (ret == EAGAIN); | |
875 if (ret < 0) | |
876 goto fail; | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
877 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
878 if (rt->is_input) { |
5123 | 879 // generate FLV header for demuxer |
880 rt->flv_size = 13; | |
881 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size); | |
882 rt->flv_off = 0; | |
883 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size); | |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
884 } else { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
885 rt->flv_size = 0; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
886 rt->flv_data = NULL; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
887 rt->flv_off = 0; |
5123 | 888 } |
889 | |
890 s->max_packet_size = url_get_max_packet_size(rt->stream); | |
891 s->is_streamed = 1; | |
892 return 0; | |
893 | |
894 fail: | |
895 rtmp_close(s); | |
896 return AVERROR(EIO); | |
897 } | |
898 | |
899 static int rtmp_read(URLContext *s, uint8_t *buf, int size) | |
900 { | |
901 RTMPContext *rt = s->priv_data; | |
902 int orig_size = size; | |
903 int ret; | |
904 | |
905 while (size > 0) { | |
906 int data_left = rt->flv_size - rt->flv_off; | |
907 | |
908 if (data_left >= size) { | |
909 memcpy(buf, rt->flv_data + rt->flv_off, size); | |
910 rt->flv_off += size; | |
911 return orig_size; | |
912 } | |
913 if (data_left > 0) { | |
914 memcpy(buf, rt->flv_data + rt->flv_off, data_left); | |
915 buf += data_left; | |
916 size -= data_left; | |
917 rt->flv_off = rt->flv_size; | |
918 } | |
919 if ((ret = get_packet(s, 0)) < 0) | |
920 return ret; | |
921 } | |
922 return orig_size; | |
923 } | |
924 | |
6068 | 925 static int rtmp_write(URLContext *h, const uint8_t *buf, int size) |
5123 | 926 { |
5416
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
927 RTMPContext *rt = h->priv_data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
928 int size_temp = size; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
929 int pktsize, pkttype; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
930 uint32_t ts; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
931 const uint8_t *buf_temp = buf; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
932 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
933 if (size < 11) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
934 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "FLV packet too small %d\n", size); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
935 return 0; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
936 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
937 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
938 do { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
939 if (!rt->flv_off) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
940 //skip flv header |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
941 if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
942 buf_temp += 9 + 4; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
943 size_temp -= 9 + 4; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
944 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
945 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
946 pkttype = bytestream_get_byte(&buf_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
947 pktsize = bytestream_get_be24(&buf_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
948 ts = bytestream_get_be24(&buf_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
949 ts |= bytestream_get_byte(&buf_temp) << 24; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
950 bytestream_get_be24(&buf_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
951 size_temp -= 11; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
952 rt->flv_size = pktsize; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
953 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
954 //force 12bytes header |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
955 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) || |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
956 pkttype == RTMP_PT_NOTIFY) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
957 if (pkttype == RTMP_PT_NOTIFY) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
958 pktsize += 16; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
959 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
960 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
961 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
962 //this can be a big packet, it's better to send it right here |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
963 ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL, pkttype, ts, pktsize); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
964 rt->out_pkt.extra = rt->main_channel_id; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
965 rt->flv_data = rt->out_pkt.data; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
966 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
967 if (pkttype == RTMP_PT_NOTIFY) |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
968 ff_amf_write_string(&rt->flv_data, "@setDataFrame"); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
969 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
970 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
971 if (rt->flv_size - rt->flv_off > size_temp) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
972 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
973 rt->flv_off += size_temp; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
974 } else { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
975 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
976 rt->flv_off += rt->flv_size - rt->flv_off; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
977 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
978 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
979 if (rt->flv_off == rt->flv_size) { |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
980 bytestream_get_be32(&buf_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
981 |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
982 ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
983 ff_rtmp_packet_destroy(&rt->out_pkt); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
984 rt->flv_size = 0; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
985 rt->flv_off = 0; |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
986 } |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
987 } while (buf_temp - buf < size_temp); |
e01b6917b3cf
Implement RTMP output (publishing FLV stream to RTMP server).
kostya
parents:
5414
diff
changeset
|
988 return size; |
5123 | 989 } |
990 | |
991 URLProtocol rtmp_protocol = { | |
992 "rtmp", | |
993 rtmp_open, | |
994 rtmp_read, | |
995 rtmp_write, | |
996 NULL, /* seek */ | |
997 rtmp_close, | |
998 }; |