[soc]: r4510 - in rtmp: rtmppkt.c rtmppkt.h rtmpproto.c
Author: kostya Date: Wed Jun 24 09:30:29 2009 New Revision: 4510 Log: Introduce AMF parsing functions and use them for parsing RTMP onStatus message Modified: rtmp/rtmppkt.c rtmp/rtmppkt.h rtmp/rtmpproto.c Modified: rtmp/rtmppkt.c ============================================================================== --- rtmp/rtmppkt.c Tue Jun 23 20:40:10 2009 (r4509) +++ rtmp/rtmppkt.c Wed Jun 24 09:30:29 2009 (r4510) @@ -193,6 +193,70 @@ void rtmp_packet_destroy(RTMPPacket *pkt pkt->data_size = 0; } +int rtmp_amf_skip_data(const uint8_t *data) +{ + const uint8_t *base = data; + + switch (*data++) { + case AMF_NUMBER: return 9; + case AMF_BOOLEAN: return 2; + case AMF_STRING: return 3 + AV_RB16(data); + case AMF_LONG_STRING: return 5 + AV_RB32(data); + case AMF_NULL: return 1; + case AMF_ECMA_ARRAY: + data += 4; + case AMF_OBJECT: + for (;;) { + int size = bytestream_get_be16(&data); + if (!size) { + data++; + break; + } + data += size; + data += rtmp_amf_skip_data(data); + } + return data - base; + case AMF_OBJECT_END: return 1; + default: return -1; + } +} + +int rtmp_amf_find_field(const uint8_t *data, const uint8_t *name, + uint8_t *dst, int dst_size) +{ + int namelen = strlen(name); + int len; + + if (*data++ != AMF_OBJECT) + return -1; + for (;;) { + int size = bytestream_get_be16(&data); + if (!size) + break; + data += size; + if (size == namelen && !memcmp(data-size, name, namelen)) { + switch (*data++) { + case AMF_NUMBER: + snprintf(dst, dst_size, "%g", av_int2dbl(AV_RB64(data))); + return 0; + case AMF_BOOLEAN: + snprintf(dst, dst_size, "%s", *data ? "true" : "false"); + return 0; + case AMF_STRING: + len = bytestream_get_be16(&data); + av_strlcpy(dst, data, FFMIN(len+1, dst_size)); + return 0; + default: + return -1; + } + } + len = rtmp_amf_skip_data(data); + if (len < 0) + return -1; + data += len; + } + return -1; +} static void parse_amf(const uint8_t *data, int size) { Modified: rtmp/rtmppkt.h ============================================================================== --- rtmp/rtmppkt.h Tue Jun 23 20:40:10 2009 (r4509) +++ rtmp/rtmppkt.h Wed Jun 24 09:30:29 2009 (r4510) @@ -119,6 +119,11 @@ int rtmp_packet_write(URLContext *h, RTM int rtmp_amf_tag_size(int type, const void *data); +int rtmp_amf_skip_data(const uint8_t *data); + +int rtmp_amf_find_field(const uint8_t *data, const uint8_t *name, + uint8_t *dst, int dst_size); + void rtmp_amf_write_tag(uint8_t **dst, AMFType type, const void *data); void rtmp_packet_inspect(RTMPPacket *pkt); Modified: rtmp/rtmpproto.c ============================================================================== --- rtmp/rtmpproto.c Tue Jun 23 20:40:10 2009 (r4509) +++ rtmp/rtmpproto.c Wed Jun 24 09:30:29 2009 (r4510) @@ -386,8 +386,23 @@ static int rtmp_parse_result(URLContext break; } } - if (!memcmp(pkt->data, "\002\000\008onStatus", 11)) { - //TODO: catch stream close event + if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) { + const uint8_t* ptr = pkt->data + 11; + uint8_t tmpstr[256]; + int t; + + for (i = 0; i < 2; i++) { + t = rtmp_amf_skip_data(ptr); + if (t < 0) + return 1; + ptr += t; + } + t = rtmp_amf_find_field(ptr, "level", tmpstr, sizeof(tmpstr)); + if (!t && !strcmp(tmpstr, "error")) { + if (!rtmp_amf_find_field(ptr, "description", tmpstr, sizeof(tmpstr))) + av_log(NULL/*s*/, AV_LOG_ERROR, "Server error: %s\n",tmpstr); + return -1; + } } break; }
participants (1)
-
kostya