annotate rtmpproto.c @ 5295:08ec48911f20 libavformat

Last parameter in RTMP "play" call was optional and some servers seem not to understand it, so drop it.
author kostya
date Sun, 18 Oct 2009 06:54:04 +0000
parents dd04eacd063b
children f0711d97bff4
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5123
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
1 /*
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
2 * RTMP network protocol
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
3 * Copyright (c) 2009 Kostya Shishkov
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
4 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
5 * This file is part of FFmpeg.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
6 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
7 * FFmpeg is free software; you can redistribute it and/or
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
8 * modify it under the terms of the GNU Lesser General Public
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
9 * License as published by the Free Software Foundation; either
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
10 * version 2.1 of the License, or (at your option) any later version.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
11 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
12 * FFmpeg is distributed in the hope that it will be useful,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
15 * Lesser General Public License for more details.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
16 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
17 * You should have received a copy of the GNU Lesser General Public
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
18 * License along with FFmpeg; if not, write to the Free Software
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
20 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
21
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
22 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
23 * @file libavformat/rtmpproto.c
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
24 * RTMP protocol
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
25 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
26
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
27 #include "libavcodec/bytestream.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
28 #include "libavutil/avstring.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
29 #include "libavutil/lfg.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
30 #include "libavutil/sha.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
31 #include "avformat.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
32
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
33 #include "network.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
34
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
35 #include "flv.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
36 #include "rtmp.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
37 #include "rtmppkt.h"
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
38
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
39 /* we can't use av_log() with URLContext yet... */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
40 #if LIBAVFORMAT_VERSION_MAJOR < 53
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
41 #define LOG_CONTEXT NULL
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
42 #else
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
43 #define LOG_CONTEXT s
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
44 #endif
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
45
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
46 /** RTMP protocol handler state */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
47 typedef enum {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
48 STATE_START, ///< client has not done anything yet
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
49 STATE_HANDSHAKED, ///< client has performed handshake
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
50 STATE_CONNECTING, ///< client connected to server successfully
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
51 STATE_READY, ///< client has sent all needed commands and waits for server reply
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
52 STATE_PLAYING, ///< client has started receiving multimedia data from server
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
53 } ClientState;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
54
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
55 /** protocol handler context */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
56 typedef struct RTMPContext {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
57 URLContext* stream; ///< TCP stream used in interactions with RTMP server
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
58 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
59 int chunk_size; ///< size of the chunks RTMP packets are divided into
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
60 char playpath[256]; ///< path to filename to play (with possible "mp4:" prefix)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
61 ClientState state; ///< current state
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
62 int main_channel_id; ///< an additional channel ID which is used for some invocations
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
63 uint8_t* flv_data; ///< buffer with data for demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
64 int flv_size; ///< current buffer size
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
65 int flv_off; ///< number of bytes read from current buffer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
66 uint32_t video_ts; ///< current video timestamp in milliseconds
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
67 uint32_t audio_ts; ///< current audio timestamp in milliseconds
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
68 } RTMPContext;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
69
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
70 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
71 /** Client key used for digest signing */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
72 static const uint8_t rtmp_player_key[] = {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
73 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
74 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
75
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
76 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
77 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
78 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
79 };
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
80
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
81 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
82 /** Key used for RTMP server digest signing */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
83 static const uint8_t rtmp_server_key[] = {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
84 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
85 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
86 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
87
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
88 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
89 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
90 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
91 };
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
92
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
93 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
94 * Generates 'connect' call and sends it to the server.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
95 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
96 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
97 const char *host, int port, const char *app)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
98 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
99 RTMPPacket pkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
100 uint8_t ver[32], *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
101 char tcurl[512];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
102
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
103 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 4096);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
104 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
105
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
106 snprintf(tcurl, sizeof(tcurl), "%s://%s:%d/%s", proto, host, port, app);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
107 ff_amf_write_string(&p, "connect");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
108 ff_amf_write_number(&p, 1.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
109 ff_amf_write_object_start(&p);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
110 ff_amf_write_field_name(&p, "app");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
111 ff_amf_write_string(&p, app);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
112
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
113 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
114 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
115 ff_amf_write_field_name(&p, "flashVer");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
116 ff_amf_write_string(&p, ver);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
117 ff_amf_write_field_name(&p, "tcUrl");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
118 ff_amf_write_string(&p, tcurl);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
119 ff_amf_write_field_name(&p, "fpad");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
120 ff_amf_write_bool(&p, 0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
121 ff_amf_write_field_name(&p, "capabilities");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
122 ff_amf_write_number(&p, 15.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
123 ff_amf_write_field_name(&p, "audioCodecs");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
124 ff_amf_write_number(&p, 1639.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
125 ff_amf_write_field_name(&p, "videoCodecs");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
126 ff_amf_write_number(&p, 252.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
127 ff_amf_write_field_name(&p, "videoFunction");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
128 ff_amf_write_number(&p, 1.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
129 ff_amf_write_object_end(&p);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
130
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
131 pkt.data_size = p - pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
132
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
133 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
134 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
135
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
136 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
137 * Generates 'createStream' call and sends it to the server. It should make
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
138 * the server allocate some channel for media streams.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
139 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
140 static void gen_create_stream(URLContext *s, RTMPContext *rt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
141 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
142 RTMPPacket pkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
143 uint8_t *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
144
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
145 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Creating stream...\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
146 ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE, 0, 25);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
147
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
148 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
149 ff_amf_write_string(&p, "createStream");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
150 ff_amf_write_number(&p, 3.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
151 ff_amf_write_null(&p);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
152
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
153 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
154 ff_rtmp_packet_destroy(&pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
155 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
156
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
157 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
158 * Generates 'play' call and sends it to the server, then pings the server
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
159 * to start actual playing.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
160 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
161 static void gen_play(URLContext *s, RTMPContext *rt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
162 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
163 RTMPPacket pkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
164 uint8_t *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
165
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
166 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
167 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
168 20 + strlen(rt->playpath));
5123
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
169 pkt.extra = rt->main_channel_id;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
170
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
171 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
172 ff_amf_write_string(&p, "play");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
173 ff_amf_write_number(&p, 0.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
174 ff_amf_write_null(&p);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
175 ff_amf_write_string(&p, rt->playpath);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
176
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
177 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
178 ff_rtmp_packet_destroy(&pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
179
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
180 // set client buffer time disguised in ping packet
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
181 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
182
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
183 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
184 bytestream_put_be16(&p, 3);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
185 bytestream_put_be32(&p, 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
186 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
187
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
188 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
189 ff_rtmp_packet_destroy(&pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
190 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
191
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
192 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
193 * Generates ping reply and sends it to the server.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
194 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
195 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
196 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
197 RTMPPacket pkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
198 uint8_t *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
199
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
200 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timestamp + 1, 6);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
201 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
202 bytestream_put_be16(&p, 7);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
203 bytestream_put_be32(&p, AV_RB32(ppkt->data+2) + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
204 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
205 ff_rtmp_packet_destroy(&pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
206 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
207
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
208 //TODO: Move HMAC code somewhere. Eventually.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
209 #define HMAC_IPAD_VAL 0x36
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
210 #define HMAC_OPAD_VAL 0x5C
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
211
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
212 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
213 * Calculates HMAC-SHA2 digest for RTMP handshake packets.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
214 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
215 * @param src input buffer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
216 * @param len input buffer length (should be 1536)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
217 * @param gap offset in buffer where 32 bytes should not be taken into account
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
218 * when calculating digest (since it will be used to store that digest)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
219 * @param key digest key
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
220 * @param keylen digest key length
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
221 * @param dst buffer where calculated digest will be stored (32 bytes)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
222 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
223 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
224 const uint8_t *key, int keylen, uint8_t *dst)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
225 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
226 struct AVSHA *sha;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
227 uint8_t hmac_buf[64+32] = {0};
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
228 int i;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
229
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
230 sha = av_mallocz(av_sha_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
231
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
232 if (keylen < 64) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
233 memcpy(hmac_buf, key, keylen);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
234 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
235 av_sha_init(sha, 256);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
236 av_sha_update(sha,key, keylen);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
237 av_sha_final(sha, hmac_buf);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
238 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
239 for (i = 0; i < 64; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
240 hmac_buf[i] ^= HMAC_IPAD_VAL;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
241
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
242 av_sha_init(sha, 256);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
243 av_sha_update(sha, hmac_buf, 64);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
244 if (gap <= 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
245 av_sha_update(sha, src, len);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
246 } else { //skip 32 bytes used for storing digest
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
247 av_sha_update(sha, src, gap);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
248 av_sha_update(sha, src + gap + 32, len - gap - 32);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
249 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
250 av_sha_final(sha, hmac_buf + 64);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
251
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
252 for (i = 0; i < 64; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
253 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
254 av_sha_init(sha, 256);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
255 av_sha_update(sha, hmac_buf, 64+32);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
256 av_sha_final(sha, dst);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
257
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
258 av_free(sha);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
259 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
260
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
261 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
262 * Puts HMAC-SHA2 digest of packet data (except for the bytes where this digest
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
263 * will be stored) into that packet.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
264 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
265 * @param buf handshake data (1536 bytes)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
266 * @return offset to the digest inside input data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
267 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
268 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
269 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
270 int i, digest_pos = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
271
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
272 for (i = 8; i < 12; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
273 digest_pos += buf[i];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
274 digest_pos = (digest_pos % 728) + 12;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
275
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
276 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
277 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
278 buf + digest_pos);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
279 return digest_pos;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
280 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
281
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
282 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
283 * Verifies that the received server response has the expected digest value.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
284 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
285 * @param buf handshake data received from the server (1536 bytes)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
286 * @param off position to search digest offset from
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
287 * @return 0 if digest is valid, digest position otherwise
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
288 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
289 static int rtmp_validate_digest(uint8_t *buf, int off)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
290 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
291 int i, digest_pos = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
292 uint8_t digest[32];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
293
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
294 for (i = 0; i < 4; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
295 digest_pos += buf[i + off];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
296 digest_pos = (digest_pos % 728) + off + 4;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
297
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
298 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
299 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
300 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
301 if (!memcmp(digest, buf + digest_pos, 32))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
302 return digest_pos;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
303 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
304 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
305
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
306 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
307 * Performs handshake with the server by means of exchanging pseudorandom data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
308 * signed with HMAC-SHA2 digest.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
309 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
310 * @return 0 if handshake succeeds, negative value otherwise
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
311 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
312 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
313 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
314 AVLFG rnd;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
315 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
316 3, // unencrypted data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
317 0, 0, 0, 0, // client uptime
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
318 RTMP_CLIENT_VER1,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
319 RTMP_CLIENT_VER2,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
320 RTMP_CLIENT_VER3,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
321 RTMP_CLIENT_VER4,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
322 };
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
323 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
324 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
325 int i;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
326 int server_pos, client_pos;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
327 uint8_t digest[32];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
328
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
329 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
330
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
331 av_lfg_init(&rnd, 0xDEADC0DE);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
332 // generate handshake packet - 1536 bytes of pseudorandom data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
333 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
334 tosend[i] = av_lfg_get(&rnd) >> 24;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
335 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
336
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
337 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
338 i = url_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
339 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
340 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
341 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
342 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
343 i = url_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
344 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
345 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
346 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
347 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
348
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
349 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
350 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
351
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
352 server_pos = rtmp_validate_digest(serverdata + 1, 772);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
353 if (!server_pos) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
354 server_pos = rtmp_validate_digest(serverdata + 1, 8);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
355 if (!server_pos) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
356 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
357 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
358 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
359 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
360
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
361 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
362 rtmp_server_key, sizeof(rtmp_server_key),
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
363 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
364 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
365 digest, 32,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
366 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
367 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
368 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
369 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
370 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
371
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
372 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
373 tosend[i] = av_lfg_get(&rnd) >> 24;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
374 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
375 rtmp_player_key, sizeof(rtmp_player_key),
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
376 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
377 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
378 digest, 32,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
379 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
380
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
381 // write reply back to the server
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
382 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
383 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
384 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
385
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
386 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
387 * Parses received packet and may perform some action depending on
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
388 * the packet contents.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
389 * @return 0 for no errors, negative values for serious errors which prevent
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
390 * further communications, positive values for uncritical errors
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
391 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
392 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
393 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
394 int i, t;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
395 const uint8_t *data_end = pkt->data + pkt->data_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
396
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
397 switch (pkt->type) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
398 case RTMP_PT_CHUNK_SIZE:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
399 if (pkt->data_size != 4) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
400 av_log(LOG_CONTEXT, AV_LOG_ERROR,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
401 "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
402 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
403 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
404 rt->chunk_size = AV_RB32(pkt->data);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
405 if (rt->chunk_size <= 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
406 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
407 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
408 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
409 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
410 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
411 case RTMP_PT_PING:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
412 t = AV_RB16(pkt->data);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
413 if (t == 6)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
414 gen_pong(s, rt, pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
415 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
416 case RTMP_PT_INVOKE:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
417 //TODO: check for the messages sent for wrong state?
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
418 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
419 uint8_t tmpstr[256];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
420
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
421 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
422 "description", tmpstr, sizeof(tmpstr)))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
423 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
424 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
425 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
426 switch (rt->state) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
427 case STATE_HANDSHAKED:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
428 gen_create_stream(s, rt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
429 rt->state = STATE_CONNECTING;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
430 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
431 case STATE_CONNECTING:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
432 //extract a number from the result
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
433 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
434 av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
435 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
436 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
437 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
438 gen_play(s, rt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
439 rt->state = STATE_READY;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
440 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
441 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
442 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
443 const uint8_t* ptr = pkt->data + 11;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
444 uint8_t tmpstr[256];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
445 int t;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
446
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
447 for (i = 0; i < 2; i++) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
448 t = ff_amf_tag_size(ptr, data_end);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
449 if (t < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
450 return 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
451 ptr += t;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
452 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
453 t = ff_amf_get_field_value(ptr, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
454 "level", tmpstr, sizeof(tmpstr));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
455 if (!t && !strcmp(tmpstr, "error")) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
456 if (!ff_amf_get_field_value(ptr, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
457 "description", tmpstr, sizeof(tmpstr)))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
458 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
459 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
460 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
461 t = ff_amf_get_field_value(ptr, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
462 "code", tmpstr, sizeof(tmpstr));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
463 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
464 rt->state = STATE_PLAYING;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
465 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
466 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
467 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
468 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
469 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
470 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
471 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
472
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
473 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
474 * Interacts with the server by receiving and sending RTMP packets until
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
475 * there is some significant data (media data or expected status notification).
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
476 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
477 * @param s reading context
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
478 * @param for_header non-zero value tells function to work until it gets notification from the server that playing has been started, otherwise function will work until some media data is received (or an error happens)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
479 * @return 0 for successful operation, negative value in case of error
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
480 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
481 static int get_packet(URLContext *s, int for_header)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
482 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
483 RTMPContext *rt = s->priv_data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
484 int ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
485
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
486 for(;;) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
487 RTMPPacket rpkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
488 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
489 rt->chunk_size, rt->prev_pkt[0])) != 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
490 if (ret > 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
491 return AVERROR(EAGAIN);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
492 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
493 return AVERROR(EIO);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
494 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
495 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
496
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
497 ret = rtmp_parse_result(s, rt, &rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
498 if (ret < 0) {//serious error in current packet
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
499 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
500 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
501 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
502 if (for_header && rt->state == STATE_PLAYING) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
503 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
504 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
505 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
506 if (!rpkt.data_size) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
507 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
508 continue;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
509 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
510 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
511 rpkt.type == RTMP_PT_NOTIFY) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
512 uint8_t *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
513 uint32_t ts = rpkt.timestamp;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
514
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
515 if (rpkt.type == RTMP_PT_VIDEO) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
516 rt->video_ts += rpkt.timestamp;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
517 ts = rt->video_ts;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
518 } else if (rpkt.type == RTMP_PT_AUDIO) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
519 rt->audio_ts += rpkt.timestamp;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
520 ts = rt->audio_ts;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
521 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
522 // generate packet header and put data into buffer for FLV demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
523 rt->flv_off = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
524 rt->flv_size = rpkt.data_size + 15;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
525 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
526 bytestream_put_byte(&p, rpkt.type);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
527 bytestream_put_be24(&p, rpkt.data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
528 bytestream_put_be24(&p, ts);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
529 bytestream_put_byte(&p, ts >> 24);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
530 bytestream_put_be24(&p, 0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
531 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
532 bytestream_put_be32(&p, 0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
533 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
534 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
535 } else if (rpkt.type == RTMP_PT_METADATA) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
536 // we got raw FLV data, make it available for FLV demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
537 rt->flv_off = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
538 rt->flv_size = rpkt.data_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
539 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
540 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
541 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
542 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
543 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
544 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
545 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
546 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
547 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
548
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
549 static int rtmp_close(URLContext *h)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
550 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
551 RTMPContext *rt = h->priv_data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
552
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
553 av_freep(&rt->flv_data);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
554 url_close(rt->stream);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
555 av_free(rt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
556 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
557 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
558
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
559 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
560 * Opens RTMP connection and verifies that the stream can be played.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
561 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
562 * URL syntax: rtmp://server[:port][/app][/playpath]
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
563 * where 'app' is first one or two directories in the path
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
564 * (e.g. /ondemand/, /flash/live/, etc.)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
565 * and 'playpath' is a file name (the rest of the path,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
566 * may be prefixed with "mp4:")
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
567 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
568 static int rtmp_open(URLContext *s, const char *uri, int flags)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
569 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
570 RTMPContext *rt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
571 char proto[8], hostname[256], path[1024], app[128], *fname;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
572 uint8_t buf[2048];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
573 int port, is_input;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
574 int ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
575
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
576 is_input = !(flags & URL_WRONLY);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
577
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
578 rt = av_mallocz(sizeof(RTMPContext));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
579 if (!rt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
580 return AVERROR(ENOMEM);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
581 s->priv_data = rt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
582
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
583 url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
584 path, sizeof(path), s->filename);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
585
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
586 if (port < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
587 port = RTMP_DEFAULT_PORT;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
588 snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
589
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
590 if (url_open(&rt->stream, buf, URL_RDWR) < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
591 goto fail;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
592
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
593 if (!is_input) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
594 av_log(LOG_CONTEXT, AV_LOG_ERROR, "RTMP output is not supported yet.\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
595 goto fail;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
596 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
597 rt->state = STATE_START;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
598 if (rtmp_handshake(s, rt))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
599 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
600
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
601 rt->chunk_size = 128;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
602 rt->state = STATE_HANDSHAKED;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
603 //extract "app" part from path
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
604 if (!strncmp(path, "/ondemand/", 10)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
605 fname = path + 10;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
606 memcpy(app, "ondemand", 9);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
607 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
608 char *p = strchr(path + 1, '/');
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
609 if (!p) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
610 fname = path + 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
611 app[0] = '\0';
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
612 } else {
5214
dd04eacd063b Do not include "mp4:" prefix from RTMP URL into "app" path or second time
kostya
parents: 5123
diff changeset
613 char *c = strchr(p + 1, ':');
5123
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
614 fname = strchr(p + 1, '/');
5214
dd04eacd063b Do not include "mp4:" prefix from RTMP URL into "app" path or second time
kostya
parents: 5123
diff changeset
615 if (!fname || c < fname) {
5123
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
616 fname = p + 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
617 av_strlcpy(app, path + 1, p - path);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
618 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
619 fname++;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
620 av_strlcpy(app, path + 1, fname - path - 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
621 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
622 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
623 }
5214
dd04eacd063b Do not include "mp4:" prefix from RTMP URL into "app" path or second time
kostya
parents: 5123
diff changeset
624 if (!strchr(fname, ':') &&
dd04eacd063b Do not include "mp4:" prefix from RTMP URL into "app" path or second time
kostya
parents: 5123
diff changeset
625 (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
dd04eacd063b Do not include "mp4:" prefix from RTMP URL into "app" path or second time
kostya
parents: 5123
diff changeset
626 !strcmp(fname + strlen(fname) - 4, ".mp4"))) {
5123
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
627 memcpy(rt->playpath, "mp4:", 5);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
628 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
629 rt->playpath[0] = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
630 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
631 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
632
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
633 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
634 proto, path, app, rt->playpath);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
635 gen_connect(s, rt, proto, hostname, port, app);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
636
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
637 do {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
638 ret = get_packet(s, 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
639 } while (ret == EAGAIN);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
640 if (ret < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
641 goto fail;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
642 // generate FLV header for demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
643 rt->flv_size = 13;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
644 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
645 rt->flv_off = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
646 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
647 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
648
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
649 s->max_packet_size = url_get_max_packet_size(rt->stream);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
650 s->is_streamed = 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
651 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
652
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
653 fail:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
654 rtmp_close(s);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
655 return AVERROR(EIO);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
656 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
657
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
658 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
659 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
660 RTMPContext *rt = s->priv_data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
661 int orig_size = size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
662 int ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
663
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
664 while (size > 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
665 int data_left = rt->flv_size - rt->flv_off;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
666
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
667 if (data_left >= size) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
668 memcpy(buf, rt->flv_data + rt->flv_off, size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
669 rt->flv_off += size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
670 return orig_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
671 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
672 if (data_left > 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
673 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
674 buf += data_left;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
675 size -= data_left;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
676 rt->flv_off = rt->flv_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
677 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
678 if ((ret = get_packet(s, 0)) < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
679 return ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
680 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
681 return orig_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
682 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
683
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
684 static int rtmp_write(URLContext *h, uint8_t *buf, int size)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
685 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
686 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
687 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
688
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
689 URLProtocol rtmp_protocol = {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
690 "rtmp",
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
691 rtmp_open,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
692 rtmp_read,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
693 rtmp_write,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
694 NULL, /* seek */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
695 rtmp_close,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
696 };