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