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.

пре 10 месеци
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. #include "sockutil.h"
  2. #include "sys/system.h"
  3. #include "rtmp-client.h"
  4. #include "flv-reader.h"
  5. #include "flv-proto.h"
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include <time.h>
  11. //#define CORRUPT_RTMP_CHUNK_DATA
  12. #if defined(CORRUPT_RTMP_CHUNK_DATA)
  13. static void rtmp_corrupt_data(const void* data, size_t bytes)
  14. {
  15. static unsigned int seed;
  16. if (0 == seed)
  17. {
  18. seed = (unsigned int)time(NULL);
  19. srand(seed);
  20. }
  21. if (bytes < 1)
  22. return;
  23. //size_t i = bytes > 20 ? 20 : bytes;
  24. //i = rand() % i;
  25. //uint8_t v = ((uint8_t*)data)[i];
  26. //((uint8_t*)data)[i] = rand() % 255;
  27. //printf("rtmp_corrupt_data[%d] %d == %d\n", i, (int)v, (int)((uint8_t*)data)[i]);
  28. if (5 == rand() % 10)
  29. {
  30. size_t i = rand() % bytes;
  31. uint8_t v = ((uint8_t*)data)[i];
  32. ((uint8_t*)data)[i] = rand() % 255;
  33. printf("rtmp_corrupt_data[%d] %d == %d\n", i, (int)v, (int)((uint8_t*)data)[i]);
  34. }
  35. }
  36. static uint8_t s_buffer[4 * 1024 * 1024];
  37. static size_t s_offset;
  38. static FILE* s_fp;
  39. static void fwritepacket(uint32_t timestamp)
  40. {
  41. assert(4 == fwrite(&s_offset, 1, 4, s_fp));
  42. assert(4 == fwrite(&timestamp, 1, 4, s_fp));
  43. assert(s_offset == fwrite(s_buffer, 1, s_offset, s_fp));
  44. s_offset = 0;
  45. }
  46. #endif
  47. static int rtmp_client_send(void* param, const void* header, size_t len, const void* data, size_t bytes)
  48. {
  49. socket_t* socket = (socket_t*)param;
  50. socket_bufvec_t vec[2];
  51. socket_setbufvec(vec, 0, (void*)header, len);
  52. socket_setbufvec(vec, 1, (void*)data, bytes);
  53. #if defined(CORRUPT_RTMP_CHUNK_DATA)
  54. //if (len > 0)
  55. //{
  56. // assert(s_offset + len < sizeof(s_buffer));
  57. // memcpy(s_buffer + s_offset, header, len);
  58. // s_offset += len;
  59. //}
  60. //if (bytes > 0)
  61. //{
  62. // assert(s_offset + bytes < sizeof(s_buffer));
  63. // memcpy(s_buffer + s_offset, data, bytes);
  64. // s_offset += bytes;
  65. //}
  66. rtmp_corrupt_data(header, len);
  67. rtmp_corrupt_data(data, bytes);
  68. #endif
  69. return socket_send_v_all_by_time(*socket, vec, bytes > 0 ? 2 : 1, 0, 5000);
  70. }
  71. static void rtmp_client_push(const char* flv, rtmp_client_t* rtmp)
  72. {
  73. int r, type;
  74. int avcrecord = 0;
  75. int aacconfig = 0;
  76. size_t taglen;
  77. uint32_t timestamp;
  78. uint32_t s_timestamp = 0;
  79. uint32_t diff = 0;
  80. uint64_t clock;
  81. static char packet[2 * 1024 * 1024];
  82. while (1)
  83. {
  84. void* f = flv_reader_create(flv);
  85. clock = system_clock(); // timestamp start from 0
  86. while (1 == flv_reader_read(f, &type, &timestamp, &taglen, packet, sizeof(packet)))
  87. {
  88. uint64_t t = system_clock();
  89. if (clock + timestamp > t && clock + timestamp < t + 3 * 1000) // dts skip
  90. system_sleep(clock + timestamp - t);
  91. else if (clock + timestamp > t + 3 * 1000)
  92. clock = t - timestamp;
  93. timestamp += diff;
  94. s_timestamp = timestamp > s_timestamp ? timestamp : s_timestamp;
  95. if (FLV_TYPE_AUDIO == type)
  96. {
  97. if (0 == packet[1])
  98. {
  99. if(0 != aacconfig)
  100. continue;
  101. aacconfig = 1;
  102. }
  103. r = rtmp_client_push_audio(rtmp, packet, taglen, timestamp);
  104. }
  105. else if (FLV_TYPE_VIDEO == type)
  106. {
  107. if (0 == packet[1] || 2 == packet[1])
  108. {
  109. if (0 != avcrecord)
  110. continue;
  111. avcrecord = 1;
  112. }
  113. //bool keyframe = 1 == ((packet[0] & 0xF0) >> 4);
  114. //printf("timestamp: %u, s_timestamp: %u%s\n", timestamp, s_timestamp, keyframe ? " [I]" : "");
  115. //if (timestamp > 10 * 1000 && keyframe)
  116. //{
  117. // uint8_t header[5];
  118. // header[0] = (1 << 4) /* FrameType */ | 7 /* AVC */;
  119. // header[1] = 2; // AVC end of sequence
  120. // header[2] = 0;
  121. // header[3] = 0;
  122. // header[4] = 0;
  123. // r = rtmp_client_push_video(rtmp, header, 5, timestamp);
  124. // system_sleep(600 * 1000);
  125. //}
  126. r = rtmp_client_push_video(rtmp, packet, taglen, timestamp);
  127. }
  128. else if (FLV_TYPE_SCRIPT == type)
  129. {
  130. r = rtmp_client_push_script(rtmp, packet, taglen, timestamp);
  131. }
  132. else
  133. {
  134. assert(0);
  135. r = 0; // ignore
  136. }
  137. if (0 != r)
  138. {
  139. assert(0);
  140. break; // TODO: handle send failed
  141. }
  142. }
  143. flv_reader_destroy(f);
  144. diff = s_timestamp + 30;
  145. }
  146. EXIT:
  147. return;
  148. }
  149. // rtmp://video-center.alivecdn.com/live/hello?vhost=your.domain
  150. // rtmp_publish_test("video-center.alivecdn.com", "live", "hello?vhost=your.domain", local-flv-file-name)
  151. void rtmp_publish_test(const char* host, const char* app, const char* stream, const char* flv)
  152. {
  153. static char packet[2 * 1024 * 1024];
  154. snprintf(packet, sizeof(packet), "rtmp://%s/%s", host, app); // tcurl
  155. struct rtmp_client_handler_t handler;
  156. memset(&handler, 0, sizeof(handler));
  157. handler.send = rtmp_client_send;
  158. socket_init();
  159. socket_t socket = socket_connect_host(host, 1935, 2000);
  160. socket_setnonblock(socket, 0);
  161. rtmp_client_t* rtmp = rtmp_client_create(app, stream, packet/*tcurl*/, &socket, &handler);
  162. int r = rtmp_client_start(rtmp, 0);
  163. while (4 != rtmp_client_getstate(rtmp) && (r = socket_recv(socket, packet, sizeof(packet), 0)) > 0)
  164. {
  165. assert(0 == rtmp_client_input(rtmp, packet, r));
  166. }
  167. rtmp_client_push(flv, rtmp);
  168. rtmp_client_destroy(rtmp);
  169. socket_close(socket);
  170. socket_cleanup();
  171. }