FFmpeg
rtmppkt.c
Go to the documentation of this file.
1 /*
2  * RTMP input format
3  * Copyright (c) 2009 Konstantin 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/intfloat.h"
24 #include "libavutil/mem.h"
25 
26 #include "rtmppkt.h"
27 #include "flv.h"
28 #include "url.h"
29 
30 #define MAX_DEPTH 16 ///< arbitrary limit to prevent unbounded recursion
31 
32 void ff_amf_write_bool(uint8_t **dst, int val)
33 {
34  bytestream_put_byte(dst, AMF_DATA_TYPE_BOOL);
35  bytestream_put_byte(dst, val);
36 }
37 
38 void ff_amf_write_number(uint8_t **dst, double val)
39 {
40  bytestream_put_byte(dst, AMF_DATA_TYPE_NUMBER);
41  bytestream_put_be64(dst, av_double2int(val));
42 }
43 
44 void ff_amf_write_array_start(uint8_t **dst, uint32_t length)
45 {
46  bytestream_put_byte(dst, AMF_DATA_TYPE_ARRAY);
47  bytestream_put_be32(dst, length);
48 }
49 
50 void ff_amf_write_string(uint8_t **dst, const char *str)
51 {
52  bytestream_put_byte(dst, AMF_DATA_TYPE_STRING);
53  bytestream_put_be16(dst, strlen(str));
54  bytestream_put_buffer(dst, str, strlen(str));
55 }
56 
57 void ff_amf_write_string2(uint8_t **dst, const char *str1, const char *str2)
58 {
59  int len1 = 0, len2 = 0;
60  if (str1)
61  len1 = strlen(str1);
62  if (str2)
63  len2 = strlen(str2);
64  bytestream_put_byte(dst, AMF_DATA_TYPE_STRING);
65  bytestream_put_be16(dst, len1 + len2);
66  bytestream_put_buffer(dst, str1, len1);
67  bytestream_put_buffer(dst, str2, len2);
68 }
69 
70 void ff_amf_write_null(uint8_t **dst)
71 {
72  bytestream_put_byte(dst, AMF_DATA_TYPE_NULL);
73 }
74 
76 {
77  bytestream_put_byte(dst, AMF_DATA_TYPE_OBJECT);
78 }
79 
80 void ff_amf_write_field_name(uint8_t **dst, const char *str)
81 {
82  bytestream_put_be16(dst, strlen(str));
83  bytestream_put_buffer(dst, str, strlen(str));
84 }
85 
87 {
88  /* first two bytes are field name length = 0,
89  * AMF object should end with it and end marker
90  */
91  bytestream_put_be24(dst, AMF_DATA_TYPE_OBJECT_END);
92 }
93 
95 {
96  uint64_t read;
97  if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NUMBER)
98  return AVERROR_INVALIDDATA;
99  read = bytestream2_get_be64(bc);
100  *val = av_int2double(read);
101  return 0;
102 }
103 
104 int ff_amf_get_string(GetByteContext *bc, uint8_t *str,
105  int strsize, int *length)
106 {
107  int stringlen = 0;
108  int readsize;
109  stringlen = bytestream2_get_be16(bc);
110  if (stringlen + 1 > strsize)
111  return AVERROR(EINVAL);
112  readsize = bytestream2_get_buffer(bc, str, stringlen);
113  if (readsize != stringlen) {
115  "Unable to read as many bytes as AMF string signaled\n");
116  }
117  str[readsize] = '\0';
118  *length = FFMIN(stringlen, readsize);
119  return 0;
120 }
121 
122 int ff_amf_read_string(GetByteContext *bc, uint8_t *str,
123  int strsize, int *length)
124 {
125  if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_STRING)
126  return AVERROR_INVALIDDATA;
127  return ff_amf_get_string(bc, str, strsize, length);
128 }
129 
131 {
132  if (bytestream2_get_byte(bc) != AMF_DATA_TYPE_NULL)
133  return AVERROR_INVALIDDATA;
134  return 0;
135 }
136 
137 int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt,
138  int channel)
139 {
140  int nb_alloc;
141  RTMPPacket *ptr;
142  if (channel < *nb_prev_pkt)
143  return 0;
144 
145  nb_alloc = channel + 16;
146  // This can't use the av_reallocp family of functions, since we
147  // would need to free each element in the array before the array
148  // itself is freed.
149  ptr = av_realloc_array(*prev_pkt, nb_alloc, sizeof(**prev_pkt));
150  if (!ptr)
151  return AVERROR(ENOMEM);
152  memset(ptr + *nb_prev_pkt, 0, (nb_alloc - *nb_prev_pkt) * sizeof(*ptr));
153  *prev_pkt = ptr;
154  *nb_prev_pkt = nb_alloc;
155  return 0;
156 }
157 
159  int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt)
160 {
161  uint8_t hdr;
162 
163  if (ffurl_read(h, &hdr, 1) != 1)
164  return AVERROR(EIO);
165 
166  return ff_rtmp_packet_read_internal(h, p, chunk_size, prev_pkt,
167  nb_prev_pkt, hdr);
168 }
169 
171  int chunk_size, RTMPPacket **prev_pkt_ptr,
172  int *nb_prev_pkt, uint8_t hdr)
173 {
174 
175  uint8_t buf[16];
176  int channel_id, timestamp, size;
177  uint32_t ts_field; // non-extended timestamp or delta field
178  uint32_t extra = 0;
179  enum RTMPPacketType type;
180  int written = 0;
181  int ret, toread;
182  RTMPPacket *prev_pkt;
183 
184  written++;
185  channel_id = hdr & 0x3F;
186 
187  if (channel_id < 2) { //special case for channel number >= 64
188  buf[1] = 0;
189  if (ffurl_read_complete(h, buf, channel_id + 1) != channel_id + 1)
190  return AVERROR(EIO);
191  written += channel_id + 1;
192  channel_id = AV_RL16(buf) + 64;
193  }
194  if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
195  channel_id)) < 0)
196  return ret;
197  prev_pkt = *prev_pkt_ptr;
198  size = prev_pkt[channel_id].size;
199  type = prev_pkt[channel_id].type;
200  extra = prev_pkt[channel_id].extra;
201 
202  hdr >>= 6; // header size indicator
203  if (hdr == RTMP_PS_ONEBYTE) {
204  ts_field = prev_pkt[channel_id].ts_field;
205  } else {
206  if (ffurl_read_complete(h, buf, 3) != 3)
207  return AVERROR(EIO);
208  written += 3;
209  ts_field = AV_RB24(buf);
210  if (hdr != RTMP_PS_FOURBYTES) {
211  if (ffurl_read_complete(h, buf, 3) != 3)
212  return AVERROR(EIO);
213  written += 3;
214  size = AV_RB24(buf);
215  if (ffurl_read_complete(h, buf, 1) != 1)
216  return AVERROR(EIO);
217  written++;
218  type = buf[0];
219  if (hdr == RTMP_PS_TWELVEBYTES) {
220  if (ffurl_read_complete(h, buf, 4) != 4)
221  return AVERROR(EIO);
222  written += 4;
223  extra = AV_RL32(buf);
224  }
225  }
226  }
227  if (ts_field == 0xFFFFFF) {
228  if (ffurl_read_complete(h, buf, 4) != 4)
229  return AVERROR(EIO);
230  timestamp = AV_RB32(buf);
231  } else {
232  timestamp = ts_field;
233  }
234  if (hdr != RTMP_PS_TWELVEBYTES)
235  timestamp += prev_pkt[channel_id].timestamp;
236 
237  if (prev_pkt[channel_id].read && size != prev_pkt[channel_id].size) {
238  av_log(h, AV_LOG_ERROR, "RTMP packet size mismatch %d != %d\n",
239  size, prev_pkt[channel_id].size);
240  ff_rtmp_packet_destroy(&prev_pkt[channel_id]);
241  prev_pkt[channel_id].read = 0;
242  return AVERROR_INVALIDDATA;
243  }
244 
245  if (!prev_pkt[channel_id].read) {
246  if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp,
247  size)) < 0)
248  return ret;
249  p->read = written;
250  p->offset = 0;
251  prev_pkt[channel_id].ts_field = ts_field;
252  prev_pkt[channel_id].timestamp = timestamp;
253  } else {
254  // previous packet in this channel hasn't completed reading
255  RTMPPacket *prev = &prev_pkt[channel_id];
256  p->data = prev->data;
257  p->size = prev->size;
258  p->channel_id = prev->channel_id;
259  p->type = prev->type;
260  p->ts_field = prev->ts_field;
261  p->extra = prev->extra;
262  p->offset = prev->offset;
263  p->read = prev->read + written;
264  p->timestamp = prev->timestamp;
265  prev->data = NULL;
266  }
267  p->extra = extra;
268  // save history
269  prev_pkt[channel_id].channel_id = channel_id;
270  prev_pkt[channel_id].type = type;
271  prev_pkt[channel_id].size = size;
272  prev_pkt[channel_id].extra = extra;
273  size = size - p->offset;
274 
275  toread = FFMIN(size, chunk_size);
276  if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) {
278  return AVERROR(EIO);
279  }
280  size -= toread;
281  p->read += toread;
282  p->offset += toread;
283 
284  if (size > 0) {
285  RTMPPacket *prev = &prev_pkt[channel_id];
286  prev->data = p->data;
287  prev->read = p->read;
288  prev->offset = p->offset;
289  p->data = NULL;
290  return AVERROR(EAGAIN);
291  }
292 
293  prev_pkt[channel_id].read = 0; // read complete; reset if needed
294  return p->read;
295 }
296 
298  RTMPPacket **prev_pkt, int *nb_prev_pkt,
299  uint8_t hdr)
300 {
301  while (1) {
302  int ret = rtmp_packet_read_one_chunk(h, p, chunk_size, prev_pkt,
303  nb_prev_pkt, hdr);
304  if (ret > 0 || ret != AVERROR(EAGAIN))
305  return ret;
306 
307  if (ffurl_read(h, &hdr, 1) != 1)
308  return AVERROR(EIO);
309  }
310 }
311 
313  int chunk_size, RTMPPacket **prev_pkt_ptr,
314  int *nb_prev_pkt)
315 {
316  uint8_t pkt_hdr[16], *p = pkt_hdr;
318  int off = 0;
319  int written = 0;
320  int ret;
321  RTMPPacket *prev_pkt;
322  int use_delta; // flag if using timestamp delta, not RTMP_PS_TWELVEBYTES
323  uint32_t timestamp; // full 32-bit timestamp or delta value
324 
325  if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
326  pkt->channel_id)) < 0)
327  return ret;
328  prev_pkt = *prev_pkt_ptr;
329 
330  //if channel_id = 0, this is first presentation of prev_pkt, send full hdr.
331  use_delta = prev_pkt[pkt->channel_id].channel_id &&
332  pkt->extra == prev_pkt[pkt->channel_id].extra &&
333  pkt->timestamp >= prev_pkt[pkt->channel_id].timestamp;
334 
335  timestamp = pkt->timestamp;
336  if (use_delta) {
337  timestamp -= prev_pkt[pkt->channel_id].timestamp;
338  }
339  if (timestamp >= 0xFFFFFF) {
340  pkt->ts_field = 0xFFFFFF;
341  } else {
342  pkt->ts_field = timestamp;
343  }
344 
345  if (use_delta) {
346  if (pkt->type == prev_pkt[pkt->channel_id].type &&
347  pkt->size == prev_pkt[pkt->channel_id].size) {
349  if (pkt->ts_field == prev_pkt[pkt->channel_id].ts_field)
351  } else {
353  }
354  }
355 
356  if (pkt->channel_id < 64) {
357  bytestream_put_byte(&p, pkt->channel_id | (mode << 6));
358  } else if (pkt->channel_id < 64 + 256) {
359  bytestream_put_byte(&p, 0 | (mode << 6));
360  bytestream_put_byte(&p, pkt->channel_id - 64);
361  } else {
362  bytestream_put_byte(&p, 1 | (mode << 6));
363  bytestream_put_le16(&p, pkt->channel_id - 64);
364  }
365  if (mode != RTMP_PS_ONEBYTE) {
366  bytestream_put_be24(&p, pkt->ts_field);
367  if (mode != RTMP_PS_FOURBYTES) {
368  bytestream_put_be24(&p, pkt->size);
369  bytestream_put_byte(&p, pkt->type);
370  if (mode == RTMP_PS_TWELVEBYTES)
371  bytestream_put_le32(&p, pkt->extra);
372  }
373  }
374  if (pkt->ts_field == 0xFFFFFF)
375  bytestream_put_be32(&p, timestamp);
376  // save history
377  prev_pkt[pkt->channel_id].channel_id = pkt->channel_id;
378  prev_pkt[pkt->channel_id].type = pkt->type;
379  prev_pkt[pkt->channel_id].size = pkt->size;
380  prev_pkt[pkt->channel_id].timestamp = pkt->timestamp;
381  prev_pkt[pkt->channel_id].ts_field = pkt->ts_field;
382  prev_pkt[pkt->channel_id].extra = pkt->extra;
383 
384  // FIXME:
385  // Writing packets is currently not optimized to minimize system calls.
386  // Since system calls flush on exit which we cannot change in a system-independant way.
387  // We should fix this behavior and by writing packets in a single or in as few as possible system calls.
388  // Protocols like TCP and RTMP should benefit from this when enabling TCP_NODELAY.
389 
390  if ((ret = ffurl_write(h, pkt_hdr, p - pkt_hdr)) < 0)
391  return ret;
392  written = p - pkt_hdr + pkt->size;
393  while (off < pkt->size) {
394  int towrite = FFMIN(chunk_size, pkt->size - off);
395  if ((ret = ffurl_write(h, pkt->data + off, towrite)) < 0)
396  return ret;
397  off += towrite;
398  if (off < pkt->size) {
399  uint8_t marker = 0xC0 | pkt->channel_id;
400  if ((ret = ffurl_write(h, &marker, 1)) < 0)
401  return ret;
402  written++;
403  if (pkt->ts_field == 0xFFFFFF) {
404  uint8_t ts_header[4];
405  AV_WB32(ts_header, timestamp);
406  if ((ret = ffurl_write(h, ts_header, 4)) < 0)
407  return ret;
408  written += 4;
409  }
410  }
411  }
412  return written;
413 }
414 
416  int timestamp, int size)
417 {
418  if (size) {
419  pkt->data = av_realloc(NULL, size);
420  if (!pkt->data)
421  return AVERROR(ENOMEM);
422  }
423  pkt->size = size;
424  pkt->channel_id = channel_id;
425  pkt->type = type;
426  pkt->timestamp = timestamp;
427  pkt->extra = 0;
428  pkt->ts_field = 0;
429 
430  return 0;
431 }
432 
434 {
435  if (!pkt)
436  return;
437  av_freep(&pkt->data);
438  pkt->size = 0;
439 }
440 
441 static int amf_tag_skip(GetByteContext *gb, int depth)
442 {
444  unsigned nb = -1;
445 
446  if (bytestream2_get_bytes_left(gb) < 1)
447  return -1;
448 
449  if (depth > MAX_DEPTH) {
450  av_log(NULL, AV_LOG_ERROR, "amf_tag_skip: exceeded max depth\n");
451  return AVERROR_PATCHWELCOME;
452  }
453 
454  type = bytestream2_get_byte(gb);
455  switch (type) {
457  bytestream2_get_be64(gb);
458  return 0;
459  case AMF_DATA_TYPE_BOOL:
460  bytestream2_get_byte(gb);
461  return 0;
463  bytestream2_skip(gb, bytestream2_get_be16(gb));
464  return 0;
466  bytestream2_skip(gb, bytestream2_get_be32(gb));
467  return 0;
468  case AMF_DATA_TYPE_NULL:
469  return 0;
470  case AMF_DATA_TYPE_DATE:
471  bytestream2_skip(gb, 10);
472  return 0;
473  case AMF_DATA_TYPE_ARRAY:
475  nb = bytestream2_get_be32(gb);
477  while (type != AMF_DATA_TYPE_ARRAY || nb-- > 0) {
478  int t;
479  if (type != AMF_DATA_TYPE_ARRAY) {
480  int size = bytestream2_get_be16(gb);
481  if (!size) {
482  bytestream2_get_byte(gb);
483  break;
484  }
485  if (size < 0 || size >= bytestream2_get_bytes_left(gb))
486  return -1;
487  bytestream2_skip(gb, size);
488  }
489  t = amf_tag_skip(gb, depth + 1);
490  if (t < 0 || bytestream2_get_bytes_left(gb) <= 0)
491  return -1;
492  }
493  return 0;
494  case AMF_DATA_TYPE_OBJECT_END: return 0;
495  default: return -1;
496  }
497 }
498 
499 int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
500 {
501  GetByteContext gb;
502  int ret;
503 
504  if (data >= data_end)
505  return -1;
506 
507  bytestream2_init(&gb, data, data_end - data);
508 
509  ret = amf_tag_skip(&gb, 0);
510  if (ret < 0 || bytestream2_get_bytes_left(&gb) <= 0)
511  return -1;
512  av_assert0(bytestream2_tell(&gb) >= 0 && bytestream2_tell(&gb) <= data_end - data);
513  return bytestream2_tell(&gb);
514 }
515 
517  const uint8_t *name, uint8_t *dst, int dst_size)
518 {
519  int namelen = strlen(name);
520  int len;
521 
522  while (bytestream2_peek_byte(gb) != AMF_DATA_TYPE_OBJECT && bytestream2_get_bytes_left(gb) > 0) {
523  int ret = amf_tag_skip(gb, 0);
524  if (ret < 0)
525  return -1;
526  }
527  if (bytestream2_get_bytes_left(gb) < 3)
528  return -1;
529  bytestream2_get_byte(gb);
530 
531  for (;;) {
532  int size = bytestream2_get_be16(gb);
533  if (!size)
534  break;
535  if (size < 0 || size >= bytestream2_get_bytes_left(gb))
536  return -1;
537  bytestream2_skip(gb, size);
538  if (size == namelen && !memcmp(gb->buffer-size, name, namelen)) {
539  switch (bytestream2_get_byte(gb)) {
541  snprintf(dst, dst_size, "%g", av_int2double(bytestream2_get_be64(gb)));
542  break;
543  case AMF_DATA_TYPE_BOOL:
544  snprintf(dst, dst_size, "%s", bytestream2_get_byte(gb) ? "true" : "false");
545  break;
547  len = bytestream2_get_be16(gb);
548  if (dst_size < 1)
549  return -1;
550  if (dst_size < len + 1)
551  len = dst_size - 1;
553  dst[len] = 0;
554  break;
555  default:
556  return -1;
557  }
558  return 0;
559  }
560  len = amf_tag_skip(gb, 0);
561  if (len < 0 || bytestream2_get_bytes_left(gb) <= 0)
562  return -1;
563  }
564  return -1;
565 }
566 
567 int ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end,
568  const uint8_t *name, uint8_t *dst, int dst_size)
569 {
570  GetByteContext gb;
571 
572  if (data >= data_end)
573  return -1;
574 
575  bytestream2_init(&gb, data, data_end - data);
576 
577  return amf_get_field_value2(&gb, name, dst, dst_size);
578 }
579 
580 #ifdef DEBUG
581 static const char* rtmp_packet_type(int type)
582 {
583  switch (type) {
584  case RTMP_PT_CHUNK_SIZE: return "chunk size";
585  case RTMP_PT_BYTES_READ: return "bytes read";
586  case RTMP_PT_USER_CONTROL: return "user control";
587  case RTMP_PT_WINDOW_ACK_SIZE: return "window acknowledgement size";
588  case RTMP_PT_SET_PEER_BW: return "set peer bandwidth";
589  case RTMP_PT_AUDIO: return "audio packet";
590  case RTMP_PT_VIDEO: return "video packet";
591  case RTMP_PT_FLEX_STREAM: return "Flex shared stream";
592  case RTMP_PT_FLEX_OBJECT: return "Flex shared object";
593  case RTMP_PT_FLEX_MESSAGE: return "Flex shared message";
594  case RTMP_PT_NOTIFY: return "notification";
595  case RTMP_PT_SHARED_OBJ: return "shared object";
596  case RTMP_PT_INVOKE: return "invoke";
597  case RTMP_PT_METADATA: return "metadata";
598  default: return "unknown";
599  }
600 }
601 
602 static void amf_tag_contents(void *ctx, const uint8_t *data,
603  const uint8_t *data_end, int depth)
604 {
605  unsigned int size, nb = -1;
606  char buf[1024];
608  int parse_key = 1;
609 
610  if (depth > MAX_DEPTH) {
611  av_log(NULL, AV_LOG_ERROR, "amf_tag_contents: exceeded max depth\n");
612  return;
613  }
614 
615  if (data >= data_end)
616  return;
617  switch ((type = *data++)) {
619  av_log(ctx, AV_LOG_DEBUG, " number %g\n", av_int2double(AV_RB64(data)));
620  return;
621  case AMF_DATA_TYPE_BOOL:
622  av_log(ctx, AV_LOG_DEBUG, " bool %d\n", *data);
623  return;
626  if (type == AMF_DATA_TYPE_STRING) {
627  size = bytestream_get_be16(&data);
628  } else {
629  size = bytestream_get_be32(&data);
630  }
631  size = FFMIN(size, sizeof(buf) - 1);
632  memcpy(buf, data, size);
633  buf[size] = 0;
634  av_log(ctx, AV_LOG_DEBUG, " string '%s'\n", buf);
635  return;
636  case AMF_DATA_TYPE_NULL:
637  av_log(ctx, AV_LOG_DEBUG, " NULL\n");
638  return;
639  case AMF_DATA_TYPE_ARRAY:
640  parse_key = 0;
642  nb = bytestream_get_be32(&data);
644  av_log(ctx, AV_LOG_DEBUG, " {\n");
645  while (nb-- > 0 || type != AMF_DATA_TYPE_ARRAY) {
646  int t;
647  if (parse_key) {
648  size = bytestream_get_be16(&data);
649  size = FFMIN(size, sizeof(buf) - 1);
650  if (!size) {
651  av_log(ctx, AV_LOG_DEBUG, " }\n");
652  data++;
653  break;
654  }
655  memcpy(buf, data, size);
656  buf[size] = 0;
657  if (size >= data_end - data)
658  return;
659  data += size;
660  av_log(ctx, AV_LOG_DEBUG, " %s: ", buf);
661  }
662  amf_tag_contents(ctx, data, data_end, depth + 1);
663  t = ff_amf_tag_size(data, data_end);
664  if (t < 0 || t >= data_end - data)
665  return;
666  data += t;
667  }
668  return;
670  av_log(ctx, AV_LOG_DEBUG, " }\n");
671  return;
672  default:
673  return;
674  }
675 }
676 
677 void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
678 {
679  av_log(ctx, AV_LOG_DEBUG, "RTMP packet type '%s'(%d) for channel %d, timestamp %d, extra field %d size %d\n",
680  rtmp_packet_type(p->type), p->type, p->channel_id, p->timestamp, p->extra, p->size);
681  if (p->type == RTMP_PT_INVOKE || p->type == RTMP_PT_NOTIFY) {
682  uint8_t *src = p->data, *src_end = p->data + p->size;
683  while (src < src_end) {
684  int sz;
685  amf_tag_contents(ctx, src, src_end, 0);
686  sz = ff_amf_tag_size(src, src_end);
687  if (sz < 0)
688  break;
689  src += sz;
690  }
691  } else if (p->type == RTMP_PT_WINDOW_ACK_SIZE) {
692  av_log(ctx, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", AV_RB32(p->data));
693  } else if (p->type == RTMP_PT_SET_PEER_BW) {
694  av_log(ctx, AV_LOG_DEBUG, "Set Peer BW = %d\n", AV_RB32(p->data));
695  } else if (p->type != RTMP_PT_AUDIO && p->type != RTMP_PT_VIDEO && p->type != RTMP_PT_METADATA) {
696  int i;
697  for (i = 0; i < p->size; i++)
698  av_log(ctx, AV_LOG_DEBUG, " %02X", p->data[i]);
699  av_log(ctx, AV_LOG_DEBUG, "\n");
700  }
701 }
702 #endif
703 
704 int ff_amf_match_string(const uint8_t *data, int size, const char *str)
705 {
706  int len = strlen(str);
707  int amf_len, type;
708 
709  if (size < 1)
710  return 0;
711 
712  type = *data++;
713 
716  return 0;
717 
719  if ((size -= 4 + 1) < 0)
720  return 0;
721  amf_len = bytestream_get_be32(&data);
722  } else {
723  if ((size -= 2 + 1) < 0)
724  return 0;
725  amf_len = bytestream_get_be16(&data);
726  }
727 
728  if (amf_len > size)
729  return 0;
730 
731  if (amf_len != len)
732  return 0;
733 
734  return !memcmp(data, str, len);
735 }
RTMP_PT_METADATA
@ RTMP_PT_METADATA
FLV metadata.
Definition: rtmppkt.h:61
RTMP_PT_FLEX_MESSAGE
@ RTMP_PT_FLEX_MESSAGE
Flex shared message.
Definition: rtmppkt.h:57
AMF_DATA_TYPE_OBJECT_END
@ AMF_DATA_TYPE_OBJECT_END
Definition: flv.h:176
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
RTMP_PT_FLEX_OBJECT
@ RTMP_PT_FLEX_OBJECT
Flex shared object.
Definition: rtmppkt.h:56
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
RTMP_PT_SHARED_OBJ
@ RTMP_PT_SHARED_OBJ
shared object
Definition: rtmppkt.h:59
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
RTMP_PT_BYTES_READ
@ RTMP_PT_BYTES_READ
number of bytes read
Definition: rtmppkt.h:49
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g)
Definition: bytestream.h:158
RTMPPacket::type
RTMPPacketType type
packet payload type
Definition: rtmppkt.h:79
GetByteContext
Definition: bytestream.h:33
bytestream2_tell
static av_always_inline int bytestream2_tell(const GetByteContext *g)
Definition: bytestream.h:192
av_int2double
static av_always_inline double av_int2double(uint64_t i)
Reinterpret a 64-bit integer as a double.
Definition: intfloat.h:60
RTMP_PT_NOTIFY
@ RTMP_PT_NOTIFY
some notification
Definition: rtmppkt.h:58
ffurl_write
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition: url.h:202
mode
Definition: swscale.c:56
AVPacket::data
uint8_t * data
Definition: packet.h:588
data
const char data[16]
Definition: mxf.c:149
ff_amf_write_field_name
void ff_amf_write_field_name(uint8_t **dst, const char *str)
Write string used as field name in AMF object to buffer.
Definition: rtmppkt.c:80
ff_amf_match_string
int ff_amf_match_string(const uint8_t *data, int size, const char *str)
Match AMF string with a NULL-terminated string.
Definition: rtmppkt.c:704
RTMP_PT_WINDOW_ACK_SIZE
@ RTMP_PT_WINDOW_ACK_SIZE
window acknowledgement size
Definition: rtmppkt.h:51
AMF_DATA_TYPE_DATE
@ AMF_DATA_TYPE_DATE
Definition: flv.h:178
RTMPPacket::extra
uint32_t extra
probably an additional channel ID used during streaming data
Definition: rtmppkt.h:82
intfloat.h
ff_rtmp_packet_read_internal
int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt, uint8_t hdr)
Read internal RTMP packet sent by the server.
Definition: rtmppkt.c:297
AMF_DATA_TYPE_OBJECT
@ AMF_DATA_TYPE_OBJECT
Definition: flv.h:171
ff_amf_write_bool
void ff_amf_write_bool(uint8_t **dst, int val)
Write boolean value in AMF format to buffer.
Definition: rtmppkt.c:32
MAX_DEPTH
#define MAX_DEPTH
arbitrary limit to prevent unbounded recursion
Definition: rtmppkt.c:30
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
ff_rtmp_packet_read
int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt)
Read RTMP packet sent by the server.
Definition: rtmppkt.c:158
val
static double val(void *priv, double ch)
Definition: aeval.c:77
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
ff_amf_get_string
int ff_amf_get_string(GetByteContext *bc, uint8_t *str, int strsize, int *length)
Get AMF string value.
Definition: rtmppkt.c:104
amf_get_field_value2
static int amf_get_field_value2(GetByteContext *gb, const uint8_t *name, uint8_t *dst, int dst_size)
Definition: rtmppkt.c:516
AMFDataType
AMFDataType
Definition: flv.h:167
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
ff_amf_write_string
void ff_amf_write_string(uint8_t **dst, const char *str)
Write string in AMF format to buffer.
Definition: rtmppkt.c:50
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:217
GetByteContext::buffer
const uint8_t * buffer
Definition: bytestream.h:34
RTMPPacket::read
int read
amount read, including headers
Definition: rtmppkt.h:86
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
parse_key
static int parse_key(DBEContext *s)
Definition: dolby_e.c:626
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
AV_RL16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:94
NULL
#define NULL
Definition: coverity.c:32
RTMPPacket
structure for holding RTMP packets
Definition: rtmppkt.h:77
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
RTMPPacketType
RTMPPacketType
known RTMP packet types
Definition: rtmppkt.h:47
ff_amf_write_object_end
void ff_amf_write_object_end(uint8_t **dst)
Write marker for end of AMF object to buffer.
Definition: rtmppkt.c:86
AMF_DATA_TYPE_BOOL
@ AMF_DATA_TYPE_BOOL
Definition: flv.h:169
ff_rtmp_packet_destroy
void ff_rtmp_packet_destroy(RTMPPacket *pkt)
Free RTMP packet.
Definition: rtmppkt.c:433
bytestream2_get_buffer
static av_always_inline unsigned int bytestream2_get_buffer(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:267
flv.h
AMF_DATA_TYPE_ARRAY
@ AMF_DATA_TYPE_ARRAY
Definition: flv.h:177
RTMP_PT_USER_CONTROL
@ RTMP_PT_USER_CONTROL
user control
Definition: rtmppkt.h:50
ff_rtmp_packet_write
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, int chunk_size, RTMPPacket **prev_pkt_ptr, int *nb_prev_pkt)
Send RTMP packet to the server.
Definition: rtmppkt.c:312
RTMPPacket::size
int size
packet payload size
Definition: rtmppkt.h:84
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:415
AVPacket::size
int size
Definition: packet.h:589
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
ff_amf_get_field_value
int ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end, const uint8_t *name, uint8_t *dst, int dst_size)
Retrieve value of given AMF object field in string form.
Definition: rtmppkt.c:567
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
RTMP_PT_INVOKE
@ RTMP_PT_INVOKE
invoke some stream action
Definition: rtmppkt.h:60
size
int size
Definition: twinvq_data.h:10344
AV_RB32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:96
ff_amf_write_null
void ff_amf_write_null(uint8_t **dst)
Write AMF NULL value to buffer.
Definition: rtmppkt.c:70
RTMPPacket::ts_field
uint32_t ts_field
24-bit timestamp or increment to the previous one, in milliseconds (latter only for media packets)....
Definition: rtmppkt.h:81
ff_rtmp_packet_dump
void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
Print information and contents of RTMP packet.
rtmp_packet_read_one_chunk
static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p, int chunk_size, RTMPPacket **prev_pkt_ptr, int *nb_prev_pkt, uint8_t hdr)
Definition: rtmppkt.c:170
ff_rtmp_packet_create
int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, int timestamp, int size)
Create new RTMP packet with given attributes.
Definition: rtmppkt.c:415
ff_rtmp_check_alloc_array
int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt, int channel)
Enlarge the prev_pkt array to fit the given channel.
Definition: rtmppkt.c:137
av_double2int
static av_always_inline uint64_t av_double2int(double f)
Reinterpret a double as a 64-bit integer.
Definition: intfloat.h:70
rtmppkt.h
bytestream_put_buffer
static av_always_inline void bytestream_put_buffer(uint8_t **b, const uint8_t *src, unsigned int size)
Definition: bytestream.h:372
URLContext
Definition: url.h:35
RTMPPacket::timestamp
uint32_t timestamp
packet full timestamp
Definition: rtmppkt.h:80
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
url.h
len
int len
Definition: vorbis_enc_data.h:426
RTMP_PT_SET_PEER_BW
@ RTMP_PT_SET_PEER_BW
peer bandwidth
Definition: rtmppkt.h:52
AMF_DATA_TYPE_MIXEDARRAY
@ AMF_DATA_TYPE_MIXEDARRAY
Definition: flv.h:175
AMF_DATA_TYPE_STRING
@ AMF_DATA_TYPE_STRING
Definition: flv.h:170
ff_amf_write_string2
void ff_amf_write_string2(uint8_t **dst, const char *str1, const char *str2)
Write a string consisting of two parts in AMF format to a buffer.
Definition: rtmppkt.c:57
RTMPPacket::offset
int offset
amount of data read so far
Definition: rtmppkt.h:85
ret
ret
Definition: filter_design.txt:187
ff_amf_read_number
int ff_amf_read_number(GetByteContext *bc, double *val)
Read AMF number value.
Definition: rtmppkt.c:94
AV_RL32
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:92
ff_amf_write_number
void ff_amf_write_number(uint8_t **dst, double val)
Write number in AMF format to buffer.
Definition: rtmppkt.c:38
RTMPPacket::channel_id
int channel_id
RTMP channel ID (nothing to do with audio/video channels though)
Definition: rtmppkt.h:78
ff_amf_write_array_start
void ff_amf_write_array_start(uint8_t **dst, uint32_t length)
Write marker and length for AMF array to buffer.
Definition: rtmppkt.c:44
RTMP_PS_EIGHTBYTES
@ RTMP_PS_EIGHTBYTES
packet has 8-byte header
Definition: rtmppkt.h:69
RTMPPacket::data
uint8_t * data
packet payload
Definition: rtmppkt.h:83
ff_amf_write_object_start
void ff_amf_write_object_start(uint8_t **dst)
Write marker for AMF object to buffer.
Definition: rtmppkt.c:75
AMF_DATA_TYPE_LONG_STRING
@ AMF_DATA_TYPE_LONG_STRING
Definition: flv.h:179
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
mem.h
AMF_DATA_TYPE_NUMBER
@ AMF_DATA_TYPE_NUMBER
Definition: flv.h:168
ffurl_read_complete
int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
Read as many bytes as possible (up to size), calling the read function multiple times if necessary.
Definition: avio.c:558
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
RTMP_PS_ONEBYTE
@ RTMP_PS_ONEBYTE
packet is really a next chunk of a packet
Definition: rtmppkt.h:71
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
amf_tag_skip
static int amf_tag_skip(GetByteContext *gb, int depth)
Definition: rtmppkt.c:441
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2070
pkt
static AVPacket * pkt
Definition: demux_decode.c:55
RTMP_PT_AUDIO
@ RTMP_PT_AUDIO
audio packet
Definition: rtmppkt.h:53
AV_RB24
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_RB24
Definition: bytestream.h:97
ff_amf_read_null
int ff_amf_read_null(GetByteContext *bc)
Read AMF NULL value.
Definition: rtmppkt.c:130
RTMP_PS_TWELVEBYTES
@ RTMP_PS_TWELVEBYTES
packet has 12-byte header
Definition: rtmppkt.h:68
snprintf
#define snprintf
Definition: snprintf.h:34
RTMP_PT_VIDEO
@ RTMP_PT_VIDEO
video packet
Definition: rtmppkt.h:54
RTMP_PS_FOURBYTES
@ RTMP_PS_FOURBYTES
packet has 4-byte header
Definition: rtmppkt.h:70
AV_RB64
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_RB64
Definition: bytestream.h:95
RTMP_PT_FLEX_STREAM
@ RTMP_PT_FLEX_STREAM
Flex shared stream.
Definition: rtmppkt.h:55
src
#define src
Definition: vp8dsp.c:248
channel
channel
Definition: ebur128.h:39
read
static uint32_t BS_FUNC() read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
Definition: bitstream_template.h:239
AMF_DATA_TYPE_NULL
@ AMF_DATA_TYPE_NULL
Definition: flv.h:172
ff_amf_tag_size
int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
Calculate number of bytes taken by first AMF entry in data.
Definition: rtmppkt.c:499
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:155
ffurl_read
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: url.h:181
RTMP_PT_CHUNK_SIZE
@ RTMP_PT_CHUNK_SIZE
chunk size change
Definition: rtmppkt.h:48
ff_amf_read_string
int ff_amf_read_string(GetByteContext *bc, uint8_t *str, int strsize, int *length)
Read AMF string value.
Definition: rtmppkt.c:122