You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.7KB

  1. #include "rtmp-chunk-header.h"
  2. #include "rtmp-internal.h"
  3. #include "rtmp-util.h"
  4. #include <string.h>
  5. #include <assert.h>
  6. #include <errno.h>
  7. // 5.3.1. Chunk Format (p11)
  8. /* 3-bytes basic header + 11-bytes message header + 4-bytes extended timestamp */
  9. //#define MAX_CHUNK_HEADER 18
  10. static struct rtmp_packet_t* rtmp_packet_find(struct rtmp_t* rtmp, uint32_t cid)
  11. {
  12. uint32_t i;
  13. struct rtmp_packet_t* pkt;
  14. // The protocol supports up to 65597 streams with IDs 3-65599
  15. assert(cid <= 65535 + 64 && cid >= 2 /* Protocol Control Messages */);
  16. for (i = 0; i < N_CHUNK_STREAM; i++)
  17. {
  18. pkt = rtmp->out_packets + ((i + cid) % N_CHUNK_STREAM);
  19. if (pkt->header.cid == cid)
  20. return pkt;
  21. }
  22. return NULL;
  23. }
  24. //static struct rtmp_packet_t* rtmp_packet_create(struct rtmp_t* rtmp, uint32_t cid)
  25. //{
  26. // uint32_t i;
  27. // struct rtmp_packet_t* pkt;
  28. //
  29. // // The protocol supports up to 65597 streams with IDs 3-65599
  30. // assert(cid <= 65535 + 64 && cid >= 2 /* Protocol Control Messages */);
  31. // assert(NULL == rtmp_packet_find(rtmp, cid));
  32. // for (i = 0; i < N_CHUNK_STREAM; i++)
  33. // {
  34. // pkt = rtmp->out_packets + ((i + cid) % N_CHUNK_STREAM);
  35. // if (0 == pkt->header.cid)
  36. // return pkt;
  37. // }
  38. // return NULL;
  39. //}
  40. static const struct rtmp_chunk_header_t* rtmp_chunk_header_zip(struct rtmp_t* rtmp, const struct rtmp_chunk_header_t* header)
  41. {
  42. struct rtmp_packet_t* pkt; // previous saved chunk header
  43. struct rtmp_chunk_header_t h;
  44. assert(0 != header->cid && 1 != header->cid);
  45. assert(RTMP_CHUNK_TYPE_0 == header->fmt || RTMP_CHUNK_TYPE_1 == header->fmt);
  46. memcpy(&h, header, sizeof(h));
  47. // find previous chunk header
  48. pkt = rtmp_packet_find(rtmp, h.cid);
  49. if (NULL == pkt)
  50. {
  51. //pkt = rtmp_packet_create(rtmp, h.cid);
  52. //if (NULL == pkt)
  53. // return NULL; // too many chunk stream id
  54. assert(0);
  55. return NULL; // can't find chunk stream id
  56. }
  57. h.fmt = RTMP_CHUNK_TYPE_0;
  58. if (RTMP_CHUNK_TYPE_0 != header->fmt /* enable compress */
  59. && header->cid == pkt->header.cid /* not the first packet */
  60. && header->timestamp >= pkt->clock /* timestamp wrap */
  61. && header->timestamp - pkt->clock < 0xFFFFFF /* timestamp delta < 1 << 24 */
  62. && header->stream_id == pkt->header.stream_id /* message stream id */)
  63. {
  64. h.fmt = RTMP_CHUNK_TYPE_1;
  65. h.timestamp -= pkt->clock; // timestamp delta
  66. if (header->type == pkt->header.type && header->length == pkt->header.length)
  67. {
  68. h.fmt = RTMP_CHUNK_TYPE_2;
  69. if (h.timestamp == pkt->header.timestamp)
  70. h.fmt = RTMP_CHUNK_TYPE_3;
  71. }
  72. }
  73. memcpy(&pkt->header, &h, sizeof(h));
  74. pkt->clock = header->timestamp; // save timestamp
  75. return &pkt->header;
  76. }
  77. int rtmp_chunk_write(struct rtmp_t* rtmp, const struct rtmp_chunk_header_t* h, const uint8_t* payload)
  78. {
  79. int r = 0;
  80. uint8_t p[MAX_CHUNK_HEADER];
  81. uint32_t chunkSize, headerSize, payloadSize;
  82. const struct rtmp_chunk_header_t* header;
  83. // compression rtmp chunk header
  84. header = rtmp_chunk_header_zip(rtmp, h);
  85. if (!header || header->length >= 0xFFFFFF)
  86. return -EINVAL; // invalid length
  87. payloadSize = header->length;
  88. headerSize = rtmp_chunk_basic_header_write(p, header->fmt, header->cid);
  89. headerSize += rtmp_chunk_message_header_write(p + headerSize, header);
  90. if(header->timestamp >= 0xFFFFFF)
  91. headerSize += rtmp_chunk_extended_timestamp_write(p + headerSize, header->timestamp);
  92. while (payloadSize > 0 && 0 == r)
  93. {
  94. chunkSize = payloadSize < rtmp->out_chunk_size ? payloadSize : rtmp->out_chunk_size;
  95. r = rtmp->send(rtmp->param, p, headerSize, payload, chunkSize); // callback
  96. payload += chunkSize;
  97. payloadSize -= chunkSize;
  98. if (payloadSize > 0)
  99. {
  100. headerSize = rtmp_chunk_basic_header_write(p, RTMP_CHUNK_TYPE_3, header->cid);
  101. if (header->timestamp >= 0xFFFFFF)
  102. headerSize += rtmp_chunk_extended_timestamp_write(p + headerSize, header->timestamp);
  103. }
  104. }
  105. return r;
  106. }