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.

254 lines
7.1 KiB

12 years ago
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <assert.h>
  4. #include <stdint.h>
  5. #define FLVF_HEADER 1
  6. #define FLVF_SCRIPT 2
  7. struct flvhdr
  8. {
  9. char fh_magic[3];
  10. char fh_version;
  11. char fh_flags;
  12. char fh_hlen[4];
  13. char fh_pads[4];
  14. }__attribute__((packed));
  15. struct taghdr
  16. {
  17. uint8_t th_type;
  18. uint8_t th_dlen[3];
  19. uint8_t th_tstamp[3];
  20. uint8_t th_xstamp;
  21. uint8_t th_streamid[3];
  22. }__attribute__((packed));
  23. struct flvcombine
  24. {
  25. FILE * fc_file;
  26. uint32_t fc_flags;
  27. uint32_t fc_timestamp;
  28. uint32_t fc_filesize;
  29. double fc_duration;
  30. int fc_filesize_offset;
  31. int fc_duration_offset;
  32. };
  33. /* duration, filesize */
  34. uint32_t buftoint(const void *buf, size_t len)
  35. {
  36. uint32_t bufint = 0;
  37. const uint8_t *pval = (const uint8_t *)buf;
  38. while (len-- > 0)
  39. bufint = (bufint << 8) + *pval++;
  40. return bufint;
  41. }
  42. int dd_copy(FILE * dst_fp, FILE * src_fp, size_t dlen)
  43. {
  44. size_t len;
  45. char buf[64 * 1024];
  46. while (dlen > 0 && !feof(src_fp)) {
  47. len = fread(buf, 1, dlen < sizeof(buf)? dlen: sizeof(buf), src_fp);
  48. if (fwrite(buf, 1, len, dst_fp) != len)
  49. break;
  50. dlen -= len;
  51. }
  52. return dlen;
  53. }
  54. void adjtimestamp(struct taghdr *header, uint32_t stampbase)
  55. {
  56. uint32_t netval = 0;
  57. uint32_t adjtime = stampbase;
  58. adjtime += buftoint(&header->th_tstamp, sizeof(header->th_tstamp));
  59. adjtime += (header->th_xstamp << 24);
  60. header->th_xstamp = (adjtime >> 24);
  61. header->th_tstamp[0] = (adjtime >> 16);
  62. header->th_tstamp[1] = (adjtime >> 8);
  63. header->th_tstamp[2] = (adjtime >> 0);
  64. }
  65. void update_metainfo(struct flvcombine *combine, FILE *fp, size_t dlen)
  66. {
  67. int i;
  68. size_t len;
  69. char *pmem = NULL;
  70. char buf[256 * 1024];
  71. double duration = 0.0;
  72. uint8_t duration_bytes[8];
  73. printf("dlen: %d\n", dlen);
  74. assert (dlen < (256 * 1024));
  75. len = fread(buf, 1, dlen < sizeof(buf)? dlen: sizeof(buf), fp);
  76. if (len == 0)
  77. return;
  78. pmem = (char *)memmem(buf, len, "duration", 8);
  79. if (pmem == NULL || pmem + 17l - buf > len)
  80. return;
  81. memcpy(&duration_bytes, pmem + 9, 8);
  82. for (i = 0; i < 4; i ++) {
  83. uint8_t tmp = duration_bytes[i];
  84. duration_bytes[i] = duration_bytes[7 - i];
  85. duration_bytes[7 - i] = tmp;
  86. }
  87. memcpy(&duration, &duration_bytes, 8);
  88. combine->fc_duration += duration;
  89. if (combine->fc_flags & FLVF_SCRIPT)
  90. return;
  91. combine->fc_duration_offset =
  92. combine->fc_filesize + (pmem + 9l - buf) + sizeof(struct taghdr);
  93. pmem = (char *)memmem(buf, len, "filesize", 8);
  94. if (pmem == NULL || pmem + 17l - buf > len)
  95. return;
  96. combine->fc_filesize_offset =
  97. combine->fc_filesize + (pmem + 9l - buf) + sizeof(struct taghdr);
  98. }
  99. int addflv(struct flvcombine *combine, const char *path)
  100. {
  101. int error = 0;
  102. FILE *fp, *fout;
  103. char magic[4];
  104. long savepos;
  105. size_t len, dlen, flags;
  106. struct flvhdr header;
  107. struct taghdr *last;
  108. struct taghdr tagvideo;
  109. struct taghdr tagaudio;
  110. struct taghdr tagheader;
  111. fp = fopen(path, "rb");
  112. fout = combine->fc_file;
  113. if (fp == NULL || fout == NULL)
  114. return 0;
  115. last = NULL;
  116. memset(magic, 0, sizeof(magic));
  117. memset(&tagvideo, 0, sizeof(tagvideo));
  118. memset(&tagaudio, 0, sizeof(tagaudio));
  119. if ( !fread(&header, sizeof(header), 1, fp) )
  120. goto fail;
  121. memcpy(magic, header.fh_magic, 3);
  122. if ( strcmp("FLV", magic) )
  123. goto fail;
  124. if ((combine->fc_flags & FLVF_HEADER) == 0) {
  125. fwrite(&header, sizeof(header), 1, fout);
  126. combine->fc_filesize += sizeof(header);
  127. combine->fc_flags |= FLVF_HEADER;
  128. }
  129. printf("magic: %s\n", magic);
  130. printf("flags: 0x%02x\n", header.fh_flags);
  131. printf("version: 0x%02x\n", header.fh_version);
  132. printf("header len: %d\n", buftoint(header.fh_hlen, sizeof(header.fh_hlen)));
  133. while (feof(fp) == 0) {
  134. if ( !fread(&tagheader, sizeof(tagheader), 1, fp) )
  135. goto fail;
  136. dlen = buftoint(tagheader.th_dlen, sizeof(tagheader.th_dlen));
  137. switch (tagheader.th_type)
  138. {
  139. case 0x09:
  140. adjtimestamp(&tagheader, combine->fc_timestamp);
  141. tagvideo = tagheader;
  142. last = &tagvideo;
  143. break;
  144. case 0x08:
  145. adjtimestamp(&tagheader, combine->fc_timestamp);
  146. tagaudio = tagheader;
  147. last = &tagaudio;
  148. break;
  149. default:
  150. flags = combine->fc_flags;
  151. savepos = ftell(fp);
  152. if (savepos == -1)
  153. goto fail;
  154. savepos = (flags & FLVF_SCRIPT)? (savepos + dlen + 4): savepos;
  155. update_metainfo(combine, fp, dlen);
  156. combine->fc_flags |= FLVF_SCRIPT;
  157. if ( fseek(fp, savepos, SEEK_SET) )
  158. goto fail;
  159. if (flags & FLVF_SCRIPT)
  160. continue;
  161. break;
  162. }
  163. fwrite(&tagheader, sizeof(tagheader), 1, fout);
  164. combine->fc_filesize += sizeof(tagheader);
  165. combine->fc_filesize += (dlen + 4);
  166. if ( dd_copy(fout, fp, dlen + 4)) {
  167. error = -__LINE__;
  168. break;
  169. }
  170. }
  171. fail:
  172. fclose(fp);
  173. if (last == &tagvideo || last == &tagaudio) {
  174. combine->fc_timestamp = buftoint(last->th_tstamp, sizeof(last->th_tstamp));
  175. combine->fc_timestamp |= (last->th_xstamp << 24);
  176. printf("time stamp: %d\n", combine->fc_timestamp);
  177. }
  178. return 0;
  179. }
  180. void fixedflv(struct flvcombine *context)
  181. {
  182. int i;
  183. double dblval = 0.0;
  184. uint8_t dblbytes[8];
  185. FILE *fout = context->fc_file;
  186. if (context->fc_filesize_offset > 0) {
  187. if ( fseek(fout, context->fc_filesize_offset, SEEK_SET) )
  188. return;
  189. dblval = context->fc_filesize;
  190. memcpy(dblbytes, &dblval, 8);
  191. for (i = 0; i < 4; i ++) {
  192. uint8_t tmp = dblbytes[i];
  193. dblbytes[i] = dblbytes[7 - i];
  194. dblbytes[7 - i] = tmp;
  195. }
  196. fwrite(dblbytes, 8, 1, fout);
  197. }
  198. if (context->fc_duration_offset > 0) {
  199. if ( fseek(fout, context->fc_duration_offset, SEEK_SET) )
  200. return;
  201. dblval = context->fc_duration;
  202. memcpy(dblbytes, &dblval, 8);
  203. for (i = 0; i < 4; i ++) {
  204. uint8_t tmp = dblbytes[i];
  205. dblbytes[i] = dblbytes[7 - i];
  206. dblbytes[7 - i] = tmp;
  207. }
  208. fwrite(dblbytes, 8, 1, fout);
  209. }
  210. }
  211. int main(int argc, char *argv[])
  212. {
  213. int i;
  214. struct flvcombine context;
  215. memset(&context, 0, sizeof(context));
  216. context.fc_file = fopen("out.flv", "wb");
  217. if (context.fc_file == NULL)
  218. return -1;
  219. context.fc_duration = 0;
  220. for (i = 1; i < argc; i++)
  221. addflv(&context, argv[i]);
  222. fixedflv(&context);
  223. fclose(context.fc_file);
  224. printf("seconds: %d\n", context.fc_timestamp);
  225. return 0;
  226. }