2
0

srs_flv_injecter.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /**
  2. * The MIT License (MIT)
  3. *
  4. * Copyright (c) 2013-2018 Winlin
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  7. * this software and associated documentation files (the "Software"), to deal in
  8. * the Software without restriction, including without limitation the rights to
  9. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10. * the Software, and to permit persons to whom the Software is furnished to do so,
  11. * subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * 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, FITNESS
  18. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <fcntl.h>
  30. #include "../../objs/include/srs_librtmp.h"
  31. #define ERROR_INJECTED 10000
  32. int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc);
  33. int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0_t* pfilepositions, int64_t* pmetadata_end_offset);
  34. int do_inject_flv(srs_flv_t ic, srs_flv_t oc, srs_amf0_t amf0_name, srs_amf0_t amf0_data, srs_amf0_t filepositions, int64_t metadata_end_offset);
  35. int main(int argc, char** argv)
  36. {
  37. int ret = 0;
  38. // user options.
  39. char* in_flv_file;
  40. char* out_flv_file;
  41. // flv handler
  42. srs_flv_t ic = NULL;
  43. srs_flv_t oc = NULL;
  44. // temp variables.
  45. int tmp_file_size = 0;
  46. char* tmp_file;
  47. printf("inject flv file keyframes to metadata.\n");
  48. printf("srs(ossrs) client librtmp library.\n");
  49. printf("version: %d.%d.%d\n", srs_version_major(), srs_version_minor(), srs_version_revision());
  50. if (argc <= 2) {
  51. printf("inject flv file keyframes to metadata\n"
  52. "Usage: %s in_flv_file out_flv_file\n"
  53. " in_flv_file input flv file to inject.\n"
  54. " out_flv_file the inject output file, can be in_flv_file.\n"
  55. "For example:\n"
  56. " %s doc/source.200kbps.768x320.flv injected.flv\n"
  57. " %s ../../doc/source.200kbps.768x320.flv injected.flv\n",
  58. argv[0], argv[0], argv[0]);
  59. exit(-1);
  60. }
  61. in_flv_file = argv[1];
  62. out_flv_file = argv[2];
  63. tmp_file_size = strlen(out_flv_file) + strlen(".tmp") + 1;
  64. tmp_file = (char*)malloc(tmp_file_size);
  65. snprintf(tmp_file, tmp_file_size, "%s.tmp", out_flv_file);
  66. srs_human_trace("input: %s", in_flv_file);
  67. srs_human_trace("output: %s", out_flv_file);
  68. srs_human_trace("tmp_file: %s", tmp_file);
  69. ret = process(in_flv_file, tmp_file, &ic, &oc);
  70. srs_flv_close(ic);
  71. srs_flv_close(oc);
  72. if (ret != 0) {
  73. unlink(tmp_file);
  74. if (ret == ERROR_INJECTED) {
  75. ret = 0;
  76. srs_human_trace("file already injected.");
  77. } else {
  78. srs_human_trace("error, remove tmp file.");
  79. }
  80. } else {
  81. rename(tmp_file, out_flv_file);
  82. srs_human_trace("completed, rename to %s", out_flv_file);
  83. }
  84. free(tmp_file);
  85. return ret;
  86. }
  87. int process(const char* in_flv_file, const char* out_flv_file, srs_flv_t* pic, srs_flv_t* poc)
  88. {
  89. int ret = 0;
  90. srs_flv_t ic;
  91. srs_flv_t oc;
  92. // to adjust metadata.
  93. // the ic metadata end offset, the next tag start offset.
  94. // all oc metadata must adjust according to:
  95. // adjust = new_metadata_end_offset - metadata_end_offset
  96. int64_t metadata_end_offset = 0;
  97. // metadata
  98. srs_amf0_t amf0_name = NULL;
  99. srs_amf0_t amf0_data = NULL;
  100. srs_amf0_t filepositions = NULL;
  101. if ((ic = srs_flv_open_read(in_flv_file)) == NULL) {
  102. ret = 2;
  103. srs_human_trace("open input flv file failed. ret=%d", ret);
  104. return ret;
  105. }
  106. *pic = ic;
  107. if ((oc = srs_flv_open_write(out_flv_file)) == NULL) {
  108. ret = 2;
  109. srs_human_trace("open output flv file failed. ret=%d", ret);
  110. return ret;
  111. }
  112. *poc = oc;
  113. /**
  114. * we use two roundtrip to avoid the paddings of metadata,
  115. * to support large keyframes videos without padding fields.
  116. */
  117. // build keyframes offset to metadata.
  118. if ((ret = build_keyframes(ic, &amf0_name, &amf0_data, &filepositions, &metadata_end_offset)) != 0) {
  119. return ret;
  120. }
  121. // inject the metadata to oc.
  122. if ((ret = do_inject_flv(ic, oc, amf0_name, amf0_data, filepositions, metadata_end_offset)) != 0) {
  123. return ret;
  124. }
  125. // TODO: FIXME: mem leak when error.
  126. srs_amf0_free(amf0_name);
  127. srs_amf0_free(amf0_data);
  128. return ret;
  129. }
  130. int parse_metadata(char* data, int size, srs_amf0_t* pname, srs_amf0_t* pdata)
  131. {
  132. int ret = 0;
  133. int nparsed = 0;
  134. *pname = srs_amf0_parse(data, size, &nparsed);
  135. if (*pname == NULL || nparsed >= size) {
  136. srs_human_trace("invalid amf0 name data.");
  137. return -1;
  138. }
  139. *pdata = srs_amf0_parse(data + nparsed, size - nparsed, &nparsed);
  140. if (*pdata == NULL || nparsed > size) {
  141. srs_human_trace("invalid amf0 value data");
  142. return -1;
  143. }
  144. return ret;
  145. }
  146. int build_keyframes(srs_flv_t ic, srs_amf0_t *pname, srs_amf0_t* pdata, srs_amf0_t* pfilepositions, int64_t* pmetadata_end_offset)
  147. {
  148. int ret = 0;
  149. // flv header
  150. char header[13];
  151. // packet data
  152. char type;
  153. uint32_t timestamp = 0;
  154. char* data = NULL;
  155. int32_t size;
  156. int64_t offset = 0;
  157. // metadata
  158. srs_amf0_t amf0_name = NULL;
  159. srs_amf0_t amf0_data = NULL;
  160. srs_amf0_t keyframes = NULL;
  161. srs_amf0_t filepositions = NULL;
  162. srs_amf0_t times = NULL;
  163. // reset to generate metadata
  164. srs_flv_lseek(ic, 0);
  165. if ((ret = srs_flv_read_header(ic, header)) != 0) {
  166. return ret;
  167. }
  168. srs_human_trace("build keyframe infos from flv");
  169. for (;;) {
  170. offset = srs_flv_tellg(ic);
  171. // tag header
  172. if ((ret = srs_flv_read_tag_header(ic, &type, &size, &timestamp)) != 0) {
  173. if (srs_flv_is_eof(ret)) {
  174. srs_human_trace("parse completed.");
  175. return 0;
  176. }
  177. srs_human_trace("flv get packet failed. ret=%d", ret);
  178. return ret;
  179. }
  180. if (size <= 0) {
  181. srs_human_trace("invalid size=%d", size);
  182. return ret;
  183. }
  184. // TODO: FIXME: mem leak when error.
  185. data = (char*)malloc(size);
  186. if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) {
  187. return ret;
  188. }
  189. // data tag
  190. if (type == SRS_RTMP_TYPE_VIDEO) {
  191. if (!srs_flv_is_sequence_header(data, size) && srs_flv_is_keyframe(data, size)) {
  192. srs_amf0_strict_array_append(filepositions, srs_amf0_create_number(offset));
  193. srs_amf0_strict_array_append(times, srs_amf0_create_number(((double)timestamp)/ 1000));
  194. }
  195. } else if (type == SRS_RTMP_TYPE_SCRIPT) {
  196. *pmetadata_end_offset = srs_flv_tellg(ic);
  197. if ((ret = parse_metadata(data, size, &amf0_name, &amf0_data)) != 0) {
  198. return ret;
  199. }
  200. *pname = amf0_name;
  201. *pdata = amf0_data;
  202. if (srs_amf0_is_object(amf0_data)) {
  203. keyframes = srs_amf0_object_property(amf0_data, "keyframes");
  204. if (keyframes == NULL) {
  205. keyframes = srs_amf0_create_object();
  206. srs_amf0_object_property_set(amf0_data, "keyframes", keyframes);
  207. }
  208. // always clear the old keyframes.
  209. srs_amf0_object_clear(keyframes);
  210. *pfilepositions = filepositions = srs_amf0_create_strict_array();
  211. srs_amf0_object_property_set(keyframes, "filepositions", filepositions);
  212. times = srs_amf0_create_strict_array();
  213. srs_amf0_object_property_set(keyframes, "times", times);
  214. } else if (srs_amf0_is_ecma_array(amf0_data)) {
  215. keyframes = srs_amf0_ecma_array_property(amf0_data, "keyframes");
  216. if (keyframes == NULL) {
  217. keyframes = srs_amf0_create_object();
  218. srs_amf0_ecma_array_property_set(amf0_data, "keyframes", keyframes);
  219. }
  220. // always clear the old keyframes.
  221. srs_amf0_object_clear(keyframes);
  222. *pfilepositions = filepositions = srs_amf0_create_strict_array();
  223. srs_amf0_object_property_set(keyframes, "filepositions", filepositions);
  224. times = srs_amf0_create_strict_array();
  225. srs_amf0_object_property_set(keyframes, "times", times);
  226. }
  227. }
  228. free(data);
  229. }
  230. return ret;
  231. }
  232. int do_inject_flv(srs_flv_t ic, srs_flv_t oc, srs_amf0_t amf0_name, srs_amf0_t amf0_data, srs_amf0_t filepositions, int64_t metadata_end_offset)
  233. {
  234. int ret = 0;
  235. // flv header
  236. char header[13];
  237. // packet data
  238. char type;
  239. uint32_t timestamp = 0;
  240. char* data = NULL;
  241. int32_t size;
  242. // metadata
  243. srs_amf0_t fileposition = NULL;
  244. int amf0_name_size = 0;
  245. int i;
  246. // the metadata end offset, the next tag start offset.
  247. int64_t new_metadata_end_offset = 0;
  248. int offset_adjust = 0;
  249. // reset to write injected file
  250. srs_flv_lseek(ic, 0);
  251. if ((ret = srs_flv_read_header(ic, header)) != 0) {
  252. return ret;
  253. }
  254. if ((ret = srs_flv_write_header(oc, header)) != 0) {
  255. return ret;
  256. }
  257. // write metadata
  258. if (amf0_name != NULL && amf0_data != NULL) {
  259. amf0_name_size = srs_amf0_size(amf0_name);
  260. size = amf0_name_size + srs_amf0_size(amf0_data);
  261. // adjust all offset of keyframes.
  262. new_metadata_end_offset = srs_flv_tellg(oc) + srs_flv_size_tag(size);
  263. // the adjust is new offset sub the old offset of metadata end.
  264. offset_adjust = new_metadata_end_offset - metadata_end_offset;
  265. for (i = 0; i < srs_amf0_strict_array_property_count(filepositions); i++) {
  266. fileposition = srs_amf0_strict_array_property_at(filepositions, i);
  267. srs_amf0_set_number(fileposition, srs_amf0_to_number(fileposition) + offset_adjust);
  268. }
  269. data = (char*)malloc(size);
  270. memset(data, 0, size);
  271. if ((ret = srs_amf0_serialize(amf0_name, data, amf0_name_size)) != 0) {
  272. return ret;
  273. }
  274. if ((ret = srs_amf0_serialize(amf0_data, data + amf0_name_size, size - amf0_name_size)) != 0) {
  275. return ret;
  276. }
  277. if ((ret = srs_flv_write_tag(oc, SRS_RTMP_TYPE_SCRIPT, 0, data, size)) != 0) {
  278. return ret;
  279. }
  280. free(data);
  281. }
  282. srs_human_trace("build keyframe infos from flv");
  283. for (;;) {
  284. // tag header
  285. if ((ret = srs_flv_read_tag_header(ic, &type, &size, &timestamp)) != 0) {
  286. if (srs_flv_is_eof(ret)) {
  287. srs_human_trace("parse completed.");
  288. return 0;
  289. }
  290. srs_human_trace("flv get packet failed. ret=%d", ret);
  291. return ret;
  292. }
  293. if (size <= 0) {
  294. srs_human_trace("invalid size=%d", size);
  295. break;
  296. }
  297. // TODO: FIXME: mem leak when error.
  298. data = (char*)malloc(size);
  299. if ((ret = srs_flv_read_tag_data(ic, data, size)) != 0) {
  300. return ret;
  301. }
  302. // data tag
  303. if (type == SRS_RTMP_TYPE_SCRIPT) {
  304. continue;
  305. }
  306. // copy
  307. if ((ret = srs_flv_write_tag(oc, type, timestamp, data, size)) != 0) {
  308. return ret;
  309. }
  310. free(data);
  311. }
  312. return ret;
  313. }