PageRenderTime 105ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/src/info.c

https://code.google.com/
C | 712 lines | 521 code | 78 blank | 113 comment | 175 complexity | 43237cc5aa038880060d362a291ce80d MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. $Id: info.c 231 2011-06-27 13:46:19Z marc.noirot $
  3. FLV Metadata updater
  4. Copyright (C) 2007-2012 Marc Noirot <marc.noirot AT gmail.com>
  5. This file is part of FLVMeta.
  6. FLVMeta is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. FLVMeta is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with FLVMeta; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "info.h"
  19. #include "avc.h"
  20. #include <string.h>
  21. /*
  22. compute Sorensen H.263 video size
  23. */
  24. static int compute_h263_size(flv_stream * flv_in, flv_info * info, uint32 body_length) {
  25. byte header[9];
  26. uint24_be psc_be;
  27. uint32 psc;
  28. /* make sure we have enough bytes to read in the current tag */
  29. if (body_length >= 9) {
  30. if (flv_read_tag_body(flv_in, header, 9) < 9) {
  31. return FLV_ERROR_EOF;
  32. }
  33. psc_be.b[0] = header[0];
  34. psc_be.b[1] = header[1];
  35. psc_be.b[2] = header[2];
  36. psc = uint24_be_to_uint32(psc_be) >> 7;
  37. if (psc == 1) {
  38. uint32 psize = ((header[3] & 0x03) << 1) + ((header[4] >> 7) & 0x01);
  39. switch (psize) {
  40. case 0:
  41. info->video_width = ((header[4] & 0x7f) << 1) + ((header[5] >> 7) & 0x01);
  42. info->video_height = ((header[5] & 0x7f) << 1) + ((header[6] >> 7) & 0x01);
  43. break;
  44. case 1:
  45. info->video_width = ((header[4] & 0x7f) << 9) + (header[5] << 1) + ((header[6] >> 7) & 0x01);
  46. info->video_height = ((header[6] & 0x7f) << 9) + (header[7] << 1) + ((header[8] >> 7) & 0x01);
  47. break;
  48. case 2:
  49. info->video_width = 352;
  50. info->video_height = 288;
  51. break;
  52. case 3:
  53. info->video_width = 176;
  54. info->video_height = 144;
  55. break;
  56. case 4:
  57. info->video_width = 128;
  58. info->video_height = 96;
  59. break;
  60. case 5:
  61. info->video_width = 320;
  62. info->video_height = 240;
  63. break;
  64. case 6:
  65. info->video_width = 160;
  66. info->video_height = 120;
  67. break;
  68. default:
  69. break;
  70. }
  71. }
  72. }
  73. return FLV_OK;
  74. }
  75. /*
  76. compute Screen video size
  77. */
  78. static int compute_screen_size(flv_stream * flv_in, flv_info * info, uint32 body_length) {
  79. byte header[4];
  80. /* make sure we have enough bytes to read in the current tag */
  81. if (body_length >= 4) {
  82. if (flv_read_tag_body(flv_in, header, 4) < 4) {
  83. return FLV_ERROR_EOF;
  84. }
  85. info->video_width = ((header[0] & 0x0f) << 8) + header[1];
  86. info->video_height = ((header[2] & 0x0f) << 8) + header[3];
  87. }
  88. return FLV_OK;
  89. }
  90. /*
  91. compute On2 VP6 video size
  92. */
  93. static int compute_vp6_size(flv_stream * flv_in, flv_info * info, uint32 body_length) {
  94. byte header[7], offset;
  95. /* make sure we have enough bytes to read in the current tag */
  96. if (body_length >= 7) {
  97. if (flv_read_tag_body(flv_in, header, 7) < 7) {
  98. return FLV_ERROR_EOF;
  99. }
  100. /* two bytes offset if VP6 0 */
  101. offset = (header[1] & 0x01 || !(header[2] & 0x06)) << 1;
  102. info->video_width = (header[4 + offset] << 4) - (header[0] >> 4);
  103. info->video_height = (header[3 + offset] << 4) - (header[0] & 0x0f);
  104. }
  105. return FLV_OK;
  106. }
  107. /*
  108. compute On2 VP6 with Alpha video size
  109. */
  110. static int compute_vp6_alpha_size(flv_stream * flv_in, flv_info * info, uint32 body_length) {
  111. byte header[10], offset;
  112. /* make sure we have enough bytes to read in the current tag */
  113. if (body_length >= 10) {
  114. if (flv_read_tag_body(flv_in, header, 10) < 10) {
  115. return FLV_ERROR_EOF;
  116. }
  117. /* two bytes offset if VP6 0 */
  118. offset = (header[4] & 0x01 || !(header[5] & 0x06)) << 1;
  119. info->video_width = (header[7 + offset] << 4) - (header[0] >> 4);
  120. info->video_height = (header[6 + offset] << 4) - (header[0] & 0x0f);
  121. }
  122. return FLV_OK;
  123. }
  124. /*
  125. compute AVC (H.264) video size (experimental)
  126. */
  127. static int compute_avc_size(flv_stream * flv_in, flv_info * info, uint32 body_length) {
  128. return read_avc_resolution(flv_in, body_length, &(info->video_width), &(info->video_height));
  129. }
  130. /*
  131. compute video width and height from the first video frame
  132. */
  133. static int compute_video_size(flv_stream * flv_in, flv_info * info, uint32 body_length) {
  134. switch (info->video_codec) {
  135. case FLV_VIDEO_TAG_CODEC_SORENSEN_H263:
  136. return compute_h263_size(flv_in, info, body_length);
  137. case FLV_VIDEO_TAG_CODEC_SCREEN_VIDEO:
  138. case FLV_VIDEO_TAG_CODEC_SCREEN_VIDEO_V2:
  139. return compute_screen_size(flv_in, info, body_length);
  140. case FLV_VIDEO_TAG_CODEC_ON2_VP6:
  141. return compute_vp6_size(flv_in, info, body_length);
  142. case FLV_VIDEO_TAG_CODEC_ON2_VP6_ALPHA:
  143. return compute_vp6_alpha_size(flv_in, info, body_length);
  144. case FLV_VIDEO_TAG_CODEC_AVC:
  145. return compute_avc_size(flv_in, info, body_length);
  146. default:
  147. return FLV_OK;
  148. }
  149. }
  150. /*
  151. read the flv file thoroughly to get all necessary information.
  152. we need to check :
  153. - timestamp of first audio for audio delay
  154. - whether we have audio and video
  155. - first frames codecs (audio, video)
  156. - total audio and video data sizes
  157. - keyframe offsets and timestamps
  158. - whether the last video frame is a keyframe
  159. - last keyframe timestamp
  160. - onMetaData tag total size
  161. - total tags size
  162. - first tag after onMetaData offset
  163. - last timestamp
  164. - real video data size, number of frames, duration to compute framerate and video data rate
  165. - real audio data size, duration to compute audio data rate
  166. - video headers to find width and height. (depends on the encoding)
  167. */
  168. int get_flv_info(flv_stream * flv_in, flv_info * info, const flvmeta_opts * opts) {
  169. uint32 prev_timestamp_video;
  170. uint32 prev_timestamp_audio;
  171. uint32 prev_timestamp_meta;
  172. uint8 timestamp_extended_video;
  173. uint8 timestamp_extended_audio;
  174. uint8 timestamp_extended_meta;
  175. uint8 have_video_size;
  176. uint8 have_first_timestamp;
  177. uint32 tag_number;
  178. int result;
  179. flv_tag ft;
  180. info->have_video = 0;
  181. info->have_audio = 0;
  182. info->video_width = 0;
  183. info->video_height = 0;
  184. info->video_codec = 0;
  185. info->video_frames_number = 0;
  186. info->audio_codec = 0;
  187. info->audio_size = 0;
  188. info->audio_rate = 0;
  189. info->audio_stereo = 0;
  190. info->video_data_size = 0;
  191. info->audio_data_size = 0;
  192. info->meta_data_size = 0;
  193. info->real_video_data_size = 0;
  194. info->real_audio_data_size = 0;
  195. info->video_first_timestamp = 0;
  196. info->audio_first_timestamp = 0;
  197. info->first_timestamp = 0;
  198. info->can_seek_to_end = 0;
  199. info->have_keyframes = 0;
  200. info->last_keyframe_timestamp = 0;
  201. info->on_metadata_size = 0;
  202. info->on_metadata_offset = 0;
  203. info->biggest_tag_body_size = 0;
  204. info->last_timestamp = 0;
  205. info->video_frame_duration = 0;
  206. info->audio_frame_duration = 0;
  207. info->total_prev_tags_size = 0;
  208. info->have_on_last_second = 0;
  209. info->original_on_metadata = NULL;
  210. info->keyframes = NULL;
  211. info->times = NULL;
  212. info->filepositions = NULL;
  213. if (opts->verbose) {
  214. fprintf(stdout, "Parsing %s...\n", opts->input_file);
  215. }
  216. /*
  217. read FLV header
  218. */
  219. if (flv_read_header(flv_in, &(info->header)) != FLV_OK) {
  220. return ERROR_NO_FLV;
  221. }
  222. info->keyframes = amf_object_new();
  223. info->times = amf_array_new();
  224. info->filepositions = amf_array_new();
  225. amf_object_add(info->keyframes, "times", info->times);
  226. amf_object_add(info->keyframes, "filepositions", info->filepositions);
  227. /* first empty previous tag size */
  228. info->total_prev_tags_size = sizeof(uint32_be);
  229. /* first timestamp */
  230. have_first_timestamp = 0;
  231. /* extended timestamp initialization */
  232. prev_timestamp_video = 0;
  233. prev_timestamp_audio = 0;
  234. prev_timestamp_meta = 0;
  235. timestamp_extended_video = 0;
  236. timestamp_extended_audio = 0;
  237. timestamp_extended_meta = 0;
  238. tag_number = 0;
  239. have_video_size = 0;
  240. while (flv_read_tag(flv_in, &ft) == FLV_OK) {
  241. file_offset_t offset;
  242. uint32 body_length;
  243. uint32 timestamp;
  244. offset = flv_get_current_tag_offset(flv_in);
  245. body_length = flv_tag_get_body_length(ft);
  246. timestamp = flv_tag_get_timestamp(ft);
  247. /* extended timestamp fixing */
  248. if (ft.type == FLV_TAG_TYPE_META) {
  249. if (timestamp < prev_timestamp_meta
  250. && prev_timestamp_meta - timestamp > 0xF00000) {
  251. ++timestamp_extended_meta;
  252. }
  253. prev_timestamp_meta = timestamp;
  254. if (timestamp_extended_meta > 0) {
  255. timestamp += timestamp_extended_meta << 24;
  256. }
  257. }
  258. else if (ft.type == FLV_TAG_TYPE_AUDIO) {
  259. if (timestamp < prev_timestamp_audio
  260. && prev_timestamp_audio - timestamp > 0xF00000) {
  261. ++timestamp_extended_audio;
  262. }
  263. prev_timestamp_audio = timestamp;
  264. if (timestamp_extended_audio > 0) {
  265. timestamp += timestamp_extended_audio << 24;
  266. }
  267. }
  268. else if (ft.type == FLV_TAG_TYPE_VIDEO) {
  269. if (timestamp < prev_timestamp_video
  270. && prev_timestamp_video - timestamp > 0xF00000) {
  271. ++timestamp_extended_video;
  272. }
  273. prev_timestamp_video = timestamp;
  274. if (timestamp_extended_video > 0) {
  275. timestamp += timestamp_extended_video << 24;
  276. }
  277. }
  278. /* non-zero starting timestamp handling */
  279. if (!have_first_timestamp && ft.type != FLV_TAG_TYPE_META) {
  280. info->first_timestamp = timestamp;
  281. have_first_timestamp = 1;
  282. }
  283. if (opts->reset_timestamps && timestamp > 0) {
  284. timestamp -= info->first_timestamp;
  285. }
  286. /* update the info struct only if the tag is valid */
  287. if (ft.type == FLV_TAG_TYPE_META
  288. || ft.type == FLV_TAG_TYPE_AUDIO
  289. || ft.type == FLV_TAG_TYPE_VIDEO) {
  290. if (info->biggest_tag_body_size < body_length) {
  291. info->biggest_tag_body_size = body_length;
  292. }
  293. info->last_timestamp = timestamp;
  294. }
  295. if (ft.type == FLV_TAG_TYPE_META) {
  296. amf_data *tag_name, *data;
  297. int retval;
  298. tag_name = data = NULL;
  299. if (body_length == 0) {
  300. if (opts->verbose) {
  301. fprintf(stdout, "Warning: empty metadata tag at 0x%" FILE_OFFSET_PRINTF_FORMAT "X\n", offset);
  302. }
  303. }
  304. else {
  305. retval = flv_read_metadata(flv_in, &tag_name, &data);
  306. if (retval == FLV_ERROR_EOF) {
  307. amf_data_free(tag_name);
  308. amf_data_free(data);
  309. return ERROR_EOF;
  310. }
  311. else if (retval == FLV_ERROR_INVALID_METADATA_NAME) {
  312. if (opts->verbose) {
  313. fprintf(stdout, "Warning: invalid metadata name at 0x%" FILE_OFFSET_PRINTF_FORMAT "X\n", offset);
  314. }
  315. }
  316. else if (retval == FLV_ERROR_INVALID_METADATA) {
  317. if (opts->verbose) {
  318. fprintf(stdout, "Warning: invalid metadata at 0x%" FILE_OFFSET_PRINTF_FORMAT "X\n", offset);
  319. }
  320. if (opts->error_handling == FLVMETA_EXIT_ON_ERROR) {
  321. amf_data_free(tag_name);
  322. amf_data_free(data);
  323. return ERROR_INVALID_TAG;
  324. }
  325. }
  326. }
  327. /* check metadata name */
  328. if (body_length > 0 && amf_data_get_type(tag_name) == AMF_TYPE_STRING) {
  329. char * name = (char *)amf_string_get_bytes(tag_name);
  330. size_t len = (size_t)amf_string_get_size(tag_name);
  331. /* get info only on the first onMetaData we read */
  332. if (info->on_metadata_size == 0 && !strncmp(name, "onMetaData", len)) {
  333. info->on_metadata_size = body_length + FLV_TAG_SIZE + sizeof(uint32_be);
  334. info->on_metadata_offset = offset;
  335. /* if we want to preserve existing metadata, then extract them */
  336. if (opts->preserve_metadata == 1) {
  337. /* we need an AMF associative array here, so we must
  338. discard errors and mis-typed data */
  339. if (amf_data_get_error_code(data) != AMF_ERROR_OK
  340. || amf_data_get_type(data) != AMF_TYPE_ASSOCIATIVE_ARRAY) {
  341. amf_data_free(data);
  342. data = amf_associative_array_new();
  343. }
  344. info->original_on_metadata = data;
  345. }
  346. else {
  347. amf_data_free(data);
  348. }
  349. }
  350. else {
  351. if (!strncmp(name, "onLastSecond", len)) {
  352. info->have_on_last_second = 1;
  353. }
  354. info->meta_data_size += (body_length + FLV_TAG_SIZE);
  355. info->total_prev_tags_size += sizeof(uint32_be);
  356. if (data != NULL) {
  357. amf_data_free(data);
  358. }
  359. }
  360. }
  361. /* just ignore metadata that don't have a proper name */
  362. else {
  363. info->meta_data_size += (body_length + FLV_TAG_SIZE);
  364. info->total_prev_tags_size += sizeof(uint32_be);
  365. amf_data_free(data);
  366. }
  367. amf_data_free(tag_name);
  368. }
  369. else if (ft.type == FLV_TAG_TYPE_VIDEO) {
  370. flv_video_tag vt;
  371. /* do not take video frame into account if body length is zero and we ignore errors */
  372. if (body_length == 0) {
  373. if (opts->verbose) {
  374. fprintf(stdout, "Warning: empty video tag at 0x%" FILE_OFFSET_PRINTF_FORMAT "X\n", offset);
  375. }
  376. }
  377. else {
  378. if (flv_read_video_tag(flv_in, &vt) != FLV_OK) {
  379. return ERROR_EOF;
  380. }
  381. if (info->have_video != 1) {
  382. info->have_video = 1;
  383. info->video_codec = flv_video_tag_codec_id(vt);
  384. info->video_first_timestamp = timestamp;
  385. }
  386. if (have_video_size != 1
  387. && flv_video_tag_frame_type(vt) == FLV_VIDEO_TAG_FRAME_TYPE_KEYFRAME) {
  388. /* read first video frame to get critical info */
  389. result = compute_video_size(flv_in, info, body_length - sizeof(flv_video_tag));
  390. if (result != FLV_OK) {
  391. return result;
  392. }
  393. if (info->video_width > 0 && info->video_height > 0) {
  394. have_video_size = 1;
  395. }
  396. /* if we cannot fetch that information from the first tag, we'll try
  397. for each following video key frame */
  398. }
  399. /* add keyframe to list */
  400. if (flv_video_tag_frame_type(vt) == FLV_VIDEO_TAG_FRAME_TYPE_KEYFRAME) {
  401. /* do not add keyframe if the previous one has the same timestamp */
  402. if (!info->have_keyframes
  403. || (info->have_keyframes && info->last_keyframe_timestamp != timestamp)
  404. || opts->all_keyframes) {
  405. info->have_keyframes = 1;
  406. info->last_keyframe_timestamp = timestamp;
  407. amf_array_push(info->times, amf_number_new(timestamp / 1000.0));
  408. amf_array_push(info->filepositions, amf_number_new((number64)offset));
  409. }
  410. /* is last frame a key frame ? if so, we can seek to end */
  411. info->can_seek_to_end = 1;
  412. }
  413. else {
  414. info->can_seek_to_end = 0;
  415. }
  416. info->real_video_data_size += (body_length - 1);
  417. }
  418. info->video_frames_number++;
  419. /*
  420. we assume all video frames have the same size as the first one:
  421. probably bogus but only used in case there's no audio in the file
  422. */
  423. if (info->video_frame_duration == 0) {
  424. info->video_frame_duration = timestamp - info->video_first_timestamp;
  425. }
  426. info->video_data_size += (body_length + FLV_TAG_SIZE);
  427. info->total_prev_tags_size += sizeof(uint32_be);
  428. }
  429. else if (ft.type == FLV_TAG_TYPE_AUDIO) {
  430. flv_audio_tag at;
  431. /* do not take audio frame into account if body length is zero and we ignore errors */
  432. if (body_length == 0) {
  433. if (opts->verbose) {
  434. fprintf(stdout, "Warning: empty audio tag at 0x%" FILE_OFFSET_PRINTF_FORMAT "X\n", offset);
  435. }
  436. }
  437. else {
  438. if (flv_read_audio_tag(flv_in, &at) != FLV_OK) {
  439. return ERROR_EOF;
  440. }
  441. if (info->have_audio != 1) {
  442. info->have_audio = 1;
  443. info->audio_codec = flv_audio_tag_sound_format(at);
  444. info->audio_rate = flv_audio_tag_sound_rate(at);
  445. info->audio_size = flv_audio_tag_sound_size(at);
  446. info->audio_stereo = flv_audio_tag_sound_type(at);
  447. info->audio_first_timestamp = timestamp;
  448. }
  449. /* we assume all audio frames have the same size as the first one */
  450. if (info->audio_frame_duration == 0) {
  451. info->audio_frame_duration = timestamp - info->audio_first_timestamp;
  452. }
  453. info->real_audio_data_size += (body_length - 1);
  454. }
  455. info->audio_data_size += (body_length + FLV_TAG_SIZE);
  456. info->total_prev_tags_size += sizeof(uint32_be);
  457. }
  458. else {
  459. if (opts->error_handling == FLVMETA_FIX_ERRORS) {
  460. /* TODO : fix errors if possible */
  461. }
  462. else if (opts->error_handling == FLVMETA_IGNORE_ERRORS) {
  463. /* let's continue the parsing */
  464. if (opts->verbose) {
  465. fprintf(stdout, "Warning: invalid tag at 0x%" FILE_OFFSET_PRINTF_FORMAT "X\n", offset);
  466. }
  467. info->total_prev_tags_size += sizeof(uint32_be);
  468. }
  469. else {
  470. return ERROR_INVALID_TAG;
  471. }
  472. }
  473. ++tag_number;
  474. }
  475. if (opts->verbose) {
  476. fprintf(stdout, "Found %d tags\n", tag_number);
  477. }
  478. return OK;
  479. }
  480. /*
  481. compute the metadata
  482. */
  483. void compute_metadata(flv_info * info, flv_metadata * meta, const flvmeta_opts * opts) {
  484. uint32 new_on_metadata_size, on_last_second_size;
  485. file_offset_t data_size, total_filesize;
  486. number64 duration, video_data_rate, framerate;
  487. amf_data * amf_total_filesize;
  488. amf_data * amf_total_data_size;
  489. amf_node * node_t;
  490. amf_node * node_f;
  491. if (opts->verbose) {
  492. fprintf(stdout, "Computing metadata...\n");
  493. }
  494. meta->on_last_second_name = amf_str("onLastSecond");
  495. meta->on_last_second = amf_associative_array_new();
  496. meta->on_metadata_name = amf_str("onMetaData");
  497. if (opts->metadata == NULL) {
  498. meta->on_metadata = amf_associative_array_new();
  499. }
  500. else {
  501. meta->on_metadata = opts->metadata;
  502. }
  503. amf_associative_array_add(meta->on_metadata, "hasMetadata", amf_boolean_new(1));
  504. amf_associative_array_add(meta->on_metadata, "hasVideo", amf_boolean_new(info->have_video));
  505. amf_associative_array_add(meta->on_metadata, "hasAudio", amf_boolean_new(info->have_audio));
  506. if (info->have_audio) {
  507. duration = (info->last_timestamp - (opts->reset_timestamps ? 0 : info->first_timestamp) + info->audio_frame_duration) / 1000.0;
  508. }
  509. else {
  510. duration = (info->last_timestamp - (opts->reset_timestamps ? 0 : info->first_timestamp) + info->video_frame_duration) / 1000.0;
  511. }
  512. amf_associative_array_add(meta->on_metadata, "duration", amf_number_new(duration));
  513. amf_associative_array_add(meta->on_metadata, "lasttimestamp", amf_number_new(info->last_timestamp / 1000.0));
  514. amf_associative_array_add(meta->on_metadata, "lastkeyframetimestamp", amf_number_new(info->last_keyframe_timestamp / 1000.0));
  515. if (info->video_width > 0)
  516. amf_associative_array_add(meta->on_metadata, "width", amf_number_new(info->video_width));
  517. if (info->video_height > 0)
  518. amf_associative_array_add(meta->on_metadata, "height", amf_number_new(info->video_height));
  519. video_data_rate = ((info->real_video_data_size / 1024.0) * 8.0) / duration;
  520. amf_associative_array_add(meta->on_metadata, "videodatarate", amf_number_new(video_data_rate));
  521. framerate = info->video_frames_number / duration;
  522. amf_associative_array_add(meta->on_metadata, "framerate", amf_number_new(framerate));
  523. if (info->have_audio) {
  524. number64 audio_khz, audio_sample_rate;
  525. number64 audio_data_rate = ((info->real_audio_data_size / 1024.0) * 8.0) / duration;
  526. amf_associative_array_add(meta->on_metadata, "audiodatarate", amf_number_new(audio_data_rate));
  527. audio_khz = 0.0;
  528. switch (info->audio_rate) {
  529. case FLV_AUDIO_TAG_SOUND_RATE_5_5: audio_khz = 5500.0; break;
  530. case FLV_AUDIO_TAG_SOUND_RATE_11: audio_khz = 11000.0; break;
  531. case FLV_AUDIO_TAG_SOUND_RATE_22: audio_khz = 22050.0; break;
  532. case FLV_AUDIO_TAG_SOUND_RATE_44: audio_khz = 44100.0; break;
  533. }
  534. amf_associative_array_add(meta->on_metadata, "audiosamplerate", amf_number_new(audio_khz));
  535. audio_sample_rate = 0.0;
  536. switch (info->audio_size) {
  537. case FLV_AUDIO_TAG_SOUND_SIZE_8: audio_sample_rate = 8.0; break;
  538. case FLV_AUDIO_TAG_SOUND_SIZE_16: audio_sample_rate = 16.0; break;
  539. }
  540. amf_associative_array_add(meta->on_metadata, "audiosamplesize", amf_number_new(audio_sample_rate));
  541. amf_associative_array_add(meta->on_metadata, "stereo", amf_boolean_new(info->audio_stereo == FLV_AUDIO_TAG_SOUND_TYPE_STEREO));
  542. }
  543. /* to be computed later */
  544. amf_total_filesize = amf_number_new(0);
  545. amf_associative_array_add(meta->on_metadata, "filesize", amf_total_filesize);
  546. if (info->have_video) {
  547. amf_associative_array_add(meta->on_metadata, "videosize", amf_number_new((number64)info->video_data_size));
  548. }
  549. if (info->have_audio) {
  550. amf_associative_array_add(meta->on_metadata, "audiosize", amf_number_new((number64)info->audio_data_size));
  551. }
  552. /* to be computed later */
  553. amf_total_data_size = amf_number_new(0);
  554. amf_associative_array_add(meta->on_metadata, "datasize", amf_total_data_size);
  555. amf_associative_array_add(meta->on_metadata, "metadatacreator", amf_str(PACKAGE_STRING));
  556. amf_associative_array_add(meta->on_metadata, "metadatadate", amf_date_new((number64)time(NULL)*1000, 0));
  557. if (info->have_audio) {
  558. amf_associative_array_add(meta->on_metadata, "audiocodecid", amf_number_new((number64)info->audio_codec));
  559. }
  560. if (info->have_video) {
  561. amf_associative_array_add(meta->on_metadata, "videocodecid", amf_number_new((number64)info->video_codec));
  562. }
  563. if (info->have_audio && info->have_video) {
  564. number64 audio_delay = ((sint32)info->audio_first_timestamp - (sint32)info->video_first_timestamp) / 1000.0;
  565. amf_associative_array_add(meta->on_metadata, "audiodelay", amf_number_new((number64)audio_delay));
  566. }
  567. amf_associative_array_add(meta->on_metadata, "canSeekToEnd", amf_boolean_new(info->can_seek_to_end));
  568. /* only add empty cuepoints if we don't preserve existing tags OR if the existing tags don't have cuepoints */
  569. if (opts->preserve_metadata == 0
  570. || (opts->preserve_metadata == 1 && amf_associative_array_get(info->original_on_metadata, "cuePoints") == NULL)) {
  571. amf_associative_array_add(meta->on_metadata, "hasCuePoints", amf_boolean_new(0));
  572. amf_associative_array_add(meta->on_metadata, "cuePoints", amf_array_new());
  573. }
  574. amf_associative_array_add(meta->on_metadata, "hasKeyframes", amf_boolean_new(info->have_keyframes));
  575. amf_associative_array_add(meta->on_metadata, "keyframes", info->keyframes);
  576. /* merge metadata from input file if we specified the preserve option */
  577. if (opts->preserve_metadata) {
  578. /* for each tag in the original metadata, we add it if it does not exist */
  579. amf_node * node = amf_associative_array_first(info->original_on_metadata);
  580. while (node != NULL) {
  581. char * name = (char *)amf_string_get_bytes(amf_associative_array_get_name(node));
  582. if (amf_associative_array_get(meta->on_metadata, name) == NULL) {
  583. /* add metadata */
  584. amf_associative_array_add(meta->on_metadata, name, amf_data_clone(amf_associative_array_get_data(node)));
  585. }
  586. node = amf_associative_array_next(node);
  587. }
  588. /* all old data has been duplicated to the new metadata, we can safely delete it */
  589. amf_data_free(info->original_on_metadata);
  590. info->original_on_metadata = NULL;
  591. }
  592. /*
  593. When we know the final size, we can recompute te offsets for the filepositions, and the final datasize.
  594. */
  595. new_on_metadata_size = FLV_TAG_SIZE + sizeof(uint32_be) +
  596. (uint32)(amf_data_size(meta->on_metadata_name) + amf_data_size(meta->on_metadata));
  597. on_last_second_size = (uint32)(amf_data_size(meta->on_last_second_name) + amf_data_size(meta->on_last_second));
  598. node_t = amf_array_first(info->times);
  599. node_f = amf_array_first(info->filepositions);
  600. while (node_t != NULL || node_f != NULL) {
  601. amf_data * amf_filepos = amf_array_get(node_f);
  602. number64 offset = amf_number_get_value(amf_filepos) + new_on_metadata_size - info->on_metadata_size;
  603. number64 timestamp = amf_number_get_value(amf_array_get(node_t));
  604. /* after the onLastSecond event we need to take in account the tag size */
  605. if (opts->insert_onlastsecond && !info->have_on_last_second && (info->last_timestamp - timestamp * 1000) <= 1000) {
  606. offset += (FLV_TAG_SIZE + on_last_second_size + sizeof(uint32_be));
  607. }
  608. amf_number_set_value(amf_filepos, offset);
  609. node_t = amf_array_next(node_t);
  610. node_f = amf_array_next(node_f);
  611. }
  612. /* compute data size, ie. size of metadata excluding prev_tag_size */
  613. data_size = info->meta_data_size + FLV_TAG_SIZE +
  614. (uint32)(amf_data_size(meta->on_metadata_name) + amf_data_size(meta->on_metadata));
  615. if (!info->have_on_last_second && opts->insert_onlastsecond) {
  616. data_size += (uint32)on_last_second_size + FLV_TAG_SIZE;
  617. }
  618. amf_number_set_value(amf_total_data_size, (number64)data_size);
  619. /* compute total file size */
  620. total_filesize = FLV_HEADER_SIZE + info->total_prev_tags_size + info->video_data_size +
  621. info->audio_data_size + info->meta_data_size + new_on_metadata_size;
  622. if (!info->have_on_last_second && opts->insert_onlastsecond) {
  623. /* if we have to add onLastSecond, we must count the header and new prevTagSize we add */
  624. total_filesize += (uint32)(FLV_TAG_SIZE + on_last_second_size + sizeof(uint32_be));
  625. }
  626. amf_number_set_value(amf_total_filesize, (number64)total_filesize);
  627. }