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