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