annotate rtmpproto.c @ 5123:cc34279f0fab libavformat

RTMP protocol support (as a client)
author kostya
date Fri, 31 Jul 2009 06:49:36 +0000
parents
children dd04eacd063b
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,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
168 29 + strlen(rt->playpath));
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 ff_amf_write_number(&p, 0.0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
177
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
178 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
179 ff_rtmp_packet_destroy(&pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
180
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
181 // set client buffer time disguised in ping packet
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
182 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, 1, 10);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
183
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
184 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
185 bytestream_put_be16(&p, 3);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
186 bytestream_put_be32(&p, 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
187 bytestream_put_be32(&p, 256); //TODO: what is a good value here?
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
188
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
189 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
190 ff_rtmp_packet_destroy(&pkt);
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
194 * Generates ping reply and sends it to the server.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
195 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
196 static void gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
197 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
198 RTMPPacket pkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
199 uint8_t *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
200
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
201 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
202 p = pkt.data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
203 bytestream_put_be16(&p, 7);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
204 bytestream_put_be32(&p, AV_RB32(ppkt->data+2) + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
205 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
206 ff_rtmp_packet_destroy(&pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
207 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
208
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
209 //TODO: Move HMAC code somewhere. Eventually.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
210 #define HMAC_IPAD_VAL 0x36
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
211 #define HMAC_OPAD_VAL 0x5C
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
212
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
213 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
214 * Calculates HMAC-SHA2 digest for RTMP handshake packets.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
215 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
216 * @param src input buffer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
217 * @param len input buffer length (should be 1536)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
218 * @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
219 * when calculating digest (since it will be used to store that digest)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
220 * @param key digest key
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
221 * @param keylen digest key length
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
222 * @param dst buffer where calculated digest will be stored (32 bytes)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
223 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
224 static void rtmp_calc_digest(const uint8_t *src, int len, int gap,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
225 const uint8_t *key, int keylen, uint8_t *dst)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
226 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
227 struct AVSHA *sha;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
228 uint8_t hmac_buf[64+32] = {0};
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
229 int i;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
230
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
231 sha = av_mallocz(av_sha_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
232
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
233 if (keylen < 64) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
234 memcpy(hmac_buf, key, keylen);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
235 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
236 av_sha_init(sha, 256);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
237 av_sha_update(sha,key, keylen);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
238 av_sha_final(sha, hmac_buf);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
239 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
240 for (i = 0; i < 64; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
241 hmac_buf[i] ^= HMAC_IPAD_VAL;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
242
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
243 av_sha_init(sha, 256);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
244 av_sha_update(sha, hmac_buf, 64);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
245 if (gap <= 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
246 av_sha_update(sha, src, len);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
247 } else { //skip 32 bytes used for storing digest
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
248 av_sha_update(sha, src, gap);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
249 av_sha_update(sha, src + gap + 32, len - gap - 32);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
250 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
251 av_sha_final(sha, hmac_buf + 64);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
252
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
253 for (i = 0; i < 64; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
254 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
255 av_sha_init(sha, 256);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
256 av_sha_update(sha, hmac_buf, 64+32);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
257 av_sha_final(sha, dst);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
258
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
259 av_free(sha);
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
263 * 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
264 * will be stored) into that packet.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
265 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
266 * @param buf handshake data (1536 bytes)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
267 * @return offset to the digest inside input data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
268 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
269 static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
270 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
271 int i, digest_pos = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
272
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
273 for (i = 8; i < 12; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
274 digest_pos += buf[i];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
275 digest_pos = (digest_pos % 728) + 12;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
276
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
277 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
278 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
279 buf + digest_pos);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
280 return digest_pos;
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
284 * Verifies that the received server response has the expected digest value.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
285 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
286 * @param buf handshake data received from the server (1536 bytes)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
287 * @param off position to search digest offset from
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
288 * @return 0 if digest is valid, digest position otherwise
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
289 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
290 static int rtmp_validate_digest(uint8_t *buf, int off)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
291 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
292 int i, digest_pos = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
293 uint8_t digest[32];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
294
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
295 for (i = 0; i < 4; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
296 digest_pos += buf[i + off];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
297 digest_pos = (digest_pos % 728) + off + 4;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
298
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
299 rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
300 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
301 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
302 if (!memcmp(digest, buf + digest_pos, 32))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
303 return digest_pos;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
304 return 0;
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
308 * Performs handshake with the server by means of exchanging pseudorandom data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
309 * signed with HMAC-SHA2 digest.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
310 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
311 * @return 0 if handshake succeeds, negative value otherwise
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
312 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
313 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
314 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
315 AVLFG rnd;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
316 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
317 3, // unencrypted data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
318 0, 0, 0, 0, // client uptime
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
319 RTMP_CLIENT_VER1,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
320 RTMP_CLIENT_VER2,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
321 RTMP_CLIENT_VER3,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
322 RTMP_CLIENT_VER4,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
323 };
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
324 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
325 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
326 int i;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
327 int server_pos, client_pos;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
328 uint8_t digest[32];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
329
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
330 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Handshaking...\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
331
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
332 av_lfg_init(&rnd, 0xDEADC0DE);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
333 // generate handshake packet - 1536 bytes of pseudorandom data
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
334 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
335 tosend[i] = av_lfg_get(&rnd) >> 24;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
336 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
337
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
338 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
339 i = url_read_complete(rt->stream, serverdata, RTMP_HANDSHAKE_PACKET_SIZE + 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
340 if (i != RTMP_HANDSHAKE_PACKET_SIZE + 1) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
341 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
342 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
343 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
344 i = url_read_complete(rt->stream, clientdata, RTMP_HANDSHAKE_PACKET_SIZE);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
345 if (i != RTMP_HANDSHAKE_PACKET_SIZE) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
346 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
347 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
348 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
349
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
350 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
351 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
352
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
353 server_pos = rtmp_validate_digest(serverdata + 1, 772);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
354 if (!server_pos) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
355 server_pos = rtmp_validate_digest(serverdata + 1, 8);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
356 if (!server_pos) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
357 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server response validating failed\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
358 return -1;
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
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
362 rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
363 rtmp_server_key, sizeof(rtmp_server_key),
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
364 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
365 rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE-32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
366 digest, 32,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
367 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
368 if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
369 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Signature mismatch\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
370 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
371 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
372
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
373 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
374 tosend[i] = av_lfg_get(&rnd) >> 24;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
375 rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
376 rtmp_player_key, sizeof(rtmp_player_key),
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
377 digest);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
378 rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
379 digest, 32,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
380 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
381
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
382 // write reply back to the server
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
383 url_write(rt->stream, tosend, RTMP_HANDSHAKE_PACKET_SIZE);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
384 return 0;
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
388 * Parses received packet and may perform some action depending on
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
389 * the packet contents.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
390 * @return 0 for no errors, negative values for serious errors which prevent
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
391 * further communications, positive values for uncritical errors
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
392 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
393 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
394 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
395 int i, t;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
396 const uint8_t *data_end = pkt->data + pkt->data_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
397
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
398 switch (pkt->type) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
399 case RTMP_PT_CHUNK_SIZE:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
400 if (pkt->data_size != 4) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
401 av_log(LOG_CONTEXT, AV_LOG_ERROR,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
402 "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
403 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
404 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
405 rt->chunk_size = AV_RB32(pkt->data);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
406 if (rt->chunk_size <= 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
407 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
408 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
409 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
410 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
411 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
412 case RTMP_PT_PING:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
413 t = AV_RB16(pkt->data);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
414 if (t == 6)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
415 gen_pong(s, rt, pkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
416 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
417 case RTMP_PT_INVOKE:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
418 //TODO: check for the messages sent for wrong state?
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
419 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
420 uint8_t tmpstr[256];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
421
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
422 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
423 "description", tmpstr, sizeof(tmpstr)))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
424 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
425 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
426 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
427 switch (rt->state) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
428 case STATE_HANDSHAKED:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
429 gen_create_stream(s, rt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
430 rt->state = STATE_CONNECTING;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
431 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
432 case STATE_CONNECTING:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
433 //extract a number from the result
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
434 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
435 av_log(LOG_CONTEXT, AV_LOG_WARNING, "Unexpected reply on connect()\n");
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
436 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
437 rt->main_channel_id = (int) av_int2dbl(AV_RB64(pkt->data + 21));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
438 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
439 gen_play(s, rt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
440 rt->state = STATE_READY;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
441 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
442 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
443 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
444 const uint8_t* ptr = pkt->data + 11;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
445 uint8_t tmpstr[256];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
446 int t;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
447
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
448 for (i = 0; i < 2; i++) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
449 t = ff_amf_tag_size(ptr, data_end);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
450 if (t < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
451 return 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
452 ptr += t;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
453 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
454 t = ff_amf_get_field_value(ptr, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
455 "level", tmpstr, sizeof(tmpstr));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
456 if (!t && !strcmp(tmpstr, "error")) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
457 if (!ff_amf_get_field_value(ptr, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
458 "description", tmpstr, sizeof(tmpstr)))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
459 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
460 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
461 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
462 t = ff_amf_get_field_value(ptr, data_end,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
463 "code", tmpstr, sizeof(tmpstr));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
464 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
465 rt->state = STATE_PLAYING;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
466 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
467 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
468 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
469 break;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
470 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
471 return 0;
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
475 * Interacts with the server by receiving and sending RTMP packets until
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
476 * there is some significant data (media data or expected status notification).
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
477 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
478 * @param s reading context
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
479 * @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
480 * @return 0 for successful operation, negative value in case of error
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
481 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
482 static int get_packet(URLContext *s, int for_header)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
483 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
484 RTMPContext *rt = s->priv_data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
485 int ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
486
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
487 for(;;) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
488 RTMPPacket rpkt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
489 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
490 rt->chunk_size, rt->prev_pkt[0])) != 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
491 if (ret > 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
492 return AVERROR(EAGAIN);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
493 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
494 return AVERROR(EIO);
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
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
498 ret = rtmp_parse_result(s, rt, &rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
499 if (ret < 0) {//serious error in current packet
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
500 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
501 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
502 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
503 if (for_header && rt->state == STATE_PLAYING) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
504 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
505 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
506 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
507 if (!rpkt.data_size) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
508 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
509 continue;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
510 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
511 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
512 rpkt.type == RTMP_PT_NOTIFY) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
513 uint8_t *p;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
514 uint32_t ts = rpkt.timestamp;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
515
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
516 if (rpkt.type == RTMP_PT_VIDEO) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
517 rt->video_ts += rpkt.timestamp;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
518 ts = rt->video_ts;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
519 } else if (rpkt.type == RTMP_PT_AUDIO) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
520 rt->audio_ts += rpkt.timestamp;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
521 ts = rt->audio_ts;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
522 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
523 // generate packet header and put data into buffer for FLV demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
524 rt->flv_off = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
525 rt->flv_size = rpkt.data_size + 15;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
526 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
527 bytestream_put_byte(&p, rpkt.type);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
528 bytestream_put_be24(&p, rpkt.data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
529 bytestream_put_be24(&p, ts);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
530 bytestream_put_byte(&p, ts >> 24);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
531 bytestream_put_be24(&p, 0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
532 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
533 bytestream_put_be32(&p, 0);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
534 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
535 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
536 } else if (rpkt.type == RTMP_PT_METADATA) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
537 // we got raw FLV data, make it available for FLV demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
538 rt->flv_off = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
539 rt->flv_size = rpkt.data_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
540 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
541 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
542 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
543 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
544 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
545 ff_rtmp_packet_destroy(&rpkt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
546 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
547 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
548 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
549
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
550 static int rtmp_close(URLContext *h)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
551 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
552 RTMPContext *rt = h->priv_data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
553
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
554 av_freep(&rt->flv_data);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
555 url_close(rt->stream);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
556 av_free(rt);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
557 return 0;
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 /**
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
561 * Opens RTMP connection and verifies that the stream can be played.
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
562 *
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
563 * URL syntax: rtmp://server[:port][/app][/playpath]
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
564 * where 'app' is first one or two directories in the path
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
565 * (e.g. /ondemand/, /flash/live/, etc.)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
566 * and 'playpath' is a file name (the rest of the path,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
567 * may be prefixed with "mp4:")
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
568 */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
569 static int rtmp_open(URLContext *s, const char *uri, int flags)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
570 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
571 RTMPContext *rt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
572 char proto[8], hostname[256], path[1024], app[128], *fname;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
573 uint8_t buf[2048];
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
574 int port, is_input;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
575 int ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
576
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
577 is_input = !(flags & URL_WRONLY);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
578
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
579 rt = av_mallocz(sizeof(RTMPContext));
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
580 if (!rt)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
581 return AVERROR(ENOMEM);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
582 s->priv_data = rt;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
583
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
584 url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
585 path, sizeof(path), s->filename);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
586
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
587 if (port < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
588 port = RTMP_DEFAULT_PORT;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
589 snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
590
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
591 if (url_open(&rt->stream, buf, URL_RDWR) < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
592 goto fail;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
593
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
594 if (!is_input) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
595 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
596 goto fail;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
597 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
598 rt->state = STATE_START;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
599 if (rtmp_handshake(s, rt))
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
600 return -1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
601
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
602 rt->chunk_size = 128;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
603 rt->state = STATE_HANDSHAKED;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
604 //extract "app" part from path
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
605 if (!strncmp(path, "/ondemand/", 10)) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
606 fname = path + 10;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
607 memcpy(app, "ondemand", 9);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
608 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
609 char *p = strchr(path + 1, '/');
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
610 if (!p) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
611 fname = path + 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
612 app[0] = '\0';
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
613 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
614 fname = strchr(p + 1, '/');
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
615 if (!fname) {
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 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
624 if (!strcmp(fname + strlen(fname) - 4, ".f4v") ||
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
625 !strcmp(fname + strlen(fname) - 4, ".mp4")) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
626 memcpy(rt->playpath, "mp4:", 5);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
627 } else {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
628 rt->playpath[0] = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
629 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
630 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
631
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
632 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
633 proto, path, app, rt->playpath);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
634 gen_connect(s, rt, proto, hostname, port, app);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
635
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
636 do {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
637 ret = get_packet(s, 1);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
638 } while (ret == EAGAIN);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
639 if (ret < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
640 goto fail;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
641 // generate FLV header for demuxer
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
642 rt->flv_size = 13;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
643 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
644 rt->flv_off = 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
645 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
646 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
647
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
648 s->max_packet_size = url_get_max_packet_size(rt->stream);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
649 s->is_streamed = 1;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
650 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
651
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
652 fail:
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
653 rtmp_close(s);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
654 return AVERROR(EIO);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
655 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
656
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
657 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
658 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
659 RTMPContext *rt = s->priv_data;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
660 int orig_size = size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
661 int ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
662
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
663 while (size > 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
664 int data_left = rt->flv_size - rt->flv_off;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
665
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
666 if (data_left >= size) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
667 memcpy(buf, rt->flv_data + rt->flv_off, size);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
668 rt->flv_off += size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
669 return orig_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
670 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
671 if (data_left > 0) {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
672 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
673 buf += data_left;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
674 size -= data_left;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
675 rt->flv_off = rt->flv_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
676 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
677 if ((ret = get_packet(s, 0)) < 0)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
678 return ret;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
679 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
680 return orig_size;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
681 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
682
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
683 static int rtmp_write(URLContext *h, uint8_t *buf, int size)
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
684 {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
685 return 0;
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
686 }
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
687
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
688 URLProtocol rtmp_protocol = {
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
689 "rtmp",
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
690 rtmp_open,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
691 rtmp_read,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
692 rtmp_write,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
693 NULL, /* seek */
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
694 rtmp_close,
cc34279f0fab RTMP protocol support (as a client)
kostya
parents:
diff changeset
695 };