Mercurial > libavformat.hg
annotate rtmppkt.c @ 5786:7d670040187e libavformat
In mpegts muxer, search for h264 aud nal, it might not be the first nal.
Improve ther error message when bitstream is malformated and tell user to use
the bitstream filter.
author | bcoudurier |
---|---|
date | Mon, 08 Mar 2010 23:59:05 +0000 |
parents | 6d4ba584fcf2 |
children |
rev | line source |
---|---|
5123 | 1 /* |
2 * RTMP input format | |
3 * Copyright (c) 2009 Kostya Shishkov | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 #include "libavcodec/bytestream.h" | |
23 #include "libavutil/avstring.h" | |
24 #include "avformat.h" | |
25 | |
26 #include "rtmppkt.h" | |
27 #include "flv.h" | |
28 | |
29 void ff_amf_write_bool(uint8_t **dst, int val) | |
30 { | |
31 bytestream_put_byte(dst, AMF_DATA_TYPE_BOOL); | |
32 bytestream_put_byte(dst, val); | |
33 } | |
34 | |
35 void ff_amf_write_number(uint8_t **dst, double val) | |
36 { | |
37 bytestream_put_byte(dst, AMF_DATA_TYPE_NUMBER); | |
38 bytestream_put_be64(dst, av_dbl2int(val)); | |
39 } | |
40 | |
41 void ff_amf_write_string(uint8_t **dst, const char *str) | |
42 { | |
43 bytestream_put_byte(dst, AMF_DATA_TYPE_STRING); | |
44 bytestream_put_be16(dst, strlen(str)); | |
45 bytestream_put_buffer(dst, str, strlen(str)); | |
46 } | |
47 | |
48 void ff_amf_write_null(uint8_t **dst) | |
49 { | |
50 bytestream_put_byte(dst, AMF_DATA_TYPE_NULL); | |
51 } | |
52 | |
53 void ff_amf_write_object_start(uint8_t **dst) | |
54 { | |
55 bytestream_put_byte(dst, AMF_DATA_TYPE_OBJECT); | |
56 } | |
57 | |
58 void ff_amf_write_field_name(uint8_t **dst, const char *str) | |
59 { | |
60 bytestream_put_be16(dst, strlen(str)); | |
61 bytestream_put_buffer(dst, str, strlen(str)); | |
62 } | |
63 | |
64 void ff_amf_write_object_end(uint8_t **dst) | |
65 { | |
66 /* first two bytes are field name length = 0, | |
67 * AMF object should end with it and end marker | |
68 */ | |
69 bytestream_put_be24(dst, AMF_DATA_TYPE_OBJECT_END); | |
70 } | |
71 | |
72 int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, | |
73 int chunk_size, RTMPPacket *prev_pkt) | |
74 { | |
75 uint8_t hdr, t, buf[16]; | |
76 int channel_id, timestamp, data_size, offset = 0; | |
77 uint32_t extra = 0; | |
5360
a00cc1aac80d
Use enum instead of integer types where appropriate.
cehoyos
parents:
5297
diff
changeset
|
78 enum RTMPPacketType type; |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
79 int size = 0; |
5123 | 80 |
81 if (url_read(h, &hdr, 1) != 1) | |
82 return AVERROR(EIO); | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
83 size++; |
5123 | 84 channel_id = hdr & 0x3F; |
85 | |
5297 | 86 if (channel_id < 2) { //special case for channel number >= 64 |
87 buf[1] = 0; | |
88 if (url_read_complete(h, buf, channel_id + 1) != channel_id + 1) | |
89 return AVERROR(EIO); | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
90 size += channel_id + 1; |
5297 | 91 channel_id = AV_RL16(buf) + 64; |
92 } | |
5123 | 93 data_size = prev_pkt[channel_id].data_size; |
94 type = prev_pkt[channel_id].type; | |
95 extra = prev_pkt[channel_id].extra; | |
96 | |
97 hdr >>= 6; | |
98 if (hdr == RTMP_PS_ONEBYTE) { | |
5410
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
99 timestamp = prev_pkt[channel_id].ts_delta; |
5123 | 100 } else { |
101 if (url_read_complete(h, buf, 3) != 3) | |
102 return AVERROR(EIO); | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
103 size += 3; |
5123 | 104 timestamp = AV_RB24(buf); |
105 if (hdr != RTMP_PS_FOURBYTES) { | |
106 if (url_read_complete(h, buf, 3) != 3) | |
107 return AVERROR(EIO); | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
108 size += 3; |
5123 | 109 data_size = AV_RB24(buf); |
5399
f042e114451f
7l trocadero: reading right into enum variable may cause unwanted effects, use
kostya
parents:
5378
diff
changeset
|
110 if (url_read_complete(h, buf, 1) != 1) |
5123 | 111 return AVERROR(EIO); |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
112 size++; |
5399
f042e114451f
7l trocadero: reading right into enum variable may cause unwanted effects, use
kostya
parents:
5378
diff
changeset
|
113 type = buf[0]; |
5123 | 114 if (hdr == RTMP_PS_TWELVEBYTES) { |
115 if (url_read_complete(h, buf, 4) != 4) | |
116 return AVERROR(EIO); | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
117 size += 4; |
5123 | 118 extra = AV_RL32(buf); |
119 } | |
120 } | |
5400
c7d1e90d4935
Read and write extended timestamps for RTMP packets.
kostya
parents:
5399
diff
changeset
|
121 if (timestamp == 0xFFFFFF) { |
c7d1e90d4935
Read and write extended timestamps for RTMP packets.
kostya
parents:
5399
diff
changeset
|
122 if (url_read_complete(h, buf, 4) != 4) |
c7d1e90d4935
Read and write extended timestamps for RTMP packets.
kostya
parents:
5399
diff
changeset
|
123 return AVERROR(EIO); |
c7d1e90d4935
Read and write extended timestamps for RTMP packets.
kostya
parents:
5399
diff
changeset
|
124 timestamp = AV_RB32(buf); |
c7d1e90d4935
Read and write extended timestamps for RTMP packets.
kostya
parents:
5399
diff
changeset
|
125 } |
5123 | 126 } |
5410
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
127 if (hdr != RTMP_PS_TWELVEBYTES) |
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
128 timestamp += prev_pkt[channel_id].timestamp; |
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
129 |
5123 | 130 if (ff_rtmp_packet_create(p, channel_id, type, timestamp, data_size)) |
131 return -1; | |
132 p->extra = extra; | |
133 // save history | |
134 prev_pkt[channel_id].channel_id = channel_id; | |
135 prev_pkt[channel_id].type = type; | |
136 prev_pkt[channel_id].data_size = data_size; | |
5410
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
137 prev_pkt[channel_id].ts_delta = timestamp - prev_pkt[channel_id].timestamp; |
5123 | 138 prev_pkt[channel_id].timestamp = timestamp; |
139 prev_pkt[channel_id].extra = extra; | |
140 while (data_size > 0) { | |
141 int toread = FFMIN(data_size, chunk_size); | |
142 if (url_read_complete(h, p->data + offset, toread) != toread) { | |
143 ff_rtmp_packet_destroy(p); | |
144 return AVERROR(EIO); | |
145 } | |
146 data_size -= chunk_size; | |
147 offset += chunk_size; | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
148 size += chunk_size; |
5123 | 149 if (data_size > 0) { |
150 url_read_complete(h, &t, 1); //marker | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
151 size++; |
5123 | 152 if (t != (0xC0 + channel_id)) |
153 return -1; | |
154 } | |
155 } | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
156 return size; |
5123 | 157 } |
158 | |
159 int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, | |
160 int chunk_size, RTMPPacket *prev_pkt) | |
161 { | |
162 uint8_t pkt_hdr[16], *p = pkt_hdr; | |
163 int mode = RTMP_PS_TWELVEBYTES; | |
164 int off = 0; | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
165 int size = 0; |
5603
8efa6bc0752e
cosmetics: add an empty line between variable declarations and code
kostya
parents:
5473
diff
changeset
|
166 |
5410
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
167 pkt->ts_delta = pkt->timestamp - prev_pkt[pkt->channel_id].timestamp; |
5123 | 168 |
5415 | 169 //if channel_id = 0, this is first presentation of prev_pkt, send full hdr. |
170 if (prev_pkt[pkt->channel_id].channel_id && | |
171 pkt->extra == prev_pkt[pkt->channel_id].extra) { | |
172 if (pkt->type == prev_pkt[pkt->channel_id].type && | |
173 pkt->data_size == prev_pkt[pkt->channel_id].data_size) { | |
174 mode = RTMP_PS_FOURBYTES; | |
175 if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta) | |
176 mode = RTMP_PS_ONEBYTE; | |
177 } else { | |
178 mode = RTMP_PS_EIGHTBYTES; | |
179 } | |
180 } | |
181 | |
5401
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
182 if (pkt->channel_id < 64) { |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
183 bytestream_put_byte(&p, pkt->channel_id | (mode << 6)); |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
184 } else if (pkt->channel_id < 64 + 256) { |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
185 bytestream_put_byte(&p, 0 | (mode << 6)); |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
186 bytestream_put_byte(&p, pkt->channel_id - 64); |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
187 } else { |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
188 bytestream_put_byte(&p, 1 | (mode << 6)); |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
189 bytestream_put_le16(&p, pkt->channel_id - 64); |
432e1b6e1568
Write header for RTMP packets with channel_id >= 64 correctly
kostya
parents:
5400
diff
changeset
|
190 } |
5123 | 191 if (mode != RTMP_PS_ONEBYTE) { |
5403
6f2d4070ab5b
Write timestamp deltas, not timestamps, for RTMP packets with partial header
kostya
parents:
5402
diff
changeset
|
192 uint32_t timestamp = pkt->timestamp; |
6f2d4070ab5b
Write timestamp deltas, not timestamps, for RTMP packets with partial header
kostya
parents:
5402
diff
changeset
|
193 if (mode != RTMP_PS_TWELVEBYTES) |
5410
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
194 timestamp = pkt->ts_delta; |
5403
6f2d4070ab5b
Write timestamp deltas, not timestamps, for RTMP packets with partial header
kostya
parents:
5402
diff
changeset
|
195 bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp); |
5123 | 196 if (mode != RTMP_PS_FOURBYTES) { |
197 bytestream_put_be24(&p, pkt->data_size); | |
198 bytestream_put_byte(&p, pkt->type); | |
199 if (mode == RTMP_PS_TWELVEBYTES) | |
200 bytestream_put_le32(&p, pkt->extra); | |
201 } | |
5403
6f2d4070ab5b
Write timestamp deltas, not timestamps, for RTMP packets with partial header
kostya
parents:
5402
diff
changeset
|
202 if (timestamp >= 0xFFFFFF) |
6f2d4070ab5b
Write timestamp deltas, not timestamps, for RTMP packets with partial header
kostya
parents:
5402
diff
changeset
|
203 bytestream_put_be32(&p, timestamp); |
5123 | 204 } |
5415 | 205 // save history |
206 prev_pkt[pkt->channel_id].channel_id = pkt->channel_id; | |
207 prev_pkt[pkt->channel_id].type = pkt->type; | |
208 prev_pkt[pkt->channel_id].data_size = pkt->data_size; | |
209 prev_pkt[pkt->channel_id].timestamp = pkt->timestamp; | |
210 if (mode != RTMP_PS_TWELVEBYTES) { | |
211 prev_pkt[pkt->channel_id].ts_delta = pkt->ts_delta; | |
212 } else { | |
213 prev_pkt[pkt->channel_id].ts_delta = pkt->timestamp; | |
214 } | |
215 prev_pkt[pkt->channel_id].extra = pkt->extra; | |
216 | |
5123 | 217 url_write(h, pkt_hdr, p-pkt_hdr); |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
218 size = p - pkt_hdr + pkt->data_size; |
5123 | 219 while (off < pkt->data_size) { |
220 int towrite = FFMIN(chunk_size, pkt->data_size - off); | |
221 url_write(h, pkt->data + off, towrite); | |
222 off += towrite; | |
223 if (off < pkt->data_size) { | |
224 uint8_t marker = 0xC0 | pkt->channel_id; | |
225 url_write(h, &marker, 1); | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
226 size++; |
5123 | 227 } |
228 } | |
5604
81b2509db2ad
Make RTMP send/receive packet functions report number of bytes read or sent.
kostya
parents:
5603
diff
changeset
|
229 return size; |
5123 | 230 } |
231 | |
232 int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, | |
233 int timestamp, int size) | |
234 { | |
235 pkt->data = av_malloc(size); | |
236 if (!pkt->data) | |
237 return AVERROR(ENOMEM); | |
238 pkt->data_size = size; | |
239 pkt->channel_id = channel_id; | |
240 pkt->type = type; | |
241 pkt->timestamp = timestamp; | |
242 pkt->extra = 0; | |
5410
f66e3c131106
RTMP packets with one-byte header use previous packet timestamp difference, so
kostya
parents:
5403
diff
changeset
|
243 pkt->ts_delta = 0; |
5123 | 244 |
245 return 0; | |
246 } | |
247 | |
248 void ff_rtmp_packet_destroy(RTMPPacket *pkt) | |
249 { | |
250 if (!pkt) | |
251 return; | |
252 av_freep(&pkt->data); | |
253 pkt->data_size = 0; | |
254 } | |
255 | |
256 int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end) | |
257 { | |
258 const uint8_t *base = data; | |
259 | |
260 if (data >= data_end) | |
261 return -1; | |
262 switch (*data++) { | |
263 case AMF_DATA_TYPE_NUMBER: return 9; | |
264 case AMF_DATA_TYPE_BOOL: return 2; | |
265 case AMF_DATA_TYPE_STRING: return 3 + AV_RB16(data); | |
266 case AMF_DATA_TYPE_LONG_STRING: return 5 + AV_RB32(data); | |
267 case AMF_DATA_TYPE_NULL: return 1; | |
268 case AMF_DATA_TYPE_ARRAY: | |
269 data += 4; | |
270 case AMF_DATA_TYPE_OBJECT: | |
271 for (;;) { | |
272 int size = bytestream_get_be16(&data); | |
273 int t; | |
274 if (!size) { | |
275 data++; | |
276 break; | |
277 } | |
278 if (data + size >= data_end || data + size < data) | |
279 return -1; | |
280 data += size; | |
281 t = ff_amf_tag_size(data, data_end); | |
282 if (t < 0 || data + t >= data_end) | |
283 return -1; | |
284 data += t; | |
285 } | |
286 return data - base; | |
287 case AMF_DATA_TYPE_OBJECT_END: return 1; | |
288 default: return -1; | |
289 } | |
290 } | |
291 | |
292 int ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end, | |
293 const uint8_t *name, uint8_t *dst, int dst_size) | |
294 { | |
295 int namelen = strlen(name); | |
296 int len; | |
297 | |
5378
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
298 while (*data != AMF_DATA_TYPE_OBJECT && data < data_end) { |
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
299 len = ff_amf_tag_size(data, data_end); |
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
300 if (len < 0) |
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
301 len = data_end - data; |
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
302 data += len; |
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
303 } |
5123 | 304 if (data_end - data < 3) |
305 return -1; | |
5378
c22a1e94e80f
When searching for AMF object field value, try to find that object first
kostya
parents:
5360
diff
changeset
|
306 data++; |
5123 | 307 for (;;) { |
308 int size = bytestream_get_be16(&data); | |
309 if (!size) | |
310 break; | |
311 if (data + size >= data_end || data + size < data) | |
312 return -1; | |
313 data += size; | |
314 if (size == namelen && !memcmp(data-size, name, namelen)) { | |
315 switch (*data++) { | |
316 case AMF_DATA_TYPE_NUMBER: | |
317 snprintf(dst, dst_size, "%g", av_int2dbl(AV_RB64(data))); | |
318 break; | |
319 case AMF_DATA_TYPE_BOOL: | |
320 snprintf(dst, dst_size, "%s", *data ? "true" : "false"); | |
321 break; | |
322 case AMF_DATA_TYPE_STRING: | |
323 len = bytestream_get_be16(&data); | |
324 av_strlcpy(dst, data, FFMIN(len+1, dst_size)); | |
325 break; | |
326 default: | |
327 return -1; | |
328 } | |
329 return 0; | |
330 } | |
331 len = ff_amf_tag_size(data, data_end); | |
332 if (len < 0 || data + len >= data_end || data + len < data) | |
333 return -1; | |
334 data += len; | |
335 } | |
336 return -1; | |
337 } | |
5432 | 338 |
339 static const char* rtmp_packet_type(int type) | |
340 { | |
341 switch (type) { | |
342 case RTMP_PT_CHUNK_SIZE: return "chunk size"; | |
343 case RTMP_PT_BYTES_READ: return "bytes read"; | |
344 case RTMP_PT_PING: return "ping"; | |
345 case RTMP_PT_SERVER_BW: return "server bandwidth"; | |
346 case RTMP_PT_CLIENT_BW: return "client bandwidth"; | |
347 case RTMP_PT_AUDIO: return "audio packet"; | |
348 case RTMP_PT_VIDEO: return "video packet"; | |
349 case RTMP_PT_FLEX_STREAM: return "Flex shared stream"; | |
350 case RTMP_PT_FLEX_OBJECT: return "Flex shared object"; | |
351 case RTMP_PT_FLEX_MESSAGE: return "Flex shared message"; | |
352 case RTMP_PT_NOTIFY: return "notification"; | |
353 case RTMP_PT_SHARED_OBJ: return "shared object"; | |
354 case RTMP_PT_INVOKE: return "invoke"; | |
355 case RTMP_PT_METADATA: return "metadata"; | |
356 default: return "unknown"; | |
357 } | |
358 } | |
359 | |
360 static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *data_end) | |
361 { | |
5473 | 362 int size; |
5432 | 363 char buf[1024]; |
364 | |
365 if (data >= data_end) | |
366 return; | |
367 switch (*data++) { | |
368 case AMF_DATA_TYPE_NUMBER: | |
369 av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2dbl(AV_RB64(data))); | |
370 return; | |
371 case AMF_DATA_TYPE_BOOL: | |
372 av_log(ctx, AV_LOG_DEBUG, " bool %d\n", *data); | |
373 return; | |
374 case AMF_DATA_TYPE_STRING: | |
375 case AMF_DATA_TYPE_LONG_STRING: | |
376 if (data[-1] == AMF_DATA_TYPE_STRING) { | |
377 size = bytestream_get_be16(&data); | |
378 } else { | |
5765
6d4ba584fcf2
1l trocadero: forgot reference operator on bytestream_get_be32() argument
kostya
parents:
5604
diff
changeset
|
379 size = bytestream_get_be32(&data); |
5432 | 380 } |
381 size = FFMIN(size, 1023); | |
382 memcpy(buf, data, size); | |
383 buf[size] = 0; | |
384 av_log(ctx, AV_LOG_DEBUG, " string '%s'\n", buf); | |
385 return; | |
386 case AMF_DATA_TYPE_NULL: | |
387 av_log(ctx, AV_LOG_DEBUG, " NULL\n"); | |
388 return; | |
389 case AMF_DATA_TYPE_ARRAY: | |
390 data += 4; | |
391 case AMF_DATA_TYPE_OBJECT: | |
392 av_log(ctx, AV_LOG_DEBUG, " {\n"); | |
393 for (;;) { | |
394 int size = bytestream_get_be16(&data); | |
395 int t; | |
396 memcpy(buf, data, size); | |
397 buf[size] = 0; | |
398 if (!size) { | |
399 av_log(ctx, AV_LOG_DEBUG, " }\n"); | |
400 data++; | |
401 break; | |
402 } | |
403 if (data + size >= data_end || data + size < data) | |
404 return; | |
405 data += size; | |
406 av_log(ctx, AV_LOG_DEBUG, " %s: ", buf); | |
407 ff_amf_tag_contents(ctx, data, data_end); | |
408 t = ff_amf_tag_size(data, data_end); | |
409 if (t < 0 || data + t >= data_end) | |
410 return; | |
411 data += t; | |
412 } | |
413 return; | |
414 case AMF_DATA_TYPE_OBJECT_END: | |
415 av_log(ctx, AV_LOG_DEBUG, " }\n"); | |
416 return; | |
417 default: | |
418 return; | |
419 } | |
420 } | |
421 | |
422 void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p) | |
423 { | |
424 av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n", | |
425 rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->data_size); | |
426 if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) { | |
427 uint8_t *src = p->data, *src_end = p->data + p->data_size; | |
428 while (src < src_end) { | |
429 int sz; | |
430 ff_amf_tag_contents(ctx, src, src_end); | |
431 sz = ff_amf_tag_size(src, src_end); | |
432 if (sz < 0) | |
433 break; | |
434 src += sz; | |
435 } | |
436 } else if (p->type == RTMP_PT_SERVER_BW){ | |
437 av_log(ctx, AV_LOG_DEBUG, "Server BW = %d\n", AV_RB32(p->data)); | |
438 } else if (p->type == RTMP_PT_CLIENT_BW){ | |
439 av_log(ctx, AV_LOG_DEBUG, "Client BW = %d\n", AV_RB32(p->data)); | |
440 } else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) { | |
441 int i; | |
442 for (i = 0; i < p->data_size; i++) | |
443 av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]); | |
444 av_log(ctx, AV_LOG_DEBUG, "\n"); | |
445 } | |
446 } |