flv.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /**********************************************************************************************/
  2. /* The MIT License */
  3. /* */
  4. /* Copyright 2016-2016 Twitch Interactive, Inc. or its affiliates. All Rights Reserved. */
  5. /* */
  6. /* Permission is hereby granted, free of charge, to any person obtaining a copy */
  7. /* of this software and associated documentation files (the "Software"), to deal */
  8. /* in the Software without restriction, including without limitation the rights */
  9. /* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */
  10. /* copies of the Software, and to permit persons to whom the Software is */
  11. /* furnished to do so, subject to the following conditions: */
  12. /* */
  13. /* The above copyright notice and this permission notice shall be included in */
  14. /* all copies or substantial portions of the Software. */
  15. /* */
  16. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */
  17. /* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */
  18. /* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */
  19. /* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */
  20. /* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
  21. /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN */
  22. /* THE SOFTWARE. */
  23. /**********************************************************************************************/
  24. #include "flv.h"
  25. #include <stdlib.h>
  26. #include <string.h>
  27. void flvtag_init (flvtag_t* tag)
  28. {
  29. memset (tag,0,sizeof (flvtag_t));
  30. }
  31. void flvtag_free (flvtag_t* tag)
  32. {
  33. if (tag->data) {
  34. free (tag->data);
  35. }
  36. flvtag_init (tag);
  37. }
  38. int flvtag_reserve (flvtag_t* tag, uint32_t size)
  39. {
  40. size += FLV_TAG_HEADER_SIZE + FLV_TAG_FOOTER_SIZE;
  41. if (size > tag->aloc) {
  42. tag->data = realloc (tag->data,size);
  43. tag->aloc = size;
  44. }
  45. return 1;
  46. }
  47. FILE* flv_open_read (const char* flv)
  48. {
  49. if (0 == flv || 0 == strcmp ("-",flv)) {
  50. return stdin;
  51. }
  52. return fopen (flv,"rb");
  53. }
  54. FILE* flv_open_write (const char* flv)
  55. {
  56. if (0 == flv || 0 == strcmp ("-",flv)) {
  57. return stdout;
  58. }
  59. return fopen (flv,"wb");
  60. }
  61. FILE* flv_close (FILE* flv)
  62. {
  63. fclose (flv);
  64. return 0;
  65. }
  66. int flv_read_header (FILE* flv, int* has_audio, int* has_video)
  67. {
  68. uint8_t h[FLV_HEADER_SIZE];
  69. if (FLV_HEADER_SIZE != fread (&h[0],1,FLV_HEADER_SIZE,flv)) {
  70. return 0;
  71. }
  72. if ('F' != h[0] || 'L' != h[1] || 'V' != h[2]) {
  73. return 0;
  74. }
  75. (*has_audio) = h[4]&0x04;
  76. (*has_video) = h[4]&0x01;
  77. return 1;
  78. }
  79. int flv_write_header (FILE* flv, int has_audio, int has_video)
  80. {
  81. uint8_t h[FLV_HEADER_SIZE] = {'F', 'L', 'V', 1, (has_audio?0x04:0x00) | (has_video?0x01:0x00), 0, 0, 0, 9, 0, 0, 0, 0 };
  82. return FLV_HEADER_SIZE == fwrite (&h[0],1,FLV_HEADER_SIZE,flv);
  83. }
  84. int flv_read_tag (FILE* flv, flvtag_t* tag)
  85. {
  86. uint32_t size;
  87. uint8_t h[FLV_TAG_HEADER_SIZE];
  88. if (FLV_TAG_HEADER_SIZE != fread (&h[0],1,FLV_TAG_HEADER_SIZE,flv)) {
  89. return 0;
  90. }
  91. size = ( (h[1]<<16) | (h[2]<<8) |h[3]);
  92. flvtag_reserve (tag, size);
  93. // copy header to buffer
  94. memcpy (tag->data,&h[0],FLV_TAG_HEADER_SIZE);
  95. if (size+FLV_TAG_FOOTER_SIZE != fread (&tag->data[FLV_TAG_HEADER_SIZE],1,size+FLV_TAG_FOOTER_SIZE,flv)) {
  96. return 0;
  97. }
  98. return 1;
  99. }
  100. int flv_write_tag (FILE* flv, flvtag_t* tag)
  101. {
  102. size_t size = flvtag_raw_size (tag);
  103. return size == fwrite (flvtag_raw_data (tag),1,size,flv);
  104. }
  105. ////////////////////////////////////////////////////////////////////////////////
  106. size_t flvtag_header_size (flvtag_t* tag)
  107. {
  108. switch (flvtag_type (tag)) {
  109. case flvtag_type_audio:
  110. return FLV_TAG_HEADER_SIZE + (flvtag_soundformat_aac != flvtag_soundformat (tag) ? 1 : 2);
  111. case flvtag_type_video:
  112. // CommandFrame does not have a compositionTime
  113. return FLV_TAG_HEADER_SIZE + (flvtag_codecid_avc != flvtag_codecid (tag) ? 1 : (flvtag_frametype_commandframe != flvtag_frametype (tag) ? 5 : 2));
  114. default:
  115. return FLV_TAG_HEADER_SIZE;
  116. }
  117. }
  118. size_t flvtag_payload_size (flvtag_t* tag)
  119. {
  120. return FLV_TAG_HEADER_SIZE + flvtag_size (tag) - flvtag_header_size (tag);
  121. }
  122. uint8_t* flvtag_payload_data (flvtag_t* tag)
  123. {
  124. size_t payload_offset = flvtag_header_size (tag);
  125. return &tag->data[payload_offset];
  126. }
  127. ////////////////////////////////////////////////////////////////////////////////
  128. int flvtag_updatesize (flvtag_t* tag, uint32_t size)
  129. {
  130. tag->data[1] = size>>16; // DataSize
  131. tag->data[2] = size>>8; // DataSize
  132. tag->data[3] = size>>0; // DataSize
  133. size += 11;
  134. tag->data[size+0] = size>>24; // PrevTagSize
  135. tag->data[size+1] = size>>16; // PrevTagSize
  136. tag->data[size+2] = size>>8; // PrevTagSize
  137. tag->data[size+3] = size>>0; // PrevTagSize
  138. return 1;
  139. }
  140. #define FLVTAG_PREALOC 2048
  141. int flvtag_initavc (flvtag_t* tag, uint32_t dts, int32_t cts, flvtag_frametype_t type)
  142. {
  143. flvtag_init (tag);
  144. flvtag_reserve (tag,5+FLVTAG_PREALOC);
  145. tag->data[0] = flvtag_type_video;
  146. tag->data[4] = dts>>16;
  147. tag->data[5] = dts>>8;
  148. tag->data[6] = dts>>0;
  149. tag->data[7] = dts>>24;
  150. tag->data[8] = 0; // StreamID
  151. tag->data[9] = 0; // StreamID
  152. tag->data[10] = 0; // StreamID
  153. // VideoTagHeader
  154. tag->data[11] = ( (type<<4) %0xF0) |0x07; // CodecId
  155. tag->data[12] = 0x01; // AVC NALU
  156. tag->data[13] = cts>>16;
  157. tag->data[14] = cts>>8;
  158. tag->data[15] = cts>>0;
  159. flvtag_updatesize (tag,5);
  160. return 1;
  161. }
  162. int flvtag_initamf (flvtag_t* tag, uint32_t dts)
  163. {
  164. flvtag_init (tag);
  165. flvtag_reserve (tag,FLVTAG_PREALOC);
  166. tag->data[0] = flvtag_type_scriptdata;
  167. tag->data[4] = dts>>16;
  168. tag->data[5] = dts>>8;
  169. tag->data[6] = dts>>0;
  170. tag->data[7] = dts>>24;
  171. tag->data[8] = 0; // StreamID
  172. tag->data[9] = 0; // StreamID
  173. tag->data[10] = 0; // StreamID
  174. flvtag_updatesize (tag,0);
  175. return 1;
  176. }
  177. // shamelessly taken from libtomcrypt, an public domain project
  178. static void base64_encode (const unsigned char* in, unsigned long inlen, unsigned char* out, unsigned long* outlen)
  179. {
  180. static const char* codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  181. unsigned long i, len2, leven;
  182. unsigned char* p;
  183. /* valid output size ? */
  184. len2 = 4 * ( (inlen + 2) / 3);
  185. if (*outlen < len2 + 1) {
  186. *outlen = len2 + 1;
  187. fprintf (stderr,"\n\nHERE\n\n");
  188. return;
  189. }
  190. p = out;
  191. leven = 3* (inlen / 3);
  192. for (i = 0; i < leven; i += 3) {
  193. *p++ = codes[ (in[0] >> 2) & 0x3F];
  194. *p++ = codes[ ( ( (in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F];
  195. *p++ = codes[ ( ( (in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F];
  196. *p++ = codes[in[2] & 0x3F];
  197. in += 3;
  198. }
  199. if (i < inlen) {
  200. unsigned a = in[0];
  201. unsigned b = (i+1 < inlen) ? in[1] : 0;
  202. *p++ = codes[ (a >> 2) & 0x3F];
  203. *p++ = codes[ ( ( (a & 3) << 4) + (b >> 4)) & 0x3F];
  204. *p++ = (i+1 < inlen) ? codes[ ( ( (b & 0xf) << 2)) & 0x3F] : '=';
  205. *p++ = '=';
  206. }
  207. /* return ok */
  208. *outlen = p - out;
  209. }
  210. const char onCaptionInfo708[] = { 0x02,0x00,0x0D, 'o','n','C','a','p','t','i','o','n','I','n','f','o',
  211. 0x08, 0x00, 0x00, 0x00, 0x02,
  212. 0x00, 0x04, 't','y','p','e',
  213. 0x02, 0x00, 0x03, '7','0','8',
  214. 0x00, 0x04, 'd','a','t','a',
  215. 0x02, 0x00,0x00
  216. };
  217. int flvtag_amfcaption_708 (flvtag_t* tag, uint32_t timestamp, sei_message_t* msg)
  218. {
  219. flvtag_initamf (tag,timestamp);
  220. unsigned long size = 1 + (4 * ( (sei_message_size (msg) + 2) / 3));
  221. flvtag_reserve (tag, sizeof (onCaptionInfo708) + size + 3);
  222. memcpy (flvtag_payload_data (tag),onCaptionInfo708,sizeof (onCaptionInfo708));
  223. uint8_t* data = flvtag_payload_data (tag) + sizeof (onCaptionInfo708);
  224. base64_encode (sei_message_data (msg), sei_message_size (msg), data, &size);
  225. // Update the size of the base64 string
  226. data[-2] = size >> 8;
  227. data[-1] = size >> 0;
  228. // write the last array element
  229. data[size+0] = 0x00;
  230. data[size+1] = 0x00;
  231. data[size+2] = 0x09;
  232. flvtag_updatesize (tag, sizeof (onCaptionInfo708) + size + 3);
  233. return 1;
  234. }
  235. const char onCaptionInfoUTF8[] = { 0x02,0x00,0x0D, 'o','n','C','a','p','t','i','o','n','I','n','f','o',
  236. 0x08, 0x00, 0x00, 0x00, 0x02,
  237. 0x00, 0x04, 't','y','p','e',
  238. 0x02, 0x00, 0x04, 'U','T','F','8',
  239. 0x00, 0x04, 'd','a','t','a',
  240. 0x02, 0x00,0x00
  241. };
  242. #define MAX_AMF_STRING 65636
  243. int flvtag_amfcaption_utf8 (flvtag_t* tag, uint32_t timestamp, const utf8_char_t* text)
  244. {
  245. flvtag_initamf (tag,timestamp);
  246. unsigned long size = strlen (text);
  247. if (MAX_AMF_STRING < size) {
  248. size = MAX_AMF_STRING;
  249. }
  250. flvtag_reserve (tag, sizeof (onCaptionInfoUTF8) + size + 3);
  251. memcpy (flvtag_payload_data (tag),onCaptionInfoUTF8,sizeof (onCaptionInfoUTF8));
  252. uint8_t* data = flvtag_payload_data (tag) + sizeof (onCaptionInfo708);
  253. memcpy (data,text,size);
  254. // Update the size of the string
  255. data[-2] = size >> 8;
  256. data[-1] = size >> 0;
  257. // write the last array element
  258. data[size+0] = 0x00;
  259. data[size+1] = 0x00;
  260. data[size+2] = 0x09;
  261. flvtag_updatesize (tag, sizeof (onCaptionInfoUTF8) + size + 3);
  262. return 1;
  263. }
  264. #define LENGTH_SIZE 4
  265. int flvtag_avcwritenal (flvtag_t* tag, uint8_t* data, size_t size)
  266. {
  267. uint32_t flvsize = flvtag_size (tag);
  268. flvtag_reserve (tag,flvsize+LENGTH_SIZE+size);
  269. uint8_t* payload = tag->data + FLV_TAG_HEADER_SIZE + flvsize;
  270. payload[0] = size>>24; // nalu size
  271. payload[1] = size>>16;
  272. payload[2] = size>>8;
  273. payload[3] = size>>0;
  274. memcpy (&payload[LENGTH_SIZE],data,size);
  275. flvtag_updatesize (tag,flvsize+LENGTH_SIZE+size);
  276. return 1;
  277. }
  278. int flvtag_addcaption (flvtag_t* tag, const utf8_char_t* text)
  279. {
  280. if (flvtag_avcpackettype_nalu != flvtag_avcpackettype (tag)) {
  281. return 0;
  282. }
  283. sei_t sei;
  284. caption_frame_t frame;
  285. sei_init (&sei);
  286. caption_frame_init (&frame);
  287. caption_frame_from_text (&frame, text);
  288. sei_from_caption_frame (&sei, &frame);
  289. uint8_t* sei_data = malloc (sei_render_size (&sei));
  290. size_t sei_size = sei_render (&sei, sei_data);
  291. // rewrite tag
  292. flvtag_t new_tag;
  293. flvtag_initavc (&new_tag, flvtag_dts (tag), flvtag_cts (tag), flvtag_frametype (tag));
  294. uint8_t* data = flvtag_payload_data (tag);
  295. ssize_t size = flvtag_payload_size (tag);
  296. while (0<size) {
  297. uint8_t* nalu_data = &data[LENGTH_SIZE];
  298. uint8_t nalu_type = nalu_data[0]&0x1F;
  299. uint32_t nalu_size = (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | data[3];
  300. data += LENGTH_SIZE + nalu_size;
  301. size -= LENGTH_SIZE + nalu_size;
  302. if (0 < sei_size && 7 != nalu_type && 8 != nalu_type && 9 != nalu_type ) {
  303. // fprintf (stderr,"Wrote SEI %d '%d'\n\n", sei_size, sei_data[3]);
  304. flvtag_avcwritenal (&new_tag,sei_data,sei_size);
  305. sei_size = 0;
  306. }
  307. flvtag_avcwritenal (&new_tag,nalu_data,nalu_size);
  308. }
  309. // On the off chance we have an empty frame,
  310. // We still wish to append the sei
  311. if (0<sei_size) {
  312. // fprintf (stderr,"Wrote SEI %d\n\n", sei_size);
  313. flvtag_avcwritenal (&new_tag,sei_data,sei_size);
  314. sei_size = 0;
  315. }
  316. if (sei_data) {
  317. free (sei_data);
  318. }
  319. free (tag->data);
  320. sei_free (&sei);
  321. tag->data = new_tag.data;
  322. tag->aloc = new_tag.aloc;
  323. return 1;
  324. }