/src/flv.c

https://code.google.com/ · C · 496 lines · 401 code · 61 blank · 34 comment · 222 complexity · 3941bacdb7e93250ce87aabfeabb8d90 MD5 · raw file

  1. /*
  2. $Id: flv.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 "flv.h"
  19. #include <string.h>
  20. void flv_tag_set_timestamp(flv_tag * tag, uint32 timestamp) {
  21. tag->timestamp = uint32_to_uint24_be(timestamp);
  22. tag->timestamp_extended = (uint8)((timestamp & 0xFF000000) >> 24);
  23. }
  24. /* FLV stream functions */
  25. flv_stream * flv_open(const char * file) {
  26. flv_stream * stream = (flv_stream *) malloc(sizeof(flv_stream));
  27. if (stream == NULL) {
  28. return NULL;
  29. }
  30. stream->flvin = fopen(file, "rb");
  31. if (stream->flvin == NULL) {
  32. free(stream);
  33. return NULL;
  34. }
  35. stream->current_tag_body_length = 0;
  36. stream->current_tag_body_overflow = 0;
  37. stream->current_tag_offset = 0;
  38. stream->state = FLV_STREAM_STATE_START;
  39. return stream;
  40. }
  41. int flv_read_header(flv_stream * stream, flv_header * header) {
  42. if (stream == NULL
  43. || stream->flvin == NULL
  44. || feof(stream->flvin)
  45. || stream->state != FLV_STREAM_STATE_START) {
  46. return FLV_ERROR_EOF;
  47. }
  48. if (fread(&header->signature, sizeof(header->signature), 1, stream->flvin) == 0
  49. || fread(&header->version, sizeof(header->version), 1, stream->flvin) == 0
  50. || fread(&header->flags, sizeof(header->flags), 1, stream->flvin) == 0
  51. || fread(&header->offset, sizeof(header->offset), 1, stream->flvin) == 0) {
  52. return FLV_ERROR_EOF;
  53. }
  54. if (header->signature[0] != 'F'
  55. || header->signature[1] != 'L'
  56. || header->signature[2] != 'V') {
  57. return FLV_ERROR_NO_FLV;
  58. }
  59. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  60. return FLV_OK;
  61. }
  62. int flv_read_prev_tag_size(flv_stream * stream, uint32 * prev_tag_size) {
  63. uint32_be val;
  64. if (stream == NULL
  65. || stream->flvin == NULL
  66. || feof(stream->flvin)) {
  67. return FLV_ERROR_EOF;
  68. }
  69. /* skip remaining tag body bytes */
  70. if (stream->state == FLV_STREAM_STATE_TAG_BODY) {
  71. lfs_fseek(stream->flvin, stream->current_tag_offset + FLV_TAG_SIZE + uint24_be_to_uint32(stream->current_tag.body_length), SEEK_SET);
  72. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  73. }
  74. if (stream->state == FLV_STREAM_STATE_PREV_TAG_SIZE) {
  75. if (fread(&val, sizeof(uint32_be), 1, stream->flvin) == 0) {
  76. return FLV_ERROR_EOF;
  77. }
  78. else {
  79. stream->state = FLV_STREAM_STATE_TAG;
  80. *prev_tag_size = swap_uint32(val);
  81. return FLV_OK;
  82. }
  83. }
  84. else {
  85. return FLV_ERROR_EOF;
  86. }
  87. }
  88. int flv_read_tag(flv_stream * stream, flv_tag * tag) {
  89. if (stream == NULL
  90. || stream->flvin == NULL
  91. || feof(stream->flvin)) {
  92. return FLV_ERROR_EOF;
  93. }
  94. /* skip header */
  95. if (stream->state == FLV_STREAM_STATE_START) {
  96. lfs_fseek(stream->flvin, FLV_HEADER_SIZE, SEEK_CUR);
  97. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  98. }
  99. /* skip current tag body */
  100. if (stream->state == FLV_STREAM_STATE_TAG_BODY) {
  101. lfs_fseek(stream->flvin, stream->current_tag_offset + FLV_TAG_SIZE + uint24_be_to_uint32(stream->current_tag.body_length), SEEK_SET);
  102. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  103. }
  104. /* skip previous tag size */
  105. if (stream->state == FLV_STREAM_STATE_PREV_TAG_SIZE) {
  106. lfs_fseek(stream->flvin, sizeof(uint32_be), SEEK_CUR);
  107. stream->state = FLV_STREAM_STATE_TAG;
  108. }
  109. if (stream->state == FLV_STREAM_STATE_TAG) {
  110. stream->current_tag_offset = lfs_ftell(stream->flvin);
  111. if (fread(&tag->type, sizeof(tag->type), 1, stream->flvin) == 0
  112. || fread(&tag->body_length, sizeof(tag->body_length), 1, stream->flvin) == 0
  113. || fread(&tag->timestamp, sizeof(tag->timestamp), 1, stream->flvin) == 0
  114. || fread(&tag->timestamp_extended, sizeof(tag->timestamp_extended), 1, stream->flvin) == 0
  115. || fread(&tag->stream_id, sizeof(tag->stream_id), 1, stream->flvin) == 0) {
  116. return FLV_ERROR_EOF;
  117. }
  118. else {
  119. memcpy(&stream->current_tag, tag, sizeof(flv_tag));
  120. stream->current_tag_body_length = uint24_be_to_uint32(tag->body_length);
  121. stream->current_tag_body_overflow = 0;
  122. stream->state = FLV_STREAM_STATE_TAG_BODY;
  123. return FLV_OK;
  124. }
  125. }
  126. else {
  127. return FLV_ERROR_EOF;
  128. }
  129. }
  130. int flv_read_audio_tag(flv_stream * stream, flv_audio_tag * tag) {
  131. if (stream == NULL
  132. || stream->flvin == NULL
  133. || feof(stream->flvin)
  134. || stream->state != FLV_STREAM_STATE_TAG_BODY) {
  135. return FLV_ERROR_EOF;
  136. }
  137. if (stream->current_tag_body_length == 0) {
  138. return FLV_ERROR_EMPTY_TAG;
  139. }
  140. if (fread(tag, sizeof(flv_audio_tag), 1, stream->flvin) == 0) {
  141. return FLV_ERROR_EOF;
  142. }
  143. if (stream->current_tag_body_length >= sizeof(flv_audio_tag)) {
  144. stream->current_tag_body_length -= sizeof(flv_audio_tag);
  145. }
  146. else {
  147. stream->current_tag_body_overflow = sizeof(flv_audio_tag) - stream->current_tag_body_length;
  148. stream->current_tag_body_length = 0;
  149. }
  150. if (stream->current_tag_body_length == 0) {
  151. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  152. if (stream->current_tag_body_overflow > 0) {
  153. lfs_fseek(stream->flvin, -(file_offset_t)stream->current_tag_body_overflow, SEEK_CUR);
  154. }
  155. }
  156. return FLV_OK;
  157. }
  158. int flv_read_video_tag(flv_stream * stream, flv_video_tag * tag) {
  159. if (stream == NULL
  160. || stream->flvin == NULL
  161. || feof(stream->flvin)
  162. || stream->state != FLV_STREAM_STATE_TAG_BODY) {
  163. return FLV_ERROR_EOF;
  164. }
  165. if (stream->current_tag_body_length == 0) {
  166. return FLV_ERROR_EMPTY_TAG;
  167. }
  168. if (fread(tag, sizeof(flv_video_tag), 1, stream->flvin) == 0) {
  169. return FLV_ERROR_EOF;
  170. }
  171. if (stream->current_tag_body_length >= sizeof(flv_video_tag)) {
  172. stream->current_tag_body_length -= sizeof(flv_video_tag);
  173. }
  174. else {
  175. stream->current_tag_body_overflow = sizeof(flv_video_tag) - stream->current_tag_body_length;
  176. stream->current_tag_body_length = 0;
  177. }
  178. if (stream->current_tag_body_length == 0) {
  179. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  180. if (stream->current_tag_body_overflow > 0) {
  181. lfs_fseek(stream->flvin, -(file_offset_t)stream->current_tag_body_overflow, SEEK_CUR);
  182. }
  183. }
  184. return FLV_OK;
  185. }
  186. int flv_read_metadata(flv_stream * stream, amf_data ** name, amf_data ** data) {
  187. amf_data * d;
  188. byte error_code;
  189. size_t data_size;
  190. if (stream == NULL
  191. || stream->flvin == NULL
  192. || feof(stream->flvin)
  193. || stream->state != FLV_STREAM_STATE_TAG_BODY) {
  194. return FLV_ERROR_EOF;
  195. }
  196. if (stream->current_tag_body_length == 0) {
  197. return FLV_ERROR_EMPTY_TAG;
  198. }
  199. /* read metadata name */
  200. d = amf_data_file_read(stream->flvin);
  201. *name = d;
  202. error_code = amf_data_get_error_code(d);
  203. if (error_code == AMF_ERROR_EOF) {
  204. return FLV_ERROR_EOF;
  205. }
  206. else if (error_code != AMF_ERROR_OK) {
  207. return FLV_ERROR_INVALID_METADATA_NAME;
  208. }
  209. /* if only name can be read, metadata are invalid */
  210. data_size = amf_data_size(d);
  211. if (stream->current_tag_body_length > data_size) {
  212. stream->current_tag_body_length -= (uint32)data_size;
  213. }
  214. else {
  215. stream->current_tag_body_length = 0;
  216. stream->current_tag_body_overflow = (uint32)data_size - stream->current_tag_body_length;
  217. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  218. if (stream->current_tag_body_overflow > 0) {
  219. lfs_fseek(stream->flvin, -(file_offset_t)stream->current_tag_body_overflow, SEEK_CUR);
  220. }
  221. return FLV_ERROR_INVALID_METADATA;
  222. }
  223. /* read metadata contents */
  224. d = amf_data_file_read(stream->flvin);
  225. *data = d;
  226. error_code = amf_data_get_error_code(d);
  227. if (error_code == AMF_ERROR_EOF) {
  228. return FLV_ERROR_EOF;
  229. }
  230. if (error_code != AMF_ERROR_OK) {
  231. return FLV_ERROR_INVALID_METADATA;
  232. }
  233. data_size = amf_data_size(d);
  234. if (stream->current_tag_body_length >= data_size) {
  235. stream->current_tag_body_length -= (uint32)data_size;
  236. }
  237. else {
  238. stream->current_tag_body_overflow = (uint32)data_size - stream->current_tag_body_length;
  239. stream->current_tag_body_length = 0;
  240. }
  241. if (stream->current_tag_body_length == 0) {
  242. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  243. if (stream->current_tag_body_overflow > 0) {
  244. lfs_fseek(stream->flvin, -(file_offset_t)stream->current_tag_body_overflow, SEEK_CUR);
  245. }
  246. }
  247. return FLV_OK;
  248. }
  249. size_t flv_read_tag_body(flv_stream * stream, void * buffer, size_t buffer_size) {
  250. size_t bytes_number;
  251. if (stream == NULL
  252. || stream->flvin == NULL
  253. || feof(stream->flvin)
  254. || stream->state != FLV_STREAM_STATE_TAG_BODY) {
  255. return 0;
  256. }
  257. bytes_number = (buffer_size > stream->current_tag_body_length) ? stream->current_tag_body_length : buffer_size;
  258. bytes_number = fread(buffer, sizeof(byte), bytes_number, stream->flvin);
  259. stream->current_tag_body_length -= (uint32)bytes_number;
  260. if (stream->current_tag_body_length == 0) {
  261. stream->state = FLV_STREAM_STATE_PREV_TAG_SIZE;
  262. }
  263. return bytes_number;
  264. }
  265. file_offset_t flv_get_current_tag_offset(flv_stream * stream) {
  266. return (stream != NULL) ? stream->current_tag_offset : 0;
  267. }
  268. file_offset_t flv_get_offset(flv_stream * stream) {
  269. return (stream != NULL) ? lfs_ftell(stream->flvin) : 0;
  270. }
  271. void flv_reset(flv_stream * stream) {
  272. /* go back to beginning of file */
  273. if (stream != NULL && stream->flvin != NULL) {
  274. stream->current_tag_body_length = 0;
  275. stream->current_tag_offset = 0;
  276. stream->state = FLV_STREAM_STATE_START;
  277. lfs_fseek(stream->flvin, 0, SEEK_SET);
  278. }
  279. }
  280. void flv_close(flv_stream * stream) {
  281. if (stream != NULL) {
  282. if (stream->flvin != NULL) {
  283. fclose(stream->flvin);
  284. }
  285. free(stream);
  286. }
  287. }
  288. /* FLV stdio writing helper functions */
  289. size_t flv_write_header(FILE * out, const flv_header * header) {
  290. if (fwrite(&header->signature, sizeof(header->signature), 1, out) == 0)
  291. return 0;
  292. if (fwrite(&header->version, sizeof(header->version), 1, out) == 0)
  293. return 0;
  294. if (fwrite(&header->flags, sizeof(header->flags), 1, out) == 0)
  295. return 0;
  296. if (fwrite(&header->offset, sizeof(header->offset), 1, out) == 0)
  297. return 0;
  298. return 1;
  299. }
  300. size_t flv_write_tag(FILE * out, const flv_tag * tag) {
  301. if (fwrite(&tag->type, sizeof(tag->type), 1, out) == 0)
  302. return 0;
  303. if (fwrite(&tag->body_length, sizeof(tag->body_length), 1, out) == 0)
  304. return 0;
  305. if (fwrite(&tag->timestamp, sizeof(tag->timestamp), 1, out) == 0)
  306. return 0;
  307. if (fwrite(&tag->timestamp_extended, sizeof(tag->timestamp_extended), 1, out) == 0)
  308. return 0;
  309. if (fwrite(&tag->stream_id, sizeof(tag->stream_id), 1, out) == 0)
  310. return 0;
  311. return 1;
  312. }
  313. /* FLV event based parser */
  314. int flv_parse(const char * file, flv_parser * parser) {
  315. flv_header header;
  316. flv_tag tag;
  317. flv_audio_tag at;
  318. flv_video_tag vt;
  319. amf_data * name, * data;
  320. uint32 prev_tag_size;
  321. int retval;
  322. if (parser == NULL) {
  323. return FLV_ERROR_EOF;
  324. }
  325. parser->stream = flv_open(file);
  326. if (parser->stream == NULL) {
  327. return FLV_ERROR_OPEN_READ;
  328. }
  329. retval = flv_read_header(parser->stream, &header);
  330. if (retval != FLV_OK) {
  331. flv_close(parser->stream);
  332. return retval;
  333. }
  334. if (parser->on_header != NULL) {
  335. retval = parser->on_header(&header, parser);
  336. if (retval != FLV_OK) {
  337. flv_close(parser->stream);
  338. return retval;
  339. }
  340. }
  341. while (flv_read_tag(parser->stream, &tag) == FLV_OK) {
  342. if (parser->on_tag != NULL) {
  343. retval = parser->on_tag(&tag, parser);
  344. if (retval != FLV_OK) {
  345. flv_close(parser->stream);
  346. return retval;
  347. }
  348. }
  349. if (tag.type == FLV_TAG_TYPE_AUDIO) {
  350. retval = flv_read_audio_tag(parser->stream, &at);
  351. if (retval == FLV_ERROR_EOF) {
  352. flv_close(parser->stream);
  353. return retval;
  354. }
  355. if (retval != FLV_ERROR_EMPTY_TAG && parser->on_audio_tag != NULL) {
  356. retval = parser->on_audio_tag(&tag, at, parser);
  357. if (retval != FLV_OK) {
  358. flv_close(parser->stream);
  359. return retval;
  360. }
  361. }
  362. }
  363. else if (tag.type == FLV_TAG_TYPE_VIDEO) {
  364. retval = flv_read_video_tag(parser->stream, &vt);
  365. if (retval == FLV_ERROR_EOF) {
  366. flv_close(parser->stream);
  367. return retval;
  368. }
  369. if (retval != FLV_ERROR_EMPTY_TAG && parser->on_video_tag != NULL) {
  370. retval = parser->on_video_tag(&tag, vt, parser);
  371. if (retval != FLV_OK) {
  372. flv_close(parser->stream);
  373. return retval;
  374. }
  375. }
  376. }
  377. else if (tag.type == FLV_TAG_TYPE_META) {
  378. name = data = NULL;
  379. retval = flv_read_metadata(parser->stream, &name, &data);
  380. if (retval == FLV_ERROR_EOF) {
  381. amf_data_free(name);
  382. amf_data_free(data);
  383. flv_close(parser->stream);
  384. return retval;
  385. }
  386. else if (retval == FLV_OK && parser->on_metadata_tag != NULL) {
  387. retval = parser->on_metadata_tag(&tag, name, data, parser);
  388. if (retval != FLV_OK) {
  389. amf_data_free(name);
  390. amf_data_free(data);
  391. flv_close(parser->stream);
  392. return retval;
  393. }
  394. }
  395. amf_data_free(name);
  396. amf_data_free(data);
  397. }
  398. else {
  399. if (parser->on_unknown_tag != NULL) {
  400. retval = parser->on_unknown_tag(&tag, parser);
  401. if (retval != FLV_OK) {
  402. flv_close(parser->stream);
  403. return retval;
  404. }
  405. }
  406. }
  407. retval = flv_read_prev_tag_size(parser->stream, &prev_tag_size);
  408. if (retval != FLV_OK) {
  409. flv_close(parser->stream);
  410. return retval;
  411. }
  412. if (parser->on_prev_tag_size != NULL) {
  413. retval = parser->on_prev_tag_size(prev_tag_size, parser);
  414. if (retval != FLV_OK) {
  415. flv_close(parser->stream);
  416. return retval;
  417. }
  418. }
  419. }
  420. if (parser->on_stream_end != NULL) {
  421. retval = parser->on_stream_end(parser);
  422. if (retval != FLV_OK) {
  423. flv_close(parser->stream);
  424. return retval;
  425. }
  426. }
  427. flv_close(parser->stream);
  428. return FLV_OK;
  429. }