Originally committed as revision 20799 to svn://svn.ffmpeg.org/ffmpeg/trunk
| ... | ... |
@@ -322,3 +322,113 @@ int ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end, |
| 322 | 322 |
} |
| 323 | 323 |
return -1; |
| 324 | 324 |
} |
| 325 |
+ |
|
| 326 |
+static const char* rtmp_packet_type(int type) |
|
| 327 |
+{
|
|
| 328 |
+ switch (type) {
|
|
| 329 |
+ case RTMP_PT_CHUNK_SIZE: return "chunk size"; |
|
| 330 |
+ case RTMP_PT_BYTES_READ: return "bytes read"; |
|
| 331 |
+ case RTMP_PT_PING: return "ping"; |
|
| 332 |
+ case RTMP_PT_SERVER_BW: return "server bandwidth"; |
|
| 333 |
+ case RTMP_PT_CLIENT_BW: return "client bandwidth"; |
|
| 334 |
+ case RTMP_PT_AUDIO: return "audio packet"; |
|
| 335 |
+ case RTMP_PT_VIDEO: return "video packet"; |
|
| 336 |
+ case RTMP_PT_FLEX_STREAM: return "Flex shared stream"; |
|
| 337 |
+ case RTMP_PT_FLEX_OBJECT: return "Flex shared object"; |
|
| 338 |
+ case RTMP_PT_FLEX_MESSAGE: return "Flex shared message"; |
|
| 339 |
+ case RTMP_PT_NOTIFY: return "notification"; |
|
| 340 |
+ case RTMP_PT_SHARED_OBJ: return "shared object"; |
|
| 341 |
+ case RTMP_PT_INVOKE: return "invoke"; |
|
| 342 |
+ case RTMP_PT_METADATA: return "metadata"; |
|
| 343 |
+ default: return "unknown"; |
|
| 344 |
+ } |
|
| 345 |
+} |
|
| 346 |
+ |
|
| 347 |
+static void ff_amf_tag_contents(void *ctx, const uint8_t *data, const uint8_t *data_end) |
|
| 348 |
+{
|
|
| 349 |
+ const uint8_t *base = data; |
|
| 350 |
+ int i, size; |
|
| 351 |
+ char buf[1024]; |
|
| 352 |
+ |
|
| 353 |
+ if (data >= data_end) |
|
| 354 |
+ return; |
|
| 355 |
+ switch (*data++) {
|
|
| 356 |
+ case AMF_DATA_TYPE_NUMBER: |
|
| 357 |
+ av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2dbl(AV_RB64(data))); |
|
| 358 |
+ return; |
|
| 359 |
+ case AMF_DATA_TYPE_BOOL: |
|
| 360 |
+ av_log(ctx, AV_LOG_DEBUG, " bool %d\n", *data); |
|
| 361 |
+ return; |
|
| 362 |
+ case AMF_DATA_TYPE_STRING: |
|
| 363 |
+ case AMF_DATA_TYPE_LONG_STRING: |
|
| 364 |
+ if (data[-1] == AMF_DATA_TYPE_STRING) {
|
|
| 365 |
+ size = bytestream_get_be16(&data); |
|
| 366 |
+ } else {
|
|
| 367 |
+ size = bytestream_get_be32(data); |
|
| 368 |
+ } |
|
| 369 |
+ size = FFMIN(size, 1023); |
|
| 370 |
+ memcpy(buf, data, size); |
|
| 371 |
+ buf[size] = 0; |
|
| 372 |
+ av_log(ctx, AV_LOG_DEBUG, " string '%s'\n", buf); |
|
| 373 |
+ return; |
|
| 374 |
+ case AMF_DATA_TYPE_NULL: |
|
| 375 |
+ av_log(ctx, AV_LOG_DEBUG, " NULL\n"); |
|
| 376 |
+ return; |
|
| 377 |
+ case AMF_DATA_TYPE_ARRAY: |
|
| 378 |
+ data += 4; |
|
| 379 |
+ case AMF_DATA_TYPE_OBJECT: |
|
| 380 |
+ av_log(ctx, AV_LOG_DEBUG, " {\n");
|
|
| 381 |
+ for (;;) {
|
|
| 382 |
+ int size = bytestream_get_be16(&data); |
|
| 383 |
+ int t; |
|
| 384 |
+ memcpy(buf, data, size); |
|
| 385 |
+ buf[size] = 0; |
|
| 386 |
+ if (!size) {
|
|
| 387 |
+ av_log(ctx, AV_LOG_DEBUG, " }\n"); |
|
| 388 |
+ data++; |
|
| 389 |
+ break; |
|
| 390 |
+ } |
|
| 391 |
+ if (data + size >= data_end || data + size < data) |
|
| 392 |
+ return; |
|
| 393 |
+ data += size; |
|
| 394 |
+ av_log(ctx, AV_LOG_DEBUG, " %s: ", buf); |
|
| 395 |
+ ff_amf_tag_contents(ctx, data, data_end); |
|
| 396 |
+ t = ff_amf_tag_size(data, data_end); |
|
| 397 |
+ if (t < 0 || data + t >= data_end) |
|
| 398 |
+ return; |
|
| 399 |
+ data += t; |
|
| 400 |
+ } |
|
| 401 |
+ return; |
|
| 402 |
+ case AMF_DATA_TYPE_OBJECT_END: |
|
| 403 |
+ av_log(ctx, AV_LOG_DEBUG, " }\n"); |
|
| 404 |
+ return; |
|
| 405 |
+ default: |
|
| 406 |
+ return; |
|
| 407 |
+ } |
|
| 408 |
+} |
|
| 409 |
+ |
|
| 410 |
+void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p) |
|
| 411 |
+{
|
|
| 412 |
+ av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n", |
|
| 413 |
+ rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->data_size); |
|
| 414 |
+ if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) {
|
|
| 415 |
+ uint8_t *src = p->data, *src_end = p->data + p->data_size; |
|
| 416 |
+ while (src < src_end) {
|
|
| 417 |
+ int sz; |
|
| 418 |
+ ff_amf_tag_contents(ctx, src, src_end); |
|
| 419 |
+ sz = ff_amf_tag_size(src, src_end); |
|
| 420 |
+ if (sz < 0) |
|
| 421 |
+ break; |
|
| 422 |
+ src += sz; |
|
| 423 |
+ } |
|
| 424 |
+ } else if (p->type == RTMP_PT_SERVER_BW){
|
|
| 425 |
+ av_log(ctx, AV_LOG_DEBUG, "Server BW = %d\n", AV_RB32(p->data)); |
|
| 426 |
+ } else if (p->type == RTMP_PT_CLIENT_BW){
|
|
| 427 |
+ av_log(ctx, AV_LOG_DEBUG, "Client BW = %d\n", AV_RB32(p->data)); |
|
| 428 |
+ } else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) {
|
|
| 429 |
+ int i; |
|
| 430 |
+ for (i = 0; i < p->data_size; i++) |
|
| 431 |
+ av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]); |
|
| 432 |
+ av_log(ctx, AV_LOG_DEBUG, "\n"); |
|
| 433 |
+ } |
|
| 434 |
+} |
| ... | ... |
@@ -129,6 +129,14 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *p, |
| 129 | 129 |
int chunk_size, RTMPPacket *prev_pkt); |
| 130 | 130 |
|
| 131 | 131 |
/** |
| 132 |
+ * Prints information and contents of RTMP packet. |
|
| 133 |
+ * |
|
| 134 |
+ * @param h output context |
|
| 135 |
+ * @param p packet to dump |
|
| 136 |
+ */ |
|
| 137 |
+void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p); |
|
| 138 |
+ |
|
| 139 |
+/** |
|
| 132 | 140 |
* @defgroup amffuncs functions used to work with AMF format (which is also used in .flv) |
| 133 | 141 |
* @see amf_* funcs in libavformat/flvdec.c |
| 134 | 142 |
* @{
|
| ... | ... |
@@ -43,6 +43,8 @@ |
| 43 | 43 |
#define LOG_CONTEXT s |
| 44 | 44 |
#endif |
| 45 | 45 |
|
| 46 |
+//#define DEBUG |
|
| 47 |
+ |
|
| 46 | 48 |
/** RTMP protocol handler state */ |
| 47 | 49 |
typedef enum {
|
| 48 | 50 |
STATE_START, ///< client has not done anything yet |
| ... | ... |
@@ -529,6 +531,10 @@ static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt) |
| 529 | 529 |
int i, t; |
| 530 | 530 |
const uint8_t *data_end = pkt->data + pkt->data_size; |
| 531 | 531 |
|
| 532 |
+#ifdef DEBUG |
|
| 533 |
+ ff_rtmp_packet_dump(LOG_CONTEXT, pkt); |
|
| 534 |
+#endif |
|
| 535 |
+ |
|
| 532 | 536 |
switch (pkt->type) {
|
| 533 | 537 |
case RTMP_PT_CHUNK_SIZE: |
| 534 | 538 |
if (pkt->data_size != 4) {
|