1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * RTMP input format
3cabdff1aSopenharmony_ci * Copyright (c) 2009 Konstantin Shishkov
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci#include "libavcodec/bytestream.h"
23cabdff1aSopenharmony_ci#include "libavutil/avstring.h"
24cabdff1aSopenharmony_ci#include "libavutil/intfloat.h"
25cabdff1aSopenharmony_ci#include "avformat.h"
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "rtmppkt.h"
28cabdff1aSopenharmony_ci#include "flv.h"
29cabdff1aSopenharmony_ci#include "url.h"
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_civoid ff_amf_write_bool(uint8_t **dst, int val)
32cabdff1aSopenharmony_ci{
33cabdff1aSopenharmony_ci    bytestream_put_byte(dst, AMF_DATA_TYPE_BOOL);
34cabdff1aSopenharmony_ci    bytestream_put_byte(dst, val);
35cabdff1aSopenharmony_ci}
36cabdff1aSopenharmony_ci
37cabdff1aSopenharmony_civoid ff_amf_write_number(uint8_t **dst, double val)
38cabdff1aSopenharmony_ci{
39cabdff1aSopenharmony_ci    bytestream_put_byte(dst, AMF_DATA_TYPE_NUMBER);
40cabdff1aSopenharmony_ci    bytestream_put_be64(dst, av_double2int(val));
41cabdff1aSopenharmony_ci}
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_civoid ff_amf_write_string(uint8_t **dst, const char *str)
44cabdff1aSopenharmony_ci{
45cabdff1aSopenharmony_ci    bytestream_put_byte(dst, AMF_DATA_TYPE_STRING);
46cabdff1aSopenharmony_ci    bytestream_put_be16(dst, strlen(str));
47cabdff1aSopenharmony_ci    bytestream_put_buffer(dst, str, strlen(str));
48cabdff1aSopenharmony_ci}
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_civoid ff_amf_write_string2(uint8_t **dst, const char *str1, const char *str2)
51cabdff1aSopenharmony_ci{
52cabdff1aSopenharmony_ci    int len1 = 0, len2 = 0;
53cabdff1aSopenharmony_ci    if (str1)
54cabdff1aSopenharmony_ci        len1 = strlen(str1);
55cabdff1aSopenharmony_ci    if (str2)
56cabdff1aSopenharmony_ci        len2 = strlen(str2);
57cabdff1aSopenharmony_ci    bytestream_put_byte(dst, AMF_DATA_TYPE_STRING);
58cabdff1aSopenharmony_ci    bytestream_put_be16(dst, len1 + len2);
59cabdff1aSopenharmony_ci    bytestream_put_buffer(dst, str1, len1);
60cabdff1aSopenharmony_ci    bytestream_put_buffer(dst, str2, len2);
61cabdff1aSopenharmony_ci}
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_civoid ff_amf_write_null(uint8_t **dst)
64cabdff1aSopenharmony_ci{
65cabdff1aSopenharmony_ci    bytestream_put_byte(dst, AMF_DATA_TYPE_NULL);
66cabdff1aSopenharmony_ci}
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_civoid ff_amf_write_object_start(uint8_t **dst)
69cabdff1aSopenharmony_ci{
70cabdff1aSopenharmony_ci    bytestream_put_byte(dst, AMF_DATA_TYPE_OBJECT);
71cabdff1aSopenharmony_ci}
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_civoid ff_amf_write_field_name(uint8_t **dst, const char *str)
74cabdff1aSopenharmony_ci{
75cabdff1aSopenharmony_ci    bytestream_put_be16(dst, strlen(str));
76cabdff1aSopenharmony_ci    bytestream_put_buffer(dst, str, strlen(str));
77cabdff1aSopenharmony_ci}
78cabdff1aSopenharmony_ci
79cabdff1aSopenharmony_civoid ff_amf_write_object_end(uint8_t **dst)
80cabdff1aSopenharmony_ci{
81cabdff1aSopenharmony_ci    /* first two bytes are field name length = 0,
82cabdff1aSopenharmony_ci     * AMF object should end with it and end marker
83cabdff1aSopenharmony_ci     */
84cabdff1aSopenharmony_ci    bytestream_put_be24(dst, AMF_DATA_TYPE_OBJECT_END);
85cabdff1aSopenharmony_ci}
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ciint ff_amf_read_number(GetByteContext *bc, double *val)
88cabdff1aSopenharmony_ci{
89cabdff1aSopenharmony_ci    uint64_t read;
90cabdff1aSopenharmony_ci    if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NUMBER)
91cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
92cabdff1aSopenharmony_ci    read = bytestream2_get_be64(bc);
93cabdff1aSopenharmony_ci    *val = av_int2double(read);
94cabdff1aSopenharmony_ci    return 0;
95cabdff1aSopenharmony_ci}
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ciint ff_amf_get_string(GetByteContext *bc, uint8_t *str,
98cabdff1aSopenharmony_ci                      int strsize, int *length)
99cabdff1aSopenharmony_ci{
100cabdff1aSopenharmony_ci    int stringlen = 0;
101cabdff1aSopenharmony_ci    int readsize;
102cabdff1aSopenharmony_ci    stringlen = bytestream2_get_be16(bc);
103cabdff1aSopenharmony_ci    if (stringlen + 1 > strsize)
104cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
105cabdff1aSopenharmony_ci    readsize = bytestream2_get_buffer(bc, str, stringlen);
106cabdff1aSopenharmony_ci    if (readsize != stringlen) {
107cabdff1aSopenharmony_ci        av_log(NULL, AV_LOG_WARNING,
108cabdff1aSopenharmony_ci               "Unable to read as many bytes as AMF string signaled\n");
109cabdff1aSopenharmony_ci    }
110cabdff1aSopenharmony_ci    str[readsize] = '\0';
111cabdff1aSopenharmony_ci    *length = FFMIN(stringlen, readsize);
112cabdff1aSopenharmony_ci    return 0;
113cabdff1aSopenharmony_ci}
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ciint ff_amf_read_string(GetByteContext *bc, uint8_t *str,
116cabdff1aSopenharmony_ci                       int strsize, int *length)
117cabdff1aSopenharmony_ci{
118cabdff1aSopenharmony_ci    if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_STRING)
119cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
120cabdff1aSopenharmony_ci    return ff_amf_get_string(bc, str, strsize, length);
121cabdff1aSopenharmony_ci}
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ciint ff_amf_read_null(GetByteContext *bc)
124cabdff1aSopenharmony_ci{
125cabdff1aSopenharmony_ci    if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NULL)
126cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
127cabdff1aSopenharmony_ci    return 0;
128cabdff1aSopenharmony_ci}
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ciint ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt,
131cabdff1aSopenharmony_ci                              int channel)
132cabdff1aSopenharmony_ci{
133cabdff1aSopenharmony_ci    int nb_alloc;
134cabdff1aSopenharmony_ci    RTMPPacket *ptr;
135cabdff1aSopenharmony_ci    if (channel < *nb_prev_pkt)
136cabdff1aSopenharmony_ci        return 0;
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci    nb_alloc = channel + 16;
139cabdff1aSopenharmony_ci    // This can't use the av_reallocp family of functions, since we
140cabdff1aSopenharmony_ci    // would need to free each element in the array before the array
141cabdff1aSopenharmony_ci    // itself is freed.
142cabdff1aSopenharmony_ci    ptr = av_realloc_array(*prev_pkt, nb_alloc, sizeof(**prev_pkt));
143cabdff1aSopenharmony_ci    if (!ptr)
144cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
145cabdff1aSopenharmony_ci    memset(ptr + *nb_prev_pkt, 0, (nb_alloc - *nb_prev_pkt) * sizeof(*ptr));
146cabdff1aSopenharmony_ci    *prev_pkt = ptr;
147cabdff1aSopenharmony_ci    *nb_prev_pkt = nb_alloc;
148cabdff1aSopenharmony_ci    return 0;
149cabdff1aSopenharmony_ci}
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ciint ff_rtmp_packet_read(URLContext *h, RTMPPacket *p,
152cabdff1aSopenharmony_ci                        int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    uint8_t hdr;
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_ci    if (ffurl_read(h, &hdr, 1) != 1)
157cabdff1aSopenharmony_ci        return AVERROR(EIO);
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt,
160cabdff1aSopenharmony_ci                                        nb_prev_pkt, hdr);
161cabdff1aSopenharmony_ci}
162cabdff1aSopenharmony_ci
163cabdff1aSopenharmony_cistatic int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p,
164cabdff1aSopenharmony_ci                                      int chunk_size, RTMPPacket **prev_pkt_ptr,
165cabdff1aSopenharmony_ci                                      int *nb_prev_pkt, uint8_t hdr)
166cabdff1aSopenharmony_ci{
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    uint8_t buf[16];
169cabdff1aSopenharmony_ci    int channel_id, timestamp, size;
170cabdff1aSopenharmony_ci    uint32_t ts_field; // non-extended timestamp or delta field
171cabdff1aSopenharmony_ci    uint32_t extra = 0;
172cabdff1aSopenharmony_ci    enum RTMPPacketType type;
173cabdff1aSopenharmony_ci    int written = 0;
174cabdff1aSopenharmony_ci    int ret, toread;
175cabdff1aSopenharmony_ci    RTMPPacket *prev_pkt;
176cabdff1aSopenharmony_ci
177cabdff1aSopenharmony_ci    written++;
178cabdff1aSopenharmony_ci    channel_id = hdr & 0x3F;
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    if (channel_id < 2) { //special case for channel number >= 64
181cabdff1aSopenharmony_ci        buf[1] = 0;
182cabdff1aSopenharmony_ci        if (ffurl_read_complete(h, buf, channel_id + 1) != channel_id + 1)
183cabdff1aSopenharmony_ci            return AVERROR(EIO);
184cabdff1aSopenharmony_ci        written += channel_id + 1;
185cabdff1aSopenharmony_ci        channel_id = AV_RL16(buf) + 64;
186cabdff1aSopenharmony_ci    }
187cabdff1aSopenharmony_ci    if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
188cabdff1aSopenharmony_ci                                         channel_id)) < 0)
189cabdff1aSopenharmony_ci        return ret;
190cabdff1aSopenharmony_ci    prev_pkt = *prev_pkt_ptr;
191cabdff1aSopenharmony_ci    size  = prev_pkt[channel_id].size;
192cabdff1aSopenharmony_ci    type  = prev_pkt[channel_id].type;
193cabdff1aSopenharmony_ci    extra = prev_pkt[channel_id].extra;
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    hdr >>= 6; // header size indicator
196cabdff1aSopenharmony_ci    if (hdr == RTMP_PS_ONEBYTE) {
197cabdff1aSopenharmony_ci        ts_field = prev_pkt[channel_id].ts_field;
198cabdff1aSopenharmony_ci    } else {
199cabdff1aSopenharmony_ci        if (ffurl_read_complete(h, buf, 3) != 3)
200cabdff1aSopenharmony_ci            return AVERROR(EIO);
201cabdff1aSopenharmony_ci        written += 3;
202cabdff1aSopenharmony_ci        ts_field = AV_RB24(buf);
203cabdff1aSopenharmony_ci        if (hdr != RTMP_PS_FOURBYTES) {
204cabdff1aSopenharmony_ci            if (ffurl_read_complete(h, buf, 3) != 3)
205cabdff1aSopenharmony_ci                return AVERROR(EIO);
206cabdff1aSopenharmony_ci            written += 3;
207cabdff1aSopenharmony_ci            size = AV_RB24(buf);
208cabdff1aSopenharmony_ci            if (ffurl_read_complete(h, buf, 1) != 1)
209cabdff1aSopenharmony_ci                return AVERROR(EIO);
210cabdff1aSopenharmony_ci            written++;
211cabdff1aSopenharmony_ci            type = buf[0];
212cabdff1aSopenharmony_ci            if (hdr == RTMP_PS_TWELVEBYTES) {
213cabdff1aSopenharmony_ci                if (ffurl_read_complete(h, buf, 4) != 4)
214cabdff1aSopenharmony_ci                    return AVERROR(EIO);
215cabdff1aSopenharmony_ci                written += 4;
216cabdff1aSopenharmony_ci                extra = AV_RL32(buf);
217cabdff1aSopenharmony_ci            }
218cabdff1aSopenharmony_ci        }
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci    if (ts_field == 0xFFFFFF) {
221cabdff1aSopenharmony_ci        if (ffurl_read_complete(h, buf, 4) != 4)
222cabdff1aSopenharmony_ci            return AVERROR(EIO);
223cabdff1aSopenharmony_ci        timestamp = AV_RB32(buf);
224cabdff1aSopenharmony_ci    } else {
225cabdff1aSopenharmony_ci        timestamp = ts_field;
226cabdff1aSopenharmony_ci    }
227cabdff1aSopenharmony_ci    if (hdr != RTMP_PS_TWELVEBYTES)
228cabdff1aSopenharmony_ci        timestamp += prev_pkt[channel_id].timestamp;
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    if (prev_pkt[channel_id].read && size != prev_pkt[channel_id].size) {
231cabdff1aSopenharmony_ci        av_log(h, AV_LOG_ERROR, "RTMP packet size mismatch %d != %d\n",
232cabdff1aSopenharmony_ci                                size, prev_pkt[channel_id].size);
233cabdff1aSopenharmony_ci        ff_rtmp_packet_destroy(&prev_pkt[channel_id]);
234cabdff1aSopenharmony_ci        prev_pkt[channel_id].read = 0;
235cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
236cabdff1aSopenharmony_ci    }
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    if (!prev_pkt[channel_id].read) {
239cabdff1aSopenharmony_ci        if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp,
240cabdff1aSopenharmony_ci                                         size)) < 0)
241cabdff1aSopenharmony_ci            return ret;
242cabdff1aSopenharmony_ci        p->read = written;
243cabdff1aSopenharmony_ci        p->offset = 0;
244cabdff1aSopenharmony_ci        prev_pkt[channel_id].ts_field   = ts_field;
245cabdff1aSopenharmony_ci        prev_pkt[channel_id].timestamp  = timestamp;
246cabdff1aSopenharmony_ci    } else {
247cabdff1aSopenharmony_ci        // previous packet in this channel hasn't completed reading
248cabdff1aSopenharmony_ci        RTMPPacket *prev = &prev_pkt[channel_id];
249cabdff1aSopenharmony_ci        p->data          = prev->data;
250cabdff1aSopenharmony_ci        p->size          = prev->size;
251cabdff1aSopenharmony_ci        p->channel_id    = prev->channel_id;
252cabdff1aSopenharmony_ci        p->type          = prev->type;
253cabdff1aSopenharmony_ci        p->ts_field      = prev->ts_field;
254cabdff1aSopenharmony_ci        p->extra         = prev->extra;
255cabdff1aSopenharmony_ci        p->offset        = prev->offset;
256cabdff1aSopenharmony_ci        p->read          = prev->read + written;
257cabdff1aSopenharmony_ci        p->timestamp     = prev->timestamp;
258cabdff1aSopenharmony_ci        prev->data       = NULL;
259cabdff1aSopenharmony_ci    }
260cabdff1aSopenharmony_ci    p->extra = extra;
261cabdff1aSopenharmony_ci    // save history
262cabdff1aSopenharmony_ci    prev_pkt[channel_id].channel_id = channel_id;
263cabdff1aSopenharmony_ci    prev_pkt[channel_id].type       = type;
264cabdff1aSopenharmony_ci    prev_pkt[channel_id].size       = size;
265cabdff1aSopenharmony_ci    prev_pkt[channel_id].extra      = extra;
266cabdff1aSopenharmony_ci    size = size - p->offset;
267cabdff1aSopenharmony_ci
268cabdff1aSopenharmony_ci    toread = FFMIN(size, chunk_size);
269cabdff1aSopenharmony_ci    if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) {
270cabdff1aSopenharmony_ci        ff_rtmp_packet_destroy(p);
271cabdff1aSopenharmony_ci        return AVERROR(EIO);
272cabdff1aSopenharmony_ci    }
273cabdff1aSopenharmony_ci    size      -= toread;
274cabdff1aSopenharmony_ci    p->read   += toread;
275cabdff1aSopenharmony_ci    p->offset += toread;
276cabdff1aSopenharmony_ci
277cabdff1aSopenharmony_ci    if (size > 0) {
278cabdff1aSopenharmony_ci       RTMPPacket *prev = &prev_pkt[channel_id];
279cabdff1aSopenharmony_ci       prev->data = p->data;
280cabdff1aSopenharmony_ci       prev->read = p->read;
281cabdff1aSopenharmony_ci       prev->offset = p->offset;
282cabdff1aSopenharmony_ci       p->data      = NULL;
283cabdff1aSopenharmony_ci       return AVERROR(EAGAIN);
284cabdff1aSopenharmony_ci    }
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ci    prev_pkt[channel_id].read = 0; // read complete; reset if needed
287cabdff1aSopenharmony_ci    return p->read;
288cabdff1aSopenharmony_ci}
289cabdff1aSopenharmony_ci
290cabdff1aSopenharmony_ciint ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size,
291cabdff1aSopenharmony_ci                                 RTMPPacket **prev_pkt, int *nb_prev_pkt,
292cabdff1aSopenharmony_ci                                 uint8_t hdr)
293cabdff1aSopenharmony_ci{
294cabdff1aSopenharmony_ci    while (1) {
295cabdff1aSopenharmony_ci        int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt,
296cabdff1aSopenharmony_ci                                             nb_prev_pkt, hdr);
297cabdff1aSopenharmony_ci        if (ret > 0 || ret != AVERROR(EAGAIN))
298cabdff1aSopenharmony_ci            return ret;
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci        if (ffurl_read(h, &hdr, 1) != 1)
301cabdff1aSopenharmony_ci            return AVERROR(EIO);
302cabdff1aSopenharmony_ci    }
303cabdff1aSopenharmony_ci}
304cabdff1aSopenharmony_ci
305cabdff1aSopenharmony_ciint ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt,
306cabdff1aSopenharmony_ci                         int chunk_size, RTMPPacket **prev_pkt_ptr,
307cabdff1aSopenharmony_ci                         int *nb_prev_pkt)
308cabdff1aSopenharmony_ci{
309cabdff1aSopenharmony_ci    uint8_t pkt_hdr[16], *p = pkt_hdr;
310cabdff1aSopenharmony_ci    int mode = RTMP_PS_TWELVEBYTES;
311cabdff1aSopenharmony_ci    int off = 0;
312cabdff1aSopenharmony_ci    int written = 0;
313cabdff1aSopenharmony_ci    int ret;
314cabdff1aSopenharmony_ci    RTMPPacket *prev_pkt;
315cabdff1aSopenharmony_ci    int use_delta; // flag if using timestamp delta, not RTMP_PS_TWELVEBYTES
316cabdff1aSopenharmony_ci    uint32_t timestamp; // full 32-bit timestamp or delta value
317cabdff1aSopenharmony_ci
318cabdff1aSopenharmony_ci    if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
319cabdff1aSopenharmony_ci                                         pkt->channel_id)) < 0)
320cabdff1aSopenharmony_ci        return ret;
321cabdff1aSopenharmony_ci    prev_pkt = *prev_pkt_ptr;
322cabdff1aSopenharmony_ci
323cabdff1aSopenharmony_ci    //if channel_id = 0, this is first presentation of prev_pkt, send full hdr.
324cabdff1aSopenharmony_ci    use_delta = prev_pkt[pkt->channel_id].channel_id &&
325cabdff1aSopenharmony_ci        pkt->extra == prev_pkt[pkt->channel_id].extra &&
326cabdff1aSopenharmony_ci        pkt->timestamp >= prev_pkt[pkt->channel_id].timestamp;
327cabdff1aSopenharmony_ci
328cabdff1aSopenharmony_ci    timestamp = pkt->timestamp;
329cabdff1aSopenharmony_ci    if (use_delta) {
330cabdff1aSopenharmony_ci        timestamp -= prev_pkt[pkt->channel_id].timestamp;
331cabdff1aSopenharmony_ci    }
332cabdff1aSopenharmony_ci    if (timestamp >= 0xFFFFFF) {
333cabdff1aSopenharmony_ci        pkt->ts_field = 0xFFFFFF;
334cabdff1aSopenharmony_ci    } else {
335cabdff1aSopenharmony_ci        pkt->ts_field = timestamp;
336cabdff1aSopenharmony_ci    }
337cabdff1aSopenharmony_ci
338cabdff1aSopenharmony_ci    if (use_delta) {
339cabdff1aSopenharmony_ci        if (pkt->type == prev_pkt[pkt->channel_id].type &&
340cabdff1aSopenharmony_ci            pkt->size == prev_pkt[pkt->channel_id].size) {
341cabdff1aSopenharmony_ci            mode = RTMP_PS_FOURBYTES;
342cabdff1aSopenharmony_ci            if (pkt->ts_field == prev_pkt[pkt->channel_id].ts_field)
343cabdff1aSopenharmony_ci                mode = RTMP_PS_ONEBYTE;
344cabdff1aSopenharmony_ci        } else {
345cabdff1aSopenharmony_ci            mode = RTMP_PS_EIGHTBYTES;
346cabdff1aSopenharmony_ci        }
347cabdff1aSopenharmony_ci    }
348cabdff1aSopenharmony_ci
349cabdff1aSopenharmony_ci    if (pkt->channel_id < 64) {
350cabdff1aSopenharmony_ci        bytestream_put_byte(&p, pkt->channel_id | (mode << 6));
351cabdff1aSopenharmony_ci    } else if (pkt->channel_id < 64 + 256) {
352cabdff1aSopenharmony_ci        bytestream_put_byte(&p, 0               | (mode << 6));
353cabdff1aSopenharmony_ci        bytestream_put_byte(&p, pkt->channel_id - 64);
354cabdff1aSopenharmony_ci    } else {
355cabdff1aSopenharmony_ci        bytestream_put_byte(&p, 1               | (mode << 6));
356cabdff1aSopenharmony_ci        bytestream_put_le16(&p, pkt->channel_id - 64);
357cabdff1aSopenharmony_ci    }
358cabdff1aSopenharmony_ci    if (mode != RTMP_PS_ONEBYTE) {
359cabdff1aSopenharmony_ci        bytestream_put_be24(&p, pkt->ts_field);
360cabdff1aSopenharmony_ci        if (mode != RTMP_PS_FOURBYTES) {
361cabdff1aSopenharmony_ci            bytestream_put_be24(&p, pkt->size);
362cabdff1aSopenharmony_ci            bytestream_put_byte(&p, pkt->type);
363cabdff1aSopenharmony_ci            if (mode == RTMP_PS_TWELVEBYTES)
364cabdff1aSopenharmony_ci                bytestream_put_le32(&p, pkt->extra);
365cabdff1aSopenharmony_ci        }
366cabdff1aSopenharmony_ci    }
367cabdff1aSopenharmony_ci    if (pkt->ts_field == 0xFFFFFF)
368cabdff1aSopenharmony_ci        bytestream_put_be32(&p, timestamp);
369cabdff1aSopenharmony_ci    // save history
370cabdff1aSopenharmony_ci    prev_pkt[pkt->channel_id].channel_id = pkt->channel_id;
371cabdff1aSopenharmony_ci    prev_pkt[pkt->channel_id].type       = pkt->type;
372cabdff1aSopenharmony_ci    prev_pkt[pkt->channel_id].size       = pkt->size;
373cabdff1aSopenharmony_ci    prev_pkt[pkt->channel_id].timestamp  = pkt->timestamp;
374cabdff1aSopenharmony_ci    prev_pkt[pkt->channel_id].ts_field   = pkt->ts_field;
375cabdff1aSopenharmony_ci    prev_pkt[pkt->channel_id].extra      = pkt->extra;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    // FIXME:
378cabdff1aSopenharmony_ci    // Writing packets is currently not optimized to minimize system calls.
379cabdff1aSopenharmony_ci    // Since system calls flush on exit which we cannot change in a system-independant way.
380cabdff1aSopenharmony_ci    // We should fix this behavior and by writing packets in a single or in as few as possible system calls.
381cabdff1aSopenharmony_ci    // Protocols like TCP and RTMP should benefit from this when enabling TCP_NODELAY.
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci    if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0)
384cabdff1aSopenharmony_ci        return ret;
385cabdff1aSopenharmony_ci    written = p - pkt_hdr + pkt->size;
386cabdff1aSopenharmony_ci    while (off < pkt->size) {
387cabdff1aSopenharmony_ci        int towrite = FFMIN(chunk_size, pkt->size - off);
388cabdff1aSopenharmony_ci        if ((ret = ffurl_write(h, pkt->data + off, towrite)) < 0)
389cabdff1aSopenharmony_ci            return ret;
390cabdff1aSopenharmony_ci        off += towrite;
391cabdff1aSopenharmony_ci        if (off < pkt->size) {
392cabdff1aSopenharmony_ci            uint8_t marker = 0xC0 | pkt->channel_id;
393cabdff1aSopenharmony_ci            if ((ret = ffurl_write(h, &marker, 1)) < 0)
394cabdff1aSopenharmony_ci                return ret;
395cabdff1aSopenharmony_ci            written++;
396cabdff1aSopenharmony_ci            if (pkt->ts_field == 0xFFFFFF) {
397cabdff1aSopenharmony_ci                uint8_t ts_header[4];
398cabdff1aSopenharmony_ci                AV_WB32(ts_header, timestamp);
399cabdff1aSopenharmony_ci                if ((ret = ffurl_write(h, ts_header, 4)) < 0)
400cabdff1aSopenharmony_ci                    return ret;
401cabdff1aSopenharmony_ci                written += 4;
402cabdff1aSopenharmony_ci            }
403cabdff1aSopenharmony_ci        }
404cabdff1aSopenharmony_ci    }
405cabdff1aSopenharmony_ci    return written;
406cabdff1aSopenharmony_ci}
407cabdff1aSopenharmony_ci
408cabdff1aSopenharmony_ciint ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type,
409cabdff1aSopenharmony_ci                          int timestamp, int size)
410cabdff1aSopenharmony_ci{
411cabdff1aSopenharmony_ci    if (size) {
412cabdff1aSopenharmony_ci        pkt->data = av_realloc(NULL, size);
413cabdff1aSopenharmony_ci        if (!pkt->data)
414cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
415cabdff1aSopenharmony_ci    }
416cabdff1aSopenharmony_ci    pkt->size       = size;
417cabdff1aSopenharmony_ci    pkt->channel_id = channel_id;
418cabdff1aSopenharmony_ci    pkt->type       = type;
419cabdff1aSopenharmony_ci    pkt->timestamp  = timestamp;
420cabdff1aSopenharmony_ci    pkt->extra      = 0;
421cabdff1aSopenharmony_ci    pkt->ts_field   = 0;
422cabdff1aSopenharmony_ci
423cabdff1aSopenharmony_ci    return 0;
424cabdff1aSopenharmony_ci}
425cabdff1aSopenharmony_ci
426cabdff1aSopenharmony_civoid ff_rtmp_packet_destroy(RTMPPacket *pkt)
427cabdff1aSopenharmony_ci{
428cabdff1aSopenharmony_ci    if (!pkt)
429cabdff1aSopenharmony_ci        return;
430cabdff1aSopenharmony_ci    av_freep(&pkt->data);
431cabdff1aSopenharmony_ci    pkt->size = 0;
432cabdff1aSopenharmony_ci}
433cabdff1aSopenharmony_ci
434cabdff1aSopenharmony_cistatic int amf_tag_skip(GetByteContext *gb)
435cabdff1aSopenharmony_ci{
436cabdff1aSopenharmony_ci    AMFDataType type;
437cabdff1aSopenharmony_ci    unsigned nb   = -1;
438cabdff1aSopenharmony_ci    int parse_key = 1;
439cabdff1aSopenharmony_ci
440cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < 1)
441cabdff1aSopenharmony_ci        return -1;
442cabdff1aSopenharmony_ci
443cabdff1aSopenharmony_ci    type = bytestream2_get_byte(gb);
444cabdff1aSopenharmony_ci    switch (type) {
445cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_NUMBER:
446cabdff1aSopenharmony_ci        bytestream2_get_be64(gb);
447cabdff1aSopenharmony_ci        return 0;
448cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_BOOL:
449cabdff1aSopenharmony_ci        bytestream2_get_byte(gb);
450cabdff1aSopenharmony_ci        return 0;
451cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_STRING:
452cabdff1aSopenharmony_ci        bytestream2_skip(gb, bytestream2_get_be16(gb));
453cabdff1aSopenharmony_ci        return 0;
454cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_LONG_STRING:
455cabdff1aSopenharmony_ci        bytestream2_skip(gb, bytestream2_get_be32(gb));
456cabdff1aSopenharmony_ci        return 0;
457cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_NULL:
458cabdff1aSopenharmony_ci        return 0;
459cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_DATE:
460cabdff1aSopenharmony_ci        bytestream2_skip(gb, 10);
461cabdff1aSopenharmony_ci        return 0;
462cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_ARRAY:
463cabdff1aSopenharmony_ci        parse_key = 0;
464cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_MIXEDARRAY:
465cabdff1aSopenharmony_ci        nb = bytestream2_get_be32(gb);
466cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_OBJECT:
467cabdff1aSopenharmony_ci        while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
468cabdff1aSopenharmony_ci            int t;
469cabdff1aSopenharmony_ci            if (parse_key) {
470cabdff1aSopenharmony_ci                int size = bytestream2_get_be16(gb);
471cabdff1aSopenharmony_ci                if (!size) {
472cabdff1aSopenharmony_ci                    bytestream2_get_byte(gb);
473cabdff1aSopenharmony_ci                    break;
474cabdff1aSopenharmony_ci                }
475cabdff1aSopenharmony_ci                if (size < 0 || size >= bytestream2_get_bytes_left(gb))
476cabdff1aSopenharmony_ci                    return -1;
477cabdff1aSopenharmony_ci                bytestream2_skip(gb, size);
478cabdff1aSopenharmony_ci            }
479cabdff1aSopenharmony_ci            t = amf_tag_skip(gb);
480cabdff1aSopenharmony_ci            if (t < 0 || bytestream2_get_bytes_left(gb) <= 0)
481cabdff1aSopenharmony_ci                return -1;
482cabdff1aSopenharmony_ci        }
483cabdff1aSopenharmony_ci        return 0;
484cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_OBJECT_END:  return 0;
485cabdff1aSopenharmony_ci    default:                        return -1;
486cabdff1aSopenharmony_ci    }
487cabdff1aSopenharmony_ci}
488cabdff1aSopenharmony_ci
489cabdff1aSopenharmony_ciint ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
490cabdff1aSopenharmony_ci{
491cabdff1aSopenharmony_ci    GetByteContext gb;
492cabdff1aSopenharmony_ci    int ret;
493cabdff1aSopenharmony_ci
494cabdff1aSopenharmony_ci    if (data >= data_end)
495cabdff1aSopenharmony_ci        return -1;
496cabdff1aSopenharmony_ci
497cabdff1aSopenharmony_ci    bytestream2_init(&gb, data, data_end - data);
498cabdff1aSopenharmony_ci
499cabdff1aSopenharmony_ci    ret = amf_tag_skip(&gb);
500cabdff1aSopenharmony_ci    if (ret < 0 || bytestream2_get_bytes_left(&gb) <= 0)
501cabdff1aSopenharmony_ci        return -1;
502cabdff1aSopenharmony_ci    av_assert0(bytestream2_tell(&gb) >= 0 && bytestream2_tell(&gb) <= data_end - data);
503cabdff1aSopenharmony_ci    return bytestream2_tell(&gb);
504cabdff1aSopenharmony_ci}
505cabdff1aSopenharmony_ci
506cabdff1aSopenharmony_cistatic int amf_get_field_value2(GetByteContext *gb,
507cabdff1aSopenharmony_ci                           const uint8_t *name, uint8_t *dst, int dst_size)
508cabdff1aSopenharmony_ci{
509cabdff1aSopenharmony_ci    int namelen = strlen(name);
510cabdff1aSopenharmony_ci    int len;
511cabdff1aSopenharmony_ci
512cabdff1aSopenharmony_ci    while (bytestream2_peek_byte(gb) != AMF_DATA_TYPE_OBJECT && bytestream2_get_bytes_left(gb) > 0) {
513cabdff1aSopenharmony_ci        int ret = amf_tag_skip(gb);
514cabdff1aSopenharmony_ci        if (ret < 0)
515cabdff1aSopenharmony_ci            return -1;
516cabdff1aSopenharmony_ci    }
517cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < 3)
518cabdff1aSopenharmony_ci        return -1;
519cabdff1aSopenharmony_ci    bytestream2_get_byte(gb);
520cabdff1aSopenharmony_ci
521cabdff1aSopenharmony_ci    for (;;) {
522cabdff1aSopenharmony_ci        int size = bytestream2_get_be16(gb);
523cabdff1aSopenharmony_ci        if (!size)
524cabdff1aSopenharmony_ci            break;
525cabdff1aSopenharmony_ci        if (size < 0 || size >= bytestream2_get_bytes_left(gb))
526cabdff1aSopenharmony_ci            return -1;
527cabdff1aSopenharmony_ci        bytestream2_skip(gb, size);
528cabdff1aSopenharmony_ci        if (size == namelen && !memcmp(gb->buffer-size, name, namelen)) {
529cabdff1aSopenharmony_ci            switch (bytestream2_get_byte(gb)) {
530cabdff1aSopenharmony_ci            case AMF_DATA_TYPE_NUMBER:
531cabdff1aSopenharmony_ci                snprintf(dst, dst_size, "%g", av_int2double(bytestream2_get_be64(gb)));
532cabdff1aSopenharmony_ci                break;
533cabdff1aSopenharmony_ci            case AMF_DATA_TYPE_BOOL:
534cabdff1aSopenharmony_ci                snprintf(dst, dst_size, "%s", bytestream2_get_byte(gb) ? "true" : "false");
535cabdff1aSopenharmony_ci                break;
536cabdff1aSopenharmony_ci            case AMF_DATA_TYPE_STRING:
537cabdff1aSopenharmony_ci                len = bytestream2_get_be16(gb);
538cabdff1aSopenharmony_ci                if (dst_size < 1)
539cabdff1aSopenharmony_ci                    return -1;
540cabdff1aSopenharmony_ci                if (dst_size < len + 1)
541cabdff1aSopenharmony_ci                    len = dst_size - 1;
542cabdff1aSopenharmony_ci                bytestream2_get_buffer(gb, dst, len);
543cabdff1aSopenharmony_ci                dst[len] = 0;
544cabdff1aSopenharmony_ci                break;
545cabdff1aSopenharmony_ci            default:
546cabdff1aSopenharmony_ci                return -1;
547cabdff1aSopenharmony_ci            }
548cabdff1aSopenharmony_ci            return 0;
549cabdff1aSopenharmony_ci        }
550cabdff1aSopenharmony_ci        len = amf_tag_skip(gb);
551cabdff1aSopenharmony_ci        if (len < 0 || bytestream2_get_bytes_left(gb) <= 0)
552cabdff1aSopenharmony_ci            return -1;
553cabdff1aSopenharmony_ci    }
554cabdff1aSopenharmony_ci    return -1;
555cabdff1aSopenharmony_ci}
556cabdff1aSopenharmony_ci
557cabdff1aSopenharmony_ciint ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end,
558cabdff1aSopenharmony_ci                           const uint8_t *name, uint8_t *dst, int dst_size)
559cabdff1aSopenharmony_ci{
560cabdff1aSopenharmony_ci    GetByteContext gb;
561cabdff1aSopenharmony_ci
562cabdff1aSopenharmony_ci    if (data >= data_end)
563cabdff1aSopenharmony_ci        return -1;
564cabdff1aSopenharmony_ci
565cabdff1aSopenharmony_ci    bytestream2_init(&gb, data, data_end - data);
566cabdff1aSopenharmony_ci
567cabdff1aSopenharmony_ci    return amf_get_field_value2(&gb, name, dst, dst_size);
568cabdff1aSopenharmony_ci}
569cabdff1aSopenharmony_ci
570cabdff1aSopenharmony_ci#ifdef DEBUG
571cabdff1aSopenharmony_cistatic const char* rtmp_packet_type(int type)
572cabdff1aSopenharmony_ci{
573cabdff1aSopenharmony_ci    switch (type) {
574cabdff1aSopenharmony_ci    case RTMP_PT_CHUNK_SIZE:     return "chunk size";
575cabdff1aSopenharmony_ci    case RTMP_PT_BYTES_READ:     return "bytes read";
576cabdff1aSopenharmony_ci    case RTMP_PT_USER_CONTROL:   return "user control";
577cabdff1aSopenharmony_ci    case RTMP_PT_WINDOW_ACK_SIZE: return "window acknowledgement size";
578cabdff1aSopenharmony_ci    case RTMP_PT_SET_PEER_BW:    return "set peer bandwidth";
579cabdff1aSopenharmony_ci    case RTMP_PT_AUDIO:          return "audio packet";
580cabdff1aSopenharmony_ci    case RTMP_PT_VIDEO:          return "video packet";
581cabdff1aSopenharmony_ci    case RTMP_PT_FLEX_STREAM:    return "Flex shared stream";
582cabdff1aSopenharmony_ci    case RTMP_PT_FLEX_OBJECT:    return "Flex shared object";
583cabdff1aSopenharmony_ci    case RTMP_PT_FLEX_MESSAGE:   return "Flex shared message";
584cabdff1aSopenharmony_ci    case RTMP_PT_NOTIFY:         return "notification";
585cabdff1aSopenharmony_ci    case RTMP_PT_SHARED_OBJ:     return "shared object";
586cabdff1aSopenharmony_ci    case RTMP_PT_INVOKE:         return "invoke";
587cabdff1aSopenharmony_ci    case RTMP_PT_METADATA:       return "metadata";
588cabdff1aSopenharmony_ci    default:                     return "unknown";
589cabdff1aSopenharmony_ci    }
590cabdff1aSopenharmony_ci}
591cabdff1aSopenharmony_ci
592cabdff1aSopenharmony_cistatic void amf_tag_contents(void *ctx, const uint8_t *data,
593cabdff1aSopenharmony_ci                             const uint8_t *data_end)
594cabdff1aSopenharmony_ci{
595cabdff1aSopenharmony_ci    unsigned int size, nb = -1;
596cabdff1aSopenharmony_ci    char buf[1024];
597cabdff1aSopenharmony_ci    AMFDataType type;
598cabdff1aSopenharmony_ci    int parse_key = 1;
599cabdff1aSopenharmony_ci
600cabdff1aSopenharmony_ci    if (data >= data_end)
601cabdff1aSopenharmony_ci        return;
602cabdff1aSopenharmony_ci    switch ((type = *data++)) {
603cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_NUMBER:
604cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2double(AV_RB64(data)));
605cabdff1aSopenharmony_ci        return;
606cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_BOOL:
607cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, " bool %d\n", *data);
608cabdff1aSopenharmony_ci        return;
609cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_STRING:
610cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_LONG_STRING:
611cabdff1aSopenharmony_ci        if (type == AMF_DATA_TYPE_STRING) {
612cabdff1aSopenharmony_ci            size = bytestream_get_be16(&data);
613cabdff1aSopenharmony_ci        } else {
614cabdff1aSopenharmony_ci            size = bytestream_get_be32(&data);
615cabdff1aSopenharmony_ci        }
616cabdff1aSopenharmony_ci        size = FFMIN(size, sizeof(buf) - 1);
617cabdff1aSopenharmony_ci        memcpy(buf, data, size);
618cabdff1aSopenharmony_ci        buf[size] = 0;
619cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, " string '%s'\n", buf);
620cabdff1aSopenharmony_ci        return;
621cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_NULL:
622cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, " NULL\n");
623cabdff1aSopenharmony_ci        return;
624cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_ARRAY:
625cabdff1aSopenharmony_ci        parse_key = 0;
626cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_MIXEDARRAY:
627cabdff1aSopenharmony_ci        nb = bytestream_get_be32(&data);
628cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_OBJECT:
629cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, " {\n");
630cabdff1aSopenharmony_ci        while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
631cabdff1aSopenharmony_ci            int t;
632cabdff1aSopenharmony_ci            if (parse_key) {
633cabdff1aSopenharmony_ci                size = bytestream_get_be16(&data);
634cabdff1aSopenharmony_ci                size = FFMIN(size, sizeof(buf) - 1);
635cabdff1aSopenharmony_ci                if (!size) {
636cabdff1aSopenharmony_ci                    av_log(ctx, AV_LOG_DEBUG, " }\n");
637cabdff1aSopenharmony_ci                    data++;
638cabdff1aSopenharmony_ci                    break;
639cabdff1aSopenharmony_ci                }
640cabdff1aSopenharmony_ci                memcpy(buf, data, size);
641cabdff1aSopenharmony_ci                buf[size] = 0;
642cabdff1aSopenharmony_ci                if (size >= data_end - data)
643cabdff1aSopenharmony_ci                    return;
644cabdff1aSopenharmony_ci                data += size;
645cabdff1aSopenharmony_ci                av_log(ctx, AV_LOG_DEBUG, "  %s: ", buf);
646cabdff1aSopenharmony_ci            }
647cabdff1aSopenharmony_ci            amf_tag_contents(ctx, data, data_end);
648cabdff1aSopenharmony_ci            t = ff_amf_tag_size(data, data_end);
649cabdff1aSopenharmony_ci            if (t < 0 || t >= data_end - data)
650cabdff1aSopenharmony_ci                return;
651cabdff1aSopenharmony_ci            data += t;
652cabdff1aSopenharmony_ci        }
653cabdff1aSopenharmony_ci        return;
654cabdff1aSopenharmony_ci    case AMF_DATA_TYPE_OBJECT_END:
655cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, " }\n");
656cabdff1aSopenharmony_ci        return;
657cabdff1aSopenharmony_ci    default:
658cabdff1aSopenharmony_ci        return;
659cabdff1aSopenharmony_ci    }
660cabdff1aSopenharmony_ci}
661cabdff1aSopenharmony_ci
662cabdff1aSopenharmony_civoid ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
663cabdff1aSopenharmony_ci{
664cabdff1aSopenharmony_ci    av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n",
665cabdff1aSopenharmony_ci           rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->size);
666cabdff1aSopenharmony_ci    if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) {
667cabdff1aSopenharmony_ci        uint8_t *src = p->data, *src_end = p->data + p->size;
668cabdff1aSopenharmony_ci        while (src < src_end) {
669cabdff1aSopenharmony_ci            int sz;
670cabdff1aSopenharmony_ci            amf_tag_contents(ctx, src, src_end);
671cabdff1aSopenharmony_ci            sz = ff_amf_tag_size(src, src_end);
672cabdff1aSopenharmony_ci            if (sz < 0)
673cabdff1aSopenharmony_ci                break;
674cabdff1aSopenharmony_ci            src += sz;
675cabdff1aSopenharmony_ci        }
676cabdff1aSopenharmony_ci    } else if (p->type == RTMP_PT_WINDOW_ACK_SIZE) {
677cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", AV_RB32(p->data));
678cabdff1aSopenharmony_ci    } else if (p->type == RTMP_PT_SET_PEER_BW) {
679cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, "Set Peer BW = %d\n", AV_RB32(p->data));
680cabdff1aSopenharmony_ci    } else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) {
681cabdff1aSopenharmony_ci        int i;
682cabdff1aSopenharmony_ci        for (i = 0; i < p->size; i++)
683cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]);
684cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_DEBUG, "\n");
685cabdff1aSopenharmony_ci    }
686cabdff1aSopenharmony_ci}
687cabdff1aSopenharmony_ci#endif
688cabdff1aSopenharmony_ci
689cabdff1aSopenharmony_ciint ff_amf_match_string(const uint8_t *data, int size, const char *str)
690cabdff1aSopenharmony_ci{
691cabdff1aSopenharmony_ci    int len = strlen(str);
692cabdff1aSopenharmony_ci    int amf_len, type;
693cabdff1aSopenharmony_ci
694cabdff1aSopenharmony_ci    if (size < 1)
695cabdff1aSopenharmony_ci        return 0;
696cabdff1aSopenharmony_ci
697cabdff1aSopenharmony_ci    type = *data++;
698cabdff1aSopenharmony_ci
699cabdff1aSopenharmony_ci    if (type != AMF_DATA_TYPE_LONG_STRING &&
700cabdff1aSopenharmony_ci        type != AMF_DATA_TYPE_STRING)
701cabdff1aSopenharmony_ci        return 0;
702cabdff1aSopenharmony_ci
703cabdff1aSopenharmony_ci    if (type == AMF_DATA_TYPE_LONG_STRING) {
704cabdff1aSopenharmony_ci        if ((size -= 4 + 1) < 0)
705cabdff1aSopenharmony_ci            return 0;
706cabdff1aSopenharmony_ci        amf_len = bytestream_get_be32(&data);
707cabdff1aSopenharmony_ci    } else {
708cabdff1aSopenharmony_ci        if ((size -= 2 + 1) < 0)
709cabdff1aSopenharmony_ci            return 0;
710cabdff1aSopenharmony_ci        amf_len = bytestream_get_be16(&data);
711cabdff1aSopenharmony_ci    }
712cabdff1aSopenharmony_ci
713cabdff1aSopenharmony_ci    if (amf_len > size)
714cabdff1aSopenharmony_ci        return 0;
715cabdff1aSopenharmony_ci
716cabdff1aSopenharmony_ci    if (amf_len != len)
717cabdff1aSopenharmony_ci        return 0;
718cabdff1aSopenharmony_ci
719cabdff1aSopenharmony_ci    return !memcmp(data, str, len);
720cabdff1aSopenharmony_ci}
721