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