X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Frtmppkt.c;h=37fbb5fc1699d5743276052b739df277b91e72eb;hb=7207dd8f829baee58b4df6c97c19ffde77039e8d;hp=defe81e05e05d4d5284ce60076885b12a1979d6b;hpb=32a414f316c7f0eea877370e3f9d9f25afbf5da2;p=ffmpeg diff --git a/libavformat/rtmppkt.c b/libavformat/rtmppkt.c index defe81e05e0..37fbb5fc169 100644 --- a/libavformat/rtmppkt.c +++ b/libavformat/rtmppkt.c @@ -102,13 +102,11 @@ int ff_amf_read_number(GetByteContext *bc, double *val) return 0; } -int ff_amf_read_string(GetByteContext *bc, uint8_t *str, - int strsize, int *length) +int ff_amf_get_string(GetByteContext *bc, uint8_t *str, + int strsize, int *length) { int stringlen = 0; int readsize; - if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_STRING) - return AVERROR_INVALIDDATA; stringlen = bytestream2_get_be16(bc); if (stringlen + 1 > strsize) return AVERROR(EINVAL); @@ -122,6 +120,14 @@ int ff_amf_read_string(GetByteContext *bc, uint8_t *str, return 0; } +int ff_amf_read_string(GetByteContext *bc, uint8_t *str, + int strsize, int *length) +{ + if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_STRING) + return AVERROR_INVALIDDATA; + return ff_amf_get_string(bc, str, strsize, length); +} + int ff_amf_read_null(GetByteContext *bc) { if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NULL) @@ -129,28 +135,52 @@ int ff_amf_read_null(GetByteContext *bc) return 0; } +int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt, + int channel) +{ + int nb_alloc; + RTMPPacket *ptr; + if (channel < *nb_prev_pkt) + return 0; + + nb_alloc = channel + 16; + // This can't use the av_reallocp family of functions, since we + // would need to free each element in the array before the array + // itself is freed. + ptr = av_realloc_array(*prev_pkt, nb_alloc, sizeof(**prev_pkt)); + if (!ptr) + return AVERROR(ENOMEM); + memset(ptr + *nb_prev_pkt, 0, (nb_alloc - *nb_prev_pkt) * sizeof(*ptr)); + *prev_pkt = ptr; + *nb_prev_pkt = nb_alloc; + return 0; +} + int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, - int chunk_size, RTMPPacket *prev_pkt) + int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt) { uint8_t hdr; if (ffurl_read(h, &hdr, 1) != 1) return AVERROR(EIO); - return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt, hdr); + return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt, + nb_prev_pkt, hdr); } static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, - int chunk_size, RTMPPacket *prev_pkt, - uint8_t hdr) + int chunk_size, RTMPPacket **prev_pkt_ptr, + int *nb_prev_pkt, uint8_t hdr) { uint8_t buf[16]; int channel_id, timestamp, size; + uint32_t ts_field; // non-extended timestamp or delta field uint32_t extra = 0; enum RTMPPacketType type; int written = 0; int ret, toread; + RTMPPacket *prev_pkt; written++; channel_id = hdr & 0x3F; @@ -162,18 +192,22 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, written += channel_id + 1; channel_id = AV_RL16(buf) + 64; } + if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt, + channel_id)) < 0) + return ret; + prev_pkt = *prev_pkt_ptr; size = prev_pkt[channel_id].size; type = prev_pkt[channel_id].type; extra = prev_pkt[channel_id].extra; - hdr >>= 6; + hdr >>= 6; // header size indicator if (hdr == RTMP_PS_ONEBYTE) { - timestamp = prev_pkt[channel_id].ts_delta; + ts_field = prev_pkt[channel_id].ts_field; } else { if (ffurl_read_complete(h, buf, 3) != 3) return AVERROR(EIO); written += 3; - timestamp = AV_RB24(buf); + ts_field = AV_RB24(buf); if (hdr != RTMP_PS_FOURBYTES) { if (ffurl_read_complete(h, buf, 3) != 3) return AVERROR(EIO); @@ -190,11 +224,13 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, extra = AV_RL32(buf); } } - if (timestamp == 0xFFFFFF) { - if (ffurl_read_complete(h, buf, 4) != 4) - return AVERROR(EIO); - timestamp = AV_RB32(buf); - } + } + if (ts_field == 0xFFFFFF) { + if (ffurl_read_complete(h, buf, 4) != 4) + return AVERROR(EIO); + timestamp = AV_RB32(buf); + } else { + timestamp = ts_field; } if (hdr != RTMP_PS_TWELVEBYTES) timestamp += prev_pkt[channel_id].timestamp; @@ -205,8 +241,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, return ret; p->read = written; p->offset = 0; - prev_pkt[channel_id].ts_delta = timestamp - - prev_pkt[channel_id].timestamp; + prev_pkt[channel_id].ts_field = ts_field; prev_pkt[channel_id].timestamp = timestamp; } else { // previous packet in this channel hasn't completed reading @@ -215,7 +250,7 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, p->size = prev->size; p->channel_id = prev->channel_id; p->type = prev->type; - p->ts_delta = prev->ts_delta; + p->ts_field = prev->ts_field; p->extra = prev->extra; p->offset = prev->offset; p->read = prev->read + written; @@ -252,10 +287,12 @@ static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, } int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, - RTMPPacket *prev_pkt, uint8_t hdr) + RTMPPacket **prev_pkt, int *nb_prev_pkt, + uint8_t hdr) { while (1) { - int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt, hdr); + int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt, + nb_prev_pkt, hdr); if (ret > 0 || ret != AVERROR(EAGAIN)) return ret; @@ -265,23 +302,43 @@ int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, } int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, - int chunk_size, RTMPPacket *prev_pkt) + int chunk_size, RTMPPacket **prev_pkt_ptr, + int *nb_prev_pkt) { uint8_t pkt_hdr[16], *p = pkt_hdr; int mode = RTMP_PS_TWELVEBYTES; int off = 0; int written = 0; int ret; + RTMPPacket *prev_pkt; + int use_delta; // flag if using timestamp delta, not RTMP_PS_TWELVEBYTES + uint32_t timestamp; // full 32-bit timestamp or delta value - pkt->ts_delta = pkt->timestamp - prev_pkt[pkt->channel_id].timestamp; + if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt, + pkt->channel_id)) < 0) + return ret; + prev_pkt = *prev_pkt_ptr; //if channel_id = 0, this is first presentation of prev_pkt, send full hdr. - if (prev_pkt[pkt->channel_id].channel_id && - pkt->extra == prev_pkt[pkt->channel_id].extra) { + use_delta = prev_pkt[pkt->channel_id].channel_id && + pkt->extra == prev_pkt[pkt->channel_id].extra && + pkt->timestamp >= prev_pkt[pkt->channel_id].timestamp; + + timestamp = pkt->timestamp; + if (use_delta) { + timestamp -= prev_pkt[pkt->channel_id].timestamp; + } + if (timestamp >= 0xFFFFFF) { + pkt->ts_field = 0xFFFFFF; + } else { + pkt->ts_field = timestamp; + } + + if (use_delta) { if (pkt->type == prev_pkt[pkt->channel_id].type && pkt->size == prev_pkt[pkt->channel_id].size) { mode = RTMP_PS_FOURBYTES; - if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta) + if (pkt->ts_field == prev_pkt[pkt->channel_id].ts_field) mode = RTMP_PS_ONEBYTE; } else { mode = RTMP_PS_EIGHTBYTES; @@ -298,29 +355,22 @@ int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, bytestream_put_le16(&p, pkt->channel_id - 64); } if (mode != RTMP_PS_ONEBYTE) { - uint32_t timestamp = pkt->timestamp; - if (mode != RTMP_PS_TWELVEBYTES) - timestamp = pkt->ts_delta; - bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp); + bytestream_put_be24(&p, pkt->ts_field); if (mode != RTMP_PS_FOURBYTES) { bytestream_put_be24(&p, pkt->size); bytestream_put_byte(&p, pkt->type); if (mode == RTMP_PS_TWELVEBYTES) bytestream_put_le32(&p, pkt->extra); } - if (timestamp >= 0xFFFFFF) - bytestream_put_be32(&p, timestamp); } + if (pkt->ts_field == 0xFFFFFF) + bytestream_put_be32(&p, timestamp); // save history prev_pkt[pkt->channel_id].channel_id = pkt->channel_id; prev_pkt[pkt->channel_id].type = pkt->type; prev_pkt[pkt->channel_id].size = pkt->size; prev_pkt[pkt->channel_id].timestamp = pkt->timestamp; - if (mode != RTMP_PS_TWELVEBYTES) { - prev_pkt[pkt->channel_id].ts_delta = pkt->ts_delta; - } else { - prev_pkt[pkt->channel_id].ts_delta = pkt->timestamp; - } + prev_pkt[pkt->channel_id].ts_field = pkt->ts_field; prev_pkt[pkt->channel_id].extra = pkt->extra; if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0) @@ -354,7 +404,7 @@ int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, pkt->type = type; pkt->timestamp = timestamp; pkt->extra = 0; - pkt->ts_delta = 0; + pkt->ts_field = 0; return 0; }