1 /*
2  * yamdi.c
3  *
4  * Copyright (c) 2007+, Ingo Oppermann
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in the
14  *       documentation and/or other materials provided with the distribution.
15  *     * Neither the name of the copyright holder nor the names of its
16  *       contributors may be used to endorse or promote products derived from
17  *       this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * -----------------------------------------------------------------------------
32  *
33  * Compile with:
34  * gcc yamdi.c -o yamdi -Wall -O2
35  *
36  * -----------------------------------------------------------------------------
37  */
38 
39 #include <sys/types.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <inttypes.h>
45 #include <errno.h>
46 
47 #ifdef __MINGW32__
48 	#define off_t _off64_t
49 	#define fseeko(stream, offset, origin) fseeko64(stream, offset, origin)
50 	#define ftello(stream) ftello64(stream)
51 #endif
52 
53 #define YAMDI_VERSION			"1.9"
54 
55 #define YAMDI_OK			0
56 #define YAMDI_ERROR			1
57 #define YAMDI_FILE_TOO_SMALL		2
58 #define YAMDI_INVALID_SIGNATURE		3
59 #define YAMDI_INVALID_FLVVERSION	4
60 #define YAMDI_INVALID_DATASIZE		5
61 #define YAMDI_READ_ERROR		6
62 #define YAMDI_INVALID_PREVIOUSTAGSIZE	7
63 #define YAMDI_OUT_OF_MEMORY		8
64 #define YAMDI_H264_USELESS_NALU		9
65 #define YAMDI_RENAME_OUTPUT		10
66 #define YAMDI_INVALID_TAGTYPE		11
67 
68 #define FLV_SIZE_HEADER			9
69 #define FLV_SIZE_PREVIOUSTAGSIZE	4
70 #define FLV_SIZE_TAGHEADER		11
71 
72 #define FLV_TAG_AUDIO			8
73 #define FLV_TAG_VIDEO			9
74 #define FLV_TAG_SCRIPTDATA		18
75 
76 #define FLV_PACKET_H263VIDEO		2
77 #define FLV_PACKET_SCREENVIDEO		3
78 #define	FLV_PACKET_VP6VIDEO		4
79 #define	FLV_PACKET_VP6ALPHAVIDEO	5
80 #define FLV_PACKET_SCREENV2VIDEO	6
81 #define FLV_PACKET_H264VIDEO		7
82 
83 #define FLV_UI32(x) (unsigned int)(((*(x)) << 24) + ((*(x + 1)) << 16) + ((*(x + 2)) << 8) + (*(x + 3)))
84 #define FLV_UI24(x) (unsigned int)(((*(x)) << 16) + ((*(x + 1)) << 8) + (*(x + 2)))
85 #define FLV_UI16(x) (unsigned int)(((*(x)) << 8) + (*(x + 1)))
86 #define FLV_UI8(x) (unsigned int)(*(x))
87 #define FLV_TIMESTAMP(x) (int)(((*(x + 3)) << 24) + ((*(x)) << 16) + ((*(x + 1)) << 8) + (*(x + 2)))
88 
89 typedef struct {
90 	unsigned char *data;
91 	size_t size;
92 	size_t used;
93 } buffer_t;
94 
95 typedef struct {
96 	off_t offset;			// Offset from the beginning of the file
97 
98 	// FLV spec v10
99 	unsigned int tagtype;
100 	size_t datasize;		// Size of the data contained in this tag
101 	int timestamp;
102 	short keyframe;			// Is this tag a keyframe?
103 
104 	size_t tagsize;		// Size of the whole tag including header and data
105 } FLVTag_t;
106 
107 typedef struct {
108 	size_t nflvtags;
109 	FLVTag_t *flvtag;
110 } FLVIndex_t;
111 
112 typedef struct {
113 	FLVIndex_t index;
114 
115 	int hascuepoints;
116 	int canseektoend;			// Set to 1 if the last video frame is a keyframe
117 
118 	short hasaudio;
119 	struct {
120 		short analyzed;			// Are the audio specs complete and valid?
121 
122 		// Audio specs
123 		short codecid;
124 		short samplerate;
125 		short samplesize;
126 		short delay;
127 		short stereo;
128 
129 		// Calculated values
130 		size_t ntags;			// # of audio tags
131 		double datarate;		// datasize / duration
132 		uint64_t datasize;		// Size of the audio data
133 		uint64_t size;			// Size of the audio tags (header + data)
134 		int keyframerate;		// Store every x tags a keyframe. Only used for -a
135 		int keyframedistance;		// The time between two keyframes. Only used for -a
136 
137 		int lasttimestamp;
138 		size_t lastframeindex;
139 	} audio;
140 
141 	short hasvideo;
142 	struct {
143 		short analyzed;			// Are the video specs complete and valid?
144 
145 		// Video specs
146 		short codecid;
147 		int height;
148 		int width;
149 
150 		// Calculated values
151 		size_t ntags;			// # of video tags
152 		double framerate;		// ntags / duration
153 		double datarate;		// datasize / duration
154 		uint64_t datasize;		// Size of the video data
155 		uint64_t size;			// Size of the video tags (header + data)
156 
157 		int lasttimestamp;
158 		size_t lastframeindex;
159 	} video;
160 
161 	short haskeyframes;
162 	struct {
163 		size_t lastkeyframeindex;
164 		int lastkeyframetimestamp;
165 		off_t lastkeyframelocation;
166 
167 		size_t nkeyframes;		// # of key frames
168 		off_t *keyframelocations;	// Array of the filepositions of the keyframes (in the target file!)
169 		int *keyframetimestamps;	// Array of the timestamps of the keyframes
170 	} keyframes;
171 
172 	uint64_t datasize;			// Size of all audio and video tags (header + data + FLV_SIZE_PREVIOUSTAGSIZE)
173 	uint64_t filesize;			// [sic!]
174 
175 	int lasttimestamp;
176 
177 	int lastsecond;
178 	size_t lastsecondindex;
179 
180 	struct {
181 		char creator[256];		// -c
182 
183 		short addonlastkeyframe;	// -k
184 		short addonlastsecond;		// -s, -l (deprecated)
185 		short addonmetadata;		// defaults to 1, -M does change it
186 		short addaudiokeyframes;	// -a
187 
188 		short keepmetadata;		// -m (not implemented)
189 		short stripmetadata;		// -M
190 
191 		short xmlomitkeyframes;		// -X
192 
193 		short overwriteinput;		// -w
194 	} options;
195 
196 	buffer_t onmetadata;
197 	buffer_t onlastkeyframe;
198 	buffer_t onlastsecond;
199 } FLV_t;
200 
201 typedef struct {
202 	unsigned char *bytes;
203 	size_t length;
204 	size_t byte;
205 	short bit;
206 } bitstream_t;
207 
208 typedef struct {
209 	short valid;
210 	int width;
211 	int height;
212 } h264data_t;
213 
214 int validateFLV(FILE *fp);
215 int initFLV(FLV_t *flv);
216 int indexFLV(FLV_t *flv, FILE *fp);
217 int finalizeFLV(FLV_t *flv, FILE *fp);
218 int writeFLV(FILE *out, FLV_t *flv, FILE *fp);
219 int freeFLV(FLV_t *flv);
220 
221 void storeFLVFromStdin(FILE *fp);
222 int readFLVTag(FLVTag_t *flvtag, off_t offset, FILE *fp);
223 int readFLVTagData(unsigned char *ptr, size_t size, FLVTag_t *flvtag, FILE *stream);
224 
225 int analyzeFLV(FLV_t *flv, FILE *fp);
226 int analyzeFLVH263VideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp);
227 int analyzeFLVH264VideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp);
228 int analyzeFLVScreenVideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp);
229 int analyzeFLVVP6VideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp);
230 int analyzeFLVVP6AlphaVideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp);
231 
232 int createFLVEvents(FLV_t *flv);
233 int createFLVEventOnMetaData(FLV_t *flv);
234 int createFLVEventOnLastKeyframe(FLV_t *flv);
235 int createFLVEventOnLastSecond(FLV_t *flv);
236 
237 int writeBufferFLVScriptDataTag(buffer_t *buffer, int timestamp, size_t datasize);
238 int writeBufferFLVPreviousTagSize(buffer_t *buffer, size_t tagsize);
239 int writeBufferFLVScriptDataValueArray(buffer_t *buffer, const char *name, size_t len);
240 int writeBufferFLVScriptDataECMAArray(buffer_t *buffer, const char *name, size_t len);
241 int writeBufferFLVScriptDataVariableArray(buffer_t *buffer, const char *name);
242 int writeBufferFLVScriptDataVariableArrayEnd(buffer_t *buffer);
243 int writeBufferFLVScriptDataValueString(buffer_t *buffer, const char *name, const char *value);
244 int writeBufferFLVScriptDataValueBool(buffer_t *buffer, const char *name, int value);
245 int writeBufferFLVScriptDataValueDouble(buffer_t *buffer, const char *name, double value);
246 int writeBufferFLVScriptDataObject(buffer_t *buffer);
247 int writeBufferFLVScriptDataString(buffer_t *buffer, const char *s);
248 int writeBufferFLVScriptDataLongString(buffer_t *buffer, const char *s);
249 int writeBufferFLVBool(buffer_t *buffer, int value);
250 int writeBufferFLVDouble(buffer_t *buffer, double v);
251 
252 int writeFLVHeader(FILE *fp, int hasaudio, int hasvideo);
253 int writeFLVDataTag(FILE *fp, int type, int timestamp, size_t datasize);
254 int writeFLVPreviousTagSize(FILE *fp, size_t tagsize);
255 
256 void writeXMLMetadata(FILE *fp, const char *infile, const char *outfile, FLV_t *flv);
257 
258 int readBytes(unsigned char *ptr, size_t size, FILE *stream);
259 
260 int readH264NALUnit(h264data_t *h264data, unsigned char *nalu, int length);
261 void readH264SPS(h264data_t *h264data, bitstream_t *bitstream);
262 
263 unsigned int readCodedU(bitstream_t *bitstream, int nbits, const char *name);
264 unsigned int readCodedUE(bitstream_t *bitstream, const char *name);
265 int readCodedSE(bitstream_t *bitstream, const char *name);
266 
267 int readBits(bitstream_t *bitstream, int nbits);
268 int readBit(bitstream_t *bitstream);
269 
270 int bufferInit(buffer_t *buffer);
271 int bufferFree(buffer_t *buffer);
272 int bufferReset(buffer_t *buffer);
273 int bufferAppendBuffer(buffer_t *dst, buffer_t *src);
274 int bufferAppendString(buffer_t *dst, const unsigned char *string);
275 int bufferAppendBytes(buffer_t *dst, const unsigned char *bytes, size_t nbytes);
276 
277 int isBigEndian(void);
278 
279 void printUsage(void);
280 
main(int argc,char ** argv)281 int main(int argc, char **argv) {
282 	FILE *fp_infile = NULL, *fp_outfile = NULL, *fp_xmloutfile = NULL;
283 	int c, unlink_infile = 0;
284 	char *infile, *outfile, *xmloutfile, *tempfile, *creator;
285 	FLV_t flv;
286 
287 #ifdef DEBUG
288 	fprintf(stderr, "[core] sizeof size_t = %d\n", (int)sizeof(size_t));
289 	fprintf(stderr, "[core] sizeof off_t = %d\n", (int)sizeof(off_t));
290 	fprintf(stderr, "[core] sizeof uint64_t = %d\n", (int)sizeof(uint64_t));
291 	fprintf(stderr, "[core] sizeof long long = %d\n", (int)sizeof(long long));
292 	fprintf(stderr, "[core] sizeof double = %d\n", (int)sizeof(double));
293 #endif
294 
295 	opterr = 0;
296 
297 	infile = NULL;
298 	outfile = NULL;
299 	xmloutfile = NULL;
300 	tempfile = NULL;
301 	creator = NULL;
302 
303 	initFLV(&flv);
304 
305 	while((c = getopt(argc, argv, ":i:o:x:t:c:a:lskMXwh")) != -1) {
306 		switch(c) {
307 			case 'i':
308 				infile = optarg;
309 				break;
310 			case 'o':
311 				outfile = optarg;
312 				break;
313 			case 'x':
314 				xmloutfile = optarg;
315 				break;
316 			case 't':
317 				tempfile = optarg;
318 				break;
319 			case 'c':
320 				strncpy(flv.options.creator, optarg, sizeof(flv.options.creator));
321 				break;
322 			case 'l':
323 			case 's':
324 				flv.options.addonlastsecond = 1;
325 				break;
326 			case 'k':
327 				flv.options.addonlastkeyframe = 1;
328 				break;
329 			case 'a':
330 				flv.options.addaudiokeyframes = 1;
331 				flv.audio.keyframedistance = (int)strtol(optarg, (char **)NULL, 10);
332 				if(flv.audio.keyframedistance <= 0) {
333 					flv.audio.keyframedistance = 0;
334 					flv.options.addaudiokeyframes = 0;
335 				}
336 				break;
337 /*
338 			case 'm':
339 				flv.options.keepmetadata = 1;
340 				break;
341 */
342 			case 'M':
343 				flv.options.stripmetadata = 1;
344 				break;
345 			case 'X':
346 				flv.options.xmlomitkeyframes = 1;
347 				break;
348 			case 'w':
349 				flv.options.overwriteinput = 1;
350 				break;
351 			case 'h':
352 				printUsage();
353 				exit(YAMDI_ERROR);
354 				break;
355 			case ':':
356 				fprintf(stderr, "The option -%c expects a parameter. -h for help.\n", optopt);
357 				exit(YAMDI_ERROR);
358 				break;
359 			case '?':
360 				fprintf(stderr, "Unknown option: -%c. -h for help.\n", optopt);
361 				exit(YAMDI_ERROR);
362 				break;
363 			default:
364 				printUsage();
365 				exit(YAMDI_ERROR);
366 				break;
367 		}
368 	}
369 
370 	if(infile == NULL) {
371 		fprintf(stderr, "Please use -i to provide an input file. -h for help.\n");
372 		exit(YAMDI_ERROR);
373 	}
374 
375 	if(outfile == NULL && xmloutfile == NULL) {
376 		fprintf(stderr, "Please use -o or -x to provide at least one output file. -h for help.\n");
377 		exit(YAMDI_ERROR);
378 	}
379 
380 	if(tempfile == NULL && !strcmp(infile, "-")) {
381 		fprintf(stderr, "Please use -t to specify a temporary file. -h for help.\n");
382 		exit(YAMDI_ERROR);
383 	}
384 
385 	// Check input file
386 	if(!strcmp(infile, "-")) {		// Read from stdin
387 		// tempfile is available
388 		// Check if the possible outfiles collide with the tempfile
389 		if(outfile != NULL) {
390 			if(!strcmp(tempfile, outfile)) {
391 				fprintf(stderr, "The temporary file and the output file must not be the same.\n");
392 				exit(YAMDI_ERROR);
393 			}
394 		}
395 
396 		if(xmloutfile != NULL) {
397 			if(!strcmp(tempfile, xmloutfile)) {
398 				fprintf(stderr, "The temporary file and the XML output file must not be the same.\n");
399 				exit(YAMDI_ERROR);
400 			}
401 		}
402 	}
403 	else {					// Read from file
404 		// infile is available
405 		// Check if the possible outfile collide with the infile
406 		if(outfile != NULL) {
407 			if(!strcmp(infile, outfile)) {
408 				fprintf(stderr, "The input file and the output file must not be the same.\n");
409 				exit(YAMDI_ERROR);
410 			}
411 		}
412 
413 		if(xmloutfile != NULL) {
414 			if(!strcmp(infile, xmloutfile)) {
415 				fprintf(stderr, "The input file and the XML output file must not be the same.\n");
416 				exit(YAMDI_ERROR);
417 			}
418 		}
419 	}
420 
421 	// Check output file
422 	if(outfile != NULL) {
423 		if(xmloutfile != NULL) {
424 			if(!strcmp(outfile, xmloutfile)) {
425 				fprintf(stderr, "The output file and the XML output file must not be the same.\n");
426 				exit(YAMDI_ERROR);
427 			}
428 		}
429 	}
430 
431 	// All checks are done. Open the files.
432 
433 	// Open the inputfile
434 	// Store data to tempfile if inputfile is stdin
435 	if(!strcmp(infile, "-")) {
436 		fp_infile = fopen(tempfile, "wb");
437 		if(fp_infile == NULL) {
438 			fprintf(stderr, "Couldn't open the tempfile %s.\n", tempfile);
439 			exit(YAMDI_ERROR);
440 		}
441 
442 		// Store stdin to temporary file
443 		storeFLVFromStdin(fp_infile);
444 
445 		// Close temporary file
446 		fclose(fp_infile);
447 
448 		// Mimic normal input file, but don't forget to remove the temporary file
449 		infile = tempfile;
450 		unlink_infile = 1;
451 	}
452 
453 	fp_infile = fopen(infile, "rb");
454 	if(fp_infile == NULL) {
455 		if(unlink_infile == 1)
456 			unlink(infile);
457 
458 		exit(YAMDI_ERROR);
459 	}
460 
461 	// Check if we have a valid FLV file
462 	if(validateFLV(fp_infile) != YAMDI_OK) {
463 		fclose(fp_infile);
464 
465 		if(unlink_infile == 1)
466 			unlink(infile);
467 
468 		exit(YAMDI_ERROR);
469 	}
470 
471 	// Open the outfile
472 	fp_outfile = NULL;
473 	if(outfile != NULL) {
474 		if(strcmp(outfile, "-")) {
475 			fp_outfile = fopen(outfile, "wb");
476 			if(fp_outfile == NULL) {
477 				fprintf(stderr, "Couldn't open %s.\n", outfile);
478 
479 				if(unlink_infile == 1)
480 					unlink(infile);
481 
482 				exit(YAMDI_ERROR);
483 			}
484 		}
485 		else
486 			fp_outfile = stdout;
487 	}
488 
489 	// Open the XML outputfile
490 	fp_xmloutfile = NULL;
491 	if(xmloutfile != NULL) {
492 		if(strcmp(xmloutfile, "-")) {
493 			fp_xmloutfile = fopen(xmloutfile, "wb");
494 			if(fp_xmloutfile == NULL) {
495 				fprintf(stderr, "Couldn't open %s.\n", xmloutfile);
496 
497 				if(unlink_infile == 1)
498 					unlink(infile);
499 
500 				exit(YAMDI_ERROR);
501 			}
502 		}
503 		else
504 			fp_xmloutfile = stdout;
505 	}
506 
507 	// Check the options
508 	if(flv.options.stripmetadata == 1) {
509 		flv.options.addonlastkeyframe = 0;
510 		flv.options.addonlastsecond = 0;
511 		flv.options.addonmetadata = 0;
512 	}
513 	else
514 		flv.options.addonmetadata = 1;
515 
516 	// Create an index of the FLV file
517 	if(indexFLV(&flv, fp_infile) != YAMDI_OK) {
518 		fclose(fp_infile);
519 
520 		if(unlink_infile == 1)
521 			unlink(infile);
522 
523 		exit(YAMDI_ERROR);
524 	}
525 
526 	if(analyzeFLV(&flv, fp_infile) != YAMDI_OK) {
527 		fclose(fp_infile);
528 
529 		if(unlink_infile == 1)
530 			unlink(infile);
531 
532 		exit(YAMDI_ERROR);
533 	}
534 
535 	if(finalizeFLV(&flv, fp_infile) != YAMDI_OK) {
536 		fclose(fp_infile);
537 
538 		if(unlink_infile == 1)
539 			unlink(infile);
540 
541 		exit(YAMDI_ERROR);
542 	}
543 
544 #ifdef DEBUG
545 	fprintf(stderr, "[FLV] onmetadata = %d bytes (%d bytes allocated)\n", flv.onmetadata.used, flv.onmetadata.size);
546 	fprintf(stderr, "[FLV] onlastsecond = %d bytes (%d bytes allocated)\n", flv.onlastsecond.used, flv.onlastsecond.size);
547 	fprintf(stderr, "[FLV] onlastkeyframe = %d bytes (%d bytes allocated)\n", flv.onlastkeyframe.used, flv.onlastkeyframe.size);
548 #endif
549 
550 	if(fp_outfile != NULL)
551 		writeFLV(fp_outfile, &flv, fp_infile);
552 
553 	if(fp_xmloutfile != NULL)
554 		writeXMLMetadata(fp_xmloutfile, infile, outfile, &flv);
555 
556 	fclose(fp_infile);
557 
558 	// Remove the input file if it is the temporary file
559 	if(unlink_infile == 1)
560 		unlink(infile);
561 
562 	if(fp_outfile != NULL && fp_outfile != stdout)
563 		fclose(fp_outfile);
564 
565 	if(fp_xmloutfile != NULL && fp_xmloutfile != stdout)
566 		fclose(fp_xmloutfile);
567 
568 	if(flv.options.overwriteinput == 1 && strcmp(infile, "-") && outfile != NULL && strcmp(outfile, "-")) {
569 		if(rename(outfile, infile) != 0)
570 			exit(YAMDI_RENAME_OUTPUT);
571 	}
572 
573 	freeFLV(&flv);
574 
575 	return YAMDI_OK;
576 }
577 
validateFLV(FILE * fp)578 int validateFLV(FILE *fp) {
579 	unsigned char buffer[FLV_SIZE_HEADER + FLV_SIZE_PREVIOUSTAGSIZE];
580 	off_t filesize;
581 
582 	fseeko(fp, 0, SEEK_END);
583 	filesize = ftello(fp);
584 
585 	// Check for minimal FLV file length
586 	if(filesize < (FLV_SIZE_HEADER + FLV_SIZE_PREVIOUSTAGSIZE))
587 		return YAMDI_FILE_TOO_SMALL;
588 
589 	rewind(fp);
590 
591 	if(readBytes(buffer, FLV_SIZE_HEADER + FLV_SIZE_PREVIOUSTAGSIZE, fp) != YAMDI_OK)
592 		return YAMDI_READ_ERROR;
593 
594 	// Check the FLV signature
595 	if(buffer[0] != 'F' || buffer[1] != 'L' || buffer[2] != 'V')
596 		return YAMDI_INVALID_SIGNATURE;
597 
598 	// Check the FLV version
599 	if(FLV_UI8(&buffer[3]) != 1)
600 		return YAMDI_INVALID_FLVVERSION;
601 
602 	// Check the DataOffset
603 	if(FLV_UI32(&buffer[5]) != FLV_SIZE_HEADER)
604 		return YAMDI_INVALID_DATASIZE;
605 
606 	// Check the PreviousTagSize0 value
607 	if(FLV_UI32(&buffer[FLV_SIZE_HEADER]) != 0)
608 		return YAMDI_INVALID_PREVIOUSTAGSIZE;
609 
610 	return YAMDI_OK;
611 }
612 
initFLV(FLV_t * flv)613 int initFLV(FLV_t *flv) {
614 	if(flv == NULL)
615 		return YAMDI_ERROR;
616 
617 	memset(flv, 0, sizeof(FLV_t));
618 
619 	return YAMDI_OK;
620 }
621 
indexFLV(FLV_t * flv,FILE * fp)622 int indexFLV(FLV_t *flv, FILE *fp) {
623 	off_t offset;
624 	size_t nflvtags;
625 	FLVTag_t flvtag;
626 
627 #ifdef DEBUG
628 	fprintf(stderr, "[FLV] indexing file ...\n");
629 #endif
630 
631 	// Count how many tags are there in this FLV
632 	offset = FLV_SIZE_HEADER + FLV_SIZE_PREVIOUSTAGSIZE;
633 	nflvtags = 0;
634 	while(readFLVTag(&flvtag, offset, fp) == YAMDI_OK) {
635 		offset += (flvtag.tagsize + FLV_SIZE_PREVIOUSTAGSIZE);
636 
637 		nflvtags++;
638 	}
639 
640 	flv->index.nflvtags = nflvtags;
641 
642 #ifdef DEBUG
643 	fprintf(stderr, "[FLV] nflvtags = %d\n", flv->index.nflvtags);
644 #endif
645 
646 	if(nflvtags == 0)
647 		return YAMDI_OK;
648 
649 	// Allocate memory for the tag metadata index
650 	flv->index.flvtag = (FLVTag_t *)calloc(flv->index.nflvtags, sizeof(FLVTag_t));
651 	if(flv->index.flvtag == NULL)
652 		return YAMDI_OUT_OF_MEMORY;
653 
654 	// Store the tag metadata in the index
655 	offset = FLV_SIZE_HEADER + FLV_SIZE_PREVIOUSTAGSIZE;
656 	nflvtags = 0;
657 	while(readFLVTag(&flvtag, offset, fp) == YAMDI_OK) {
658 		flv->index.flvtag[nflvtags].offset = flvtag.offset;
659 		flv->index.flvtag[nflvtags].tagtype = flvtag.tagtype;
660 		flv->index.flvtag[nflvtags].datasize = flvtag.datasize;
661 		flv->index.flvtag[nflvtags].timestamp = flvtag.timestamp;
662 		flv->index.flvtag[nflvtags].tagsize = flvtag.tagsize;
663 
664 		offset += (flv->index.flvtag[nflvtags].tagsize + FLV_SIZE_PREVIOUSTAGSIZE);
665 
666 		nflvtags++;
667 #ifdef DEBUG
668 		if((nflvtags % 100) == 0)
669 			fprintf(stderr, "[FLV] storing metadata (tag %d of %d)\r", nflvtags, flv->index.nflvtags);
670 #endif
671 	}
672 
673 #ifdef DEBUG
674 	fprintf(stderr, "[FLV] storing metadata (tag %d of %d)\n", nflvtags, flv->index.nflvtags);
675 #endif
676 
677 	return YAMDI_OK;
678 }
679 
storeFLVFromStdin(FILE * fp)680 void storeFLVFromStdin(FILE *fp) {
681 	char buf[4096];
682 	size_t bytes;
683 
684 	while((bytes = fread(buf, 1, sizeof(buf), stdin)) > 0)
685 		fwrite(buf, 1, bytes, fp);
686 
687 	return;
688 }
689 
freeFLV(FLV_t * flv)690 int freeFLV(FLV_t *flv) {
691 	if(flv->index.nflvtags != 0)
692 		free(flv->index.flvtag);
693 
694 	if(flv->keyframes.keyframelocations != NULL)
695 		free(flv->keyframes.keyframelocations);
696 
697 	if(flv->keyframes.keyframetimestamps != NULL)
698 		free(flv->keyframes.keyframetimestamps);
699 
700 	bufferFree(&flv->onmetadata);
701 	bufferFree(&flv->onlastsecond);
702 	bufferFree(&flv->onlastkeyframe);
703 
704 	memset(flv, 0, sizeof(FLV_t));
705 
706 	return YAMDI_OK;
707 }
708 
analyzeFLV(FLV_t * flv,FILE * fp)709 int analyzeFLV(FLV_t *flv, FILE *fp) {
710 	int rv;
711 	size_t i, index;
712 	unsigned char flags;
713 	FLVTag_t *flvtag;
714 
715 #ifdef DEBUG
716 	fprintf(stderr, "[FLV] analyzing FLV ...\n");
717 #endif
718 
719 	for(i = 0; i < flv->index.nflvtags; i++) {
720 		flvtag = &flv->index.flvtag[i];
721 
722 		if(flvtag->tagtype == FLV_TAG_AUDIO) {
723 			flv->hasaudio = 1;
724 
725 			flv->audio.ntags++;
726 			flv->audio.datasize += flvtag->datasize;
727 			flv->audio.size += flvtag->tagsize;
728 
729 			flv->audio.lasttimestamp = flvtag->timestamp;
730 			flv->audio.lastframeindex = i;
731 
732 			readFLVTagData(&flags, 1, flvtag, fp);
733 
734 			if(flv->audio.analyzed == 0) {
735 				// SoundFormat
736 				flv->audio.codecid = (flags >> 4) & 0xf;
737 
738 				// SoundRate
739 				flv->audio.samplerate = (flags >> 2) & 0x3;
740 
741 				// SoundSize
742 				flv->audio.samplesize = (flags >> 1) & 0x1;
743 
744 				// SoundType
745 				flv->audio.stereo = flags & 0x1;
746 
747 				if(flv->audio.codecid == 4 || flv->audio.codecid == 5 || flv->audio.codecid == 6) {
748 					// Nellymoser
749 					flv->audio.stereo = 0;
750 				}
751 				else if(flv->audio.codecid == 10) {
752 					// AAC
753 					flv->audio.samplerate = 3;
754 					flv->audio.stereo = 1;
755 				}
756 
757 				flv->audio.analyzed = 1;
758 			}
759 		}
760 		else if(flvtag->tagtype == FLV_TAG_VIDEO) {
761 			flv->hasvideo = 1;
762 
763 			flv->video.ntags++;
764 			flv->video.datasize += flvtag->datasize;
765 			flv->video.size += flvtag->tagsize;
766 
767 			flv->video.lasttimestamp = flvtag->timestamp;
768 			flv->video.lastframeindex = i;
769 
770 			readFLVTagData(&flags, 1, flvtag, fp);
771 
772 			// Keyframes
773 			flvtag->keyframe = (flags >> 4) & 0xf;
774 			if(flvtag->keyframe == 1) {
775 				flv->canseektoend = 1;
776 				flv->keyframes.nkeyframes++;
777 				flv->keyframes.lastkeyframeindex = i;
778 			}
779 			else
780 				flv->canseektoend = 0;
781 
782 			if(flvtag->keyframe == 1 && flv->video.analyzed == 0) {
783 				// Video Codec
784 				flv->video.codecid = flags & 0xf;
785 
786 				switch(flv->video.codecid) {
787 					case FLV_PACKET_H263VIDEO:
788 						rv = analyzeFLVH263VideoPacket(flv, flvtag, fp);
789 						break;
790 					case FLV_PACKET_SCREENVIDEO:
791 						rv = analyzeFLVScreenVideoPacket(flv, flvtag, fp);
792 						break;
793 					case FLV_PACKET_VP6VIDEO:
794 						rv = analyzeFLVVP6VideoPacket(flv, flvtag, fp);
795 						break;
796 					case FLV_PACKET_VP6ALPHAVIDEO:
797 						rv = analyzeFLVVP6AlphaVideoPacket(flv, flvtag, fp);
798 						break;
799 					case FLV_PACKET_SCREENV2VIDEO:
800 						rv = analyzeFLVScreenVideoPacket(flv, flvtag, fp);
801 						break;
802 					case FLV_PACKET_H264VIDEO:
803 						rv = analyzeFLVH264VideoPacket(flv, flvtag, fp);
804 						break;
805 					default:
806 						rv = YAMDI_ERROR;
807 						break;
808 				}
809 
810 				if(rv == YAMDI_OK)
811 					flv->video.analyzed = 1;
812 			}
813 		}
814 
815 		flv->lasttimestamp = flvtag->timestamp;
816 
817 #ifdef DEBUG
818 		if((i % 100) == 0)
819 			fprintf(stderr, "[FLV] analyzing FLV (tag %d of %d)\r", i, flv->index.nflvtags);
820 #endif
821 	}
822 
823 #ifdef DEBUG
824 	fprintf(stderr, "[FLV] analyzing FLV (tag %d of %d)\n", i, flv->index.nflvtags);
825 
826 	fprintf(stderr, "[FLV] lasttimestamp = %d ms\n", flv->lasttimestamp);
827 #endif
828 
829 	// Calculate the last second
830 	if(flv->lasttimestamp >= 1000) {
831 		flv->lastsecond = flv->lasttimestamp - 1000;
832 		for(i = (flv->index.nflvtags - 1); i >= 0; i--) {
833 			flvtag = &flv->index.flvtag[i];
834 
835 			if(flvtag->timestamp <= flv->lastsecond) {
836 				flv->lastsecond += 1;
837 				flv->lastsecondindex = i;
838 
839 				break;
840 			}
841 		}
842 	}
843 	else
844 		flv->options.addonlastsecond = 0;
845 
846 #ifdef DEBUG
847 	fprintf(stderr, "[FLV] lastsecond = %d ms\n", flv->lastsecond);
848 	fprintf(stderr, "[FLV] lastsecondindex = %d\n", flv->lastsecondindex);
849 #endif
850 
851 	// Calculate audio datarate
852 	if(flv->audio.datasize != 0)
853 		flv->audio.datarate = (double)flv->audio.datasize * 8.0 / 1024.0 / (double)flv->audio.lasttimestamp * 1000.0;
854 
855 #ifdef DEBUG
856 	fprintf(stderr, "[FLV] audio.codecid = %d\n", flv->audio.codecid);
857 	fprintf(stderr, "[FLV] audio.lasttimestamp = %d ms\n", flv->audio.lasttimestamp);
858 	fprintf(stderr, "[FLV] audio.lastframeindex = %d\n", flv->audio.lastframeindex);
859 	fprintf(stderr, "[FLV] audio.ntags = %d\n", flv->audio.ntags);
860 	fprintf(stderr, "[FLV] audio.datasize = %" PRIu64 " kb\n", flv->audio.datasize);
861 	fprintf(stderr, "[FLV] audio.datarate = %f kbit/s\n", flv->audio.datarate);
862 #endif
863 
864 	// Calculate video framerate
865 	if(flv->video.ntags != 0)
866 		flv->video.framerate = (double)flv->video.ntags / (double)flv->video.lasttimestamp * 1000.0;
867 
868 	// Calculate video datarate
869 	if(flv->video.datasize != 0)
870 		flv->video.datarate = (double)flv->video.datasize * 8.0 / 1024.0 / (double)flv->lasttimestamp * 1000.0;
871 
872 #ifdef DEBUG
873 	fprintf(stderr, "[FLV] video.codecid = %d\n", flv->video.codecid);
874 	fprintf(stderr, "[FLV] video.lasttimestamp = %d ms\n", flv->video.lasttimestamp);
875 	fprintf(stderr, "[FLV] video.lastframeindex = %d\n", flv->video.lastframeindex);
876 	fprintf(stderr, "[FLV] video.ntags = %d\n", flv->video.ntags);
877 	fprintf(stderr, "[FLV] video.framerate = %f fps\n", flv->video.framerate);
878 	fprintf(stderr, "[FLV] video.datasize = %" PRIu64 " kb\n", flv->video.datasize);
879 	fprintf(stderr, "[FLV] video.datarate = %f kbit/s\n", flv->video.datarate);
880 	fprintf(stderr, "[FLV] video.width = %d\n", flv->video.width);
881 	fprintf(stderr, "[FLV] video.height = %d\n", flv->video.height);
882 #endif
883 
884 	// Calculate datasize
885 	flv->datasize = flv->audio.size + (flv->audio.ntags * FLV_SIZE_PREVIOUSTAGSIZE) + flv->video.size + (flv->video.ntags * FLV_SIZE_PREVIOUSTAGSIZE);
886 
887 #ifdef DEBUG
888 	fprintf(stderr, "[FLV] datasize = %" PRIu64 " kb\n", flv->datasize);
889 #endif
890 
891 	// Fake keyframes if we have only audio and the corresponding option has been set
892 	if(flv->options.addaudiokeyframes == 1 && flv->hasaudio == 1 && flv->hasvideo == 0) {
893 		// Add a keyframe at least every x milliseconds
894 		flv->audio.keyframerate = (int)((double)flv->audio.keyframedistance / (double)flv->audio.lasttimestamp * (double)flv->audio.ntags);
895 
896 		// If every frame is longer than the intervalthen add every frame a keyframe
897 		if(flv->audio.keyframerate == 0)
898 			flv->audio.keyframerate = 1;
899 		else if(flv->audio.keyframerate >= flv->audio.ntags)
900 			flv->audio.keyframerate = flv->audio.ntags;
901 
902 #ifdef DEBUG
903 		fprintf(stderr, "[FLV] audio.keyframerate = %d\n", flv->audio.keyframerate);
904 #endif
905 
906 		// Mark all audio tags that should be considered as a keyframe
907 		index = 0;
908 		for(i = 0; i < flv->index.nflvtags; i++) {
909 			flvtag = &flv->index.flvtag[i];
910 
911 			if(flvtag->tagtype == FLV_TAG_AUDIO) {
912 				if((index % flv->audio.keyframerate) == 0) {
913 					flvtag->keyframe = 1;
914 					flv->keyframes.nkeyframes++;
915 				}
916 
917 				index++;
918 			}
919 		}
920 
921 		// Add an extra keyframe for the last frame
922 		if(flv->index.flvtag[flv->audio.lastframeindex].keyframe == 0) {
923 			flv->index.flvtag[flv->audio.lastframeindex].keyframe = 1;
924 			flv->keyframes.nkeyframes++;
925 		}
926 
927 		flv->canseektoend = 1;
928 		flv->keyframes.lastkeyframeindex = flv->audio.lastframeindex;
929 	}
930 	else
931 		flv->options.addaudiokeyframes = 0;
932 
933 #ifdef DEBUG
934 	fprintf(stderr, "[FLV] keyframes.nkeyframes = %d\n", flv->keyframes.nkeyframes);
935 	fprintf(stderr, "[FLV] keyframes.lastkeyframeindex = %d\n", flv->keyframes.lastkeyframeindex);
936 #endif
937 
938 	// Allocate some memory for the keyframe index
939 	if(flv->keyframes.nkeyframes != 0) {
940 		flv->haskeyframes = 1;
941 
942 		flv->keyframes.keyframelocations = (off_t *)calloc(flv->keyframes.nkeyframes, sizeof(off_t));
943 		if(flv->keyframes.keyframelocations == NULL)
944 			return YAMDI_OUT_OF_MEMORY;
945 
946 		flv->keyframes.keyframetimestamps = (int *)calloc(flv->keyframes.nkeyframes, sizeof(int));
947 		if(flv->keyframes.keyframetimestamps == NULL)
948 			return YAMDI_OUT_OF_MEMORY;
949 	}
950 
951 	return YAMDI_OK;
952 }
953 
finalizeFLV(FLV_t * flv,FILE * fp)954 int finalizeFLV(FLV_t *flv, FILE *fp) {
955 	size_t i, index;
956 	FLVTag_t *flvtag;
957 
958 	// 2 passes
959 	// 1. create onmetadata event to get the size of it (it doesn't matter if the values are not yet correct)
960 	// 2. calculate the new keyframelocations and the final filesize
961 	//    pay attention to the size of these events
962 	//        onmetadata
963 	//        onlastsecond
964 	//        onlastkeyframe
965 	//        (oncuepoint) keep them from the input flv?
966 	// 3. recreate the onmetadata event with the correct values
967 	// filesize
968 	// keyframelocations
969 	// lastkeyframelocation
970 
971 	// Create the metadata tags. Even though we don't have all values,
972 	// the size will not change. We need the size.
973 	createFLVEvents(flv);
974 
975 	// Start calculating the final filesize
976 	flv->filesize = 0;
977 
978 	// FLV header + PreviousTagSize
979 	flv->filesize += FLV_SIZE_HEADER + FLV_SIZE_PREVIOUSTAGSIZE;
980 
981 	// onMetaData event
982 	if(flv->options.addonmetadata == 1)
983 		flv->filesize += flv->onmetadata.used;
984 
985 	// Calculate the final filesize and update the keyframe index
986 	index = 0;
987 	for(i = 0; i < flv->index.nflvtags; i++) {
988 		flvtag = &flv->index.flvtag[i];
989 
990 		// Skip every script tag (subject to change if we want to keep existing events)
991 		if(flvtag->tagtype != FLV_TAG_AUDIO && flvtag->tagtype != FLV_TAG_VIDEO)
992 			continue;
993 
994 		// Take care of the onlastsecond event
995 		if(flv->options.addonlastsecond == 1 && flv->lastsecondindex == i)
996 			flv->filesize += flv->onlastsecond.used;
997 
998 		// Update the keyframe index only if there are keyframes ...
999 		if(flv->haskeyframes == 1) {
1000 			if(flvtag->tagtype == FLV_TAG_VIDEO || flvtag->tagtype == FLV_TAG_AUDIO) {
1001 				// Keyframes
1002 				if(flvtag->keyframe == 1) {
1003 					// Take care of the onlastkeyframe event
1004 					if(flv->options.addonlastkeyframe == 1 && flv->keyframes.lastkeyframeindex == i)
1005 						flv->filesize += flv->onlastkeyframe.used;
1006 
1007 					flv->keyframes.keyframelocations[index] = flv->filesize;
1008 					flv->keyframes.keyframetimestamps[index] = flvtag->timestamp;
1009 
1010 					index++;
1011 				}
1012 			}
1013 		}
1014 
1015 		flv->filesize += flvtag->tagsize + FLV_SIZE_PREVIOUSTAGSIZE;
1016 	}
1017 
1018 	if(flv->haskeyframes == 1) {
1019 		flv->keyframes.lastkeyframetimestamp = flv->keyframes.keyframetimestamps[flv->keyframes.nkeyframes - 1];
1020 		flv->keyframes.lastkeyframelocation = flv->keyframes.keyframelocations[flv->keyframes.nkeyframes - 1];
1021 	}
1022 
1023 #ifdef DEBUG
1024 	fprintf(stderr, "[FLV] keyframes.lastkeyframetimestamp = %d ms\n", flv->keyframes.lastkeyframetimestamp);
1025 	fprintf(stderr, "[FLV] keyframes.lastkeyframelocation = %" PRIi64 "\n", flv->keyframes.lastkeyframelocation);
1026 
1027 	fprintf(stderr, "[FLV] filesize = %" PRIu64 " kb\n", flv->filesize);
1028 #endif
1029 
1030 	// Create the metadata tags with the correct values
1031 	createFLVEvents(flv);
1032 
1033 	return YAMDI_OK;
1034 }
1035 
writeFLV(FILE * out,FLV_t * flv,FILE * fp)1036 int writeFLV(FILE *out, FLV_t *flv, FILE *fp) {
1037 	size_t i, datasize = 0;
1038 	unsigned char *data = NULL, *d;
1039 	FLVTag_t *flvtag;
1040 
1041 	if(fp == NULL)
1042 		return YAMDI_ERROR;
1043 
1044 	// Write the header
1045 	writeFLVHeader(out, flv->hasaudio, flv->hasvideo);
1046 	writeFLVPreviousTagSize(out, 0);
1047 
1048 	// Write the onMetaData tag
1049 	if(flv->options.addonmetadata == 1)
1050 		fwrite(flv->onmetadata.data, flv->onmetadata.used, 1, out);
1051 
1052 	// Copy the audio and video tags
1053 	for(i = 0; i < flv->index.nflvtags; i++) {
1054 		flvtag = &flv->index.flvtag[i];
1055 
1056 		// Skip every script tag (subject to change if we want to keep existing events)
1057 		if(flvtag->tagtype != FLV_TAG_AUDIO && flvtag->tagtype != FLV_TAG_VIDEO)
1058 			continue;
1059 
1060 		// Write the onlastsecond event
1061 		if(flv->options.addonlastsecond == 1 && flv->lastsecondindex == i)
1062 			fwrite(flv->onlastsecond.data, flv->onlastsecond.used, 1, out);
1063 
1064 		// Write the onlastkeyframe event
1065 		if(flv->options.addonlastkeyframe == 1 && flv->keyframes.lastkeyframeindex == i)
1066 			fwrite(flv->onlastkeyframe.data, flv->onlastkeyframe.used, 1, out);
1067 
1068 		writeFLVDataTag(out, flvtag->tagtype, flvtag->timestamp, flvtag->datasize);
1069 
1070 		// Read the data
1071 		if(flvtag->datasize > datasize) {
1072 			d = (unsigned char *)realloc(data, flvtag->datasize);
1073 			if(d == NULL)
1074 				return YAMDI_OUT_OF_MEMORY;
1075 
1076 			data = d;
1077 			datasize = flvtag->datasize;
1078 		}
1079 
1080 		if(readFLVTagData(data, flvtag->datasize, flvtag, fp) != YAMDI_OK)
1081 			return YAMDI_READ_ERROR;
1082 
1083 		fwrite(data, flvtag->datasize, 1, out);
1084 
1085 		writeFLVPreviousTagSize(out, flvtag->tagsize);
1086 	}
1087 
1088 	if(data != NULL)
1089 		free(data);
1090 
1091 	// We are done!
1092 
1093 	return YAMDI_OK;
1094 }
1095 
writeFLVHeader(FILE * fp,int hasaudio,int hasvideo)1096 int writeFLVHeader(FILE *fp, int hasaudio, int hasvideo) {
1097 	unsigned char bytes[FLV_SIZE_HEADER];
1098 
1099 	// Signature
1100 	bytes[0] = 'F';
1101 	bytes[1] = 'L';
1102 	bytes[2] = 'V';
1103 
1104 	// Version
1105 	bytes[3] = 1;
1106 
1107 	// Flags
1108 	bytes[4] = 0;
1109 
1110 	if(hasaudio == 1)
1111 		bytes[4] |= 0x4;
1112 
1113 	if(hasvideo == 1)
1114 		bytes[4] |= 0x1;
1115 
1116 	// DataOffset
1117 	bytes[5] = ((FLV_SIZE_HEADER >> 24) & 0xff);
1118 	bytes[6] = ((FLV_SIZE_HEADER >> 16) & 0xff);
1119 	bytes[7] = ((FLV_SIZE_HEADER >>  8) & 0xff);
1120 	bytes[8] = ((FLV_SIZE_HEADER >>  0) & 0xff);
1121 
1122 	fwrite(bytes, FLV_SIZE_HEADER, 1, fp);
1123 
1124 	return YAMDI_OK;
1125 }
1126 
createFLVEvents(FLV_t * flv)1127 int createFLVEvents(FLV_t *flv) {
1128 	if(flv->options.addonmetadata == 1)
1129 		createFLVEventOnMetaData(flv);
1130 
1131 	if(flv->options.addonlastkeyframe == 1)
1132 		createFLVEventOnLastKeyframe(flv);
1133 
1134 	if(flv->options.addonlastsecond == 1)
1135 		createFLVEventOnLastSecond(flv);
1136 
1137 	return YAMDI_OK;
1138 }
1139 
createFLVEventOnMetaData(FLV_t * flv)1140 int createFLVEventOnMetaData(FLV_t *flv) {
1141 	int pass = 0;
1142 	size_t i, length = 0;
1143 	buffer_t b;
1144 
1145 	bufferInit(&b);
1146 
1147 onmetadatapass:
1148 	bufferReset(&b);
1149 
1150 	// ScriptDataObject
1151 	writeBufferFLVScriptDataObject(&b);
1152 
1153 	writeBufferFLVScriptDataECMAArray(&b, "onMetaData", length);
1154 
1155 	length = 0;
1156 
1157 	if(strlen(flv->options.creator) != 0) {
1158 		writeBufferFLVScriptDataValueString(&b, "creator", flv->options.creator); length++;
1159 	}
1160 
1161 	writeBufferFLVScriptDataValueString(&b, "metadatacreator", "Yet Another Metadata Injector for FLV - Version " YAMDI_VERSION "\0"); length++;
1162 	writeBufferFLVScriptDataValueBool(&b, "hasKeyframes", flv->haskeyframes); length++;
1163 	writeBufferFLVScriptDataValueBool(&b, "hasVideo", flv->hasvideo); length++;
1164 	writeBufferFLVScriptDataValueBool(&b, "hasAudio", flv->hasaudio); length++;
1165 	writeBufferFLVScriptDataValueBool(&b, "hasMetadata", 1); length++;
1166 	writeBufferFLVScriptDataValueBool(&b, "canSeekToEnd", flv->canseektoend); length++;
1167 
1168 	writeBufferFLVScriptDataValueDouble(&b, "duration", (double)flv->lasttimestamp / 1000.0); length++;
1169 	writeBufferFLVScriptDataValueDouble(&b, "datasize", (double)flv->datasize); length++;
1170 
1171 	if(flv->hasvideo == 1) {
1172 		writeBufferFLVScriptDataValueDouble(&b, "videosize", (double)flv->video.size); length++;
1173 		writeBufferFLVScriptDataValueDouble(&b, "framerate", (double)flv->video.framerate); length++;
1174 		writeBufferFLVScriptDataValueDouble(&b, "videodatarate", (double)flv->video.datarate); length++;
1175 
1176 		if(flv->video.analyzed == 1) {
1177 			writeBufferFLVScriptDataValueDouble(&b, "videocodecid", (double)flv->video.codecid); length++;
1178 			writeBufferFLVScriptDataValueDouble(&b, "width", (double)flv->video.width); length++;
1179 			writeBufferFLVScriptDataValueDouble(&b, "height", (double)flv->video.height); length++;
1180 		}
1181 	}
1182 
1183 	if(flv->hasaudio == 1) {
1184 		writeBufferFLVScriptDataValueDouble(&b, "audiosize", (double)flv->audio.size); length++;
1185 		writeBufferFLVScriptDataValueDouble(&b, "audiodatarate", (double)flv->audio.datarate); length++;
1186 
1187 		if(flv->audio.analyzed == 1) {
1188 			writeBufferFLVScriptDataValueDouble(&b, "audiocodecid", (double)flv->audio.codecid); length++;
1189 			writeBufferFLVScriptDataValueDouble(&b, "audiosamplerate", (double)flv->audio.samplerate); length++;
1190 			writeBufferFLVScriptDataValueDouble(&b, "audiosamplesize", (double)flv->audio.samplesize); length++;
1191 			writeBufferFLVScriptDataValueBool(&b, "stereo", flv->audio.stereo); length++;
1192 		}
1193 	}
1194 
1195 	writeBufferFLVScriptDataValueDouble(&b, "filesize", (double)flv->filesize); length++;
1196 	writeBufferFLVScriptDataValueDouble(&b, "lasttimestamp", (double)flv->lasttimestamp / 1000.0); length++;
1197 
1198 	if(flv->haskeyframes == 1) {
1199 		writeBufferFLVScriptDataValueDouble(&b, "lastkeyframetimestamp", (double)flv->keyframes.lastkeyframetimestamp / 1000.0); length++;
1200 		writeBufferFLVScriptDataValueDouble(&b, "lastkeyframelocation", (double)flv->keyframes.lastkeyframelocation); length++;
1201 
1202 		writeBufferFLVScriptDataVariableArray(&b, "keyframes"); length++;
1203 
1204 			writeBufferFLVScriptDataValueArray(&b, "filepositions", flv->keyframes.nkeyframes);
1205 
1206 			for(i = 0; i < flv->keyframes.nkeyframes; i++)
1207 				writeBufferFLVScriptDataValueDouble(&b, NULL, (double)flv->keyframes.keyframelocations[i]);
1208 
1209 			writeBufferFLVScriptDataValueArray(&b, "times", flv->keyframes.nkeyframes);
1210 
1211 			for(i = 0; i < flv->keyframes.nkeyframes; i++)
1212 				writeBufferFLVScriptDataValueDouble(&b, NULL, (double)flv->keyframes.keyframetimestamps[i] / 1000.0);
1213 
1214 		writeBufferFLVScriptDataVariableArrayEnd(&b);
1215 	}
1216 
1217 	writeBufferFLVScriptDataVariableArrayEnd(&b);
1218 
1219 	if(pass == 0) {
1220 		pass = 1;
1221 		goto onmetadatapass;
1222 	}
1223 
1224 	// Write the onMetaData tag
1225 	bufferReset(&flv->onmetadata);
1226 
1227 	writeBufferFLVScriptDataTag(&flv->onmetadata, 0, b.used);
1228 	bufferAppendBuffer(&flv->onmetadata, &b);
1229 	writeBufferFLVPreviousTagSize(&flv->onmetadata, flv->onmetadata.used);
1230 
1231 	bufferFree(&b);
1232 
1233 	return YAMDI_OK;
1234 }
1235 
createFLVEventOnLastSecond(FLV_t * flv)1236 int createFLVEventOnLastSecond(FLV_t *flv) {
1237 	buffer_t b;
1238 
1239 	bufferInit(&b);
1240 
1241 	// ScriptDataObject
1242 	writeBufferFLVScriptDataObject(&b);
1243 
1244 	writeBufferFLVScriptDataECMAArray(&b, "onLastSecond", 0);
1245 	writeBufferFLVScriptDataVariableArrayEnd(&b);
1246 
1247 	// Write the onLastSecond tag
1248 	bufferReset(&flv->onlastsecond);
1249 
1250 	writeBufferFLVScriptDataTag(&flv->onlastsecond, flv->lastsecond, b.used);
1251 	bufferAppendBuffer(&flv->onlastsecond, &b);
1252 	writeBufferFLVPreviousTagSize(&flv->onlastsecond, flv->onlastsecond.used);
1253 
1254 	bufferFree(&b);
1255 
1256 	return YAMDI_OK;
1257 }
1258 
createFLVEventOnLastKeyframe(FLV_t * flv)1259 int createFLVEventOnLastKeyframe(FLV_t *flv) {
1260 	buffer_t b;
1261 
1262 	bufferInit(&b);
1263 
1264 	// ScriptDataObject
1265 	writeBufferFLVScriptDataObject(&b);
1266 
1267 	writeBufferFLVScriptDataECMAArray(&b, "onLastKeyframe", 0);
1268 	writeBufferFLVScriptDataVariableArrayEnd(&b);
1269 
1270 	// Write the onLastKeyframe tag
1271 	bufferReset(&flv->onlastkeyframe);
1272 
1273 	writeBufferFLVScriptDataTag(&flv->onlastkeyframe, flv->keyframes.lastkeyframetimestamp - 1, b.used);
1274 	bufferAppendBuffer(&flv->onlastkeyframe, &b);
1275 	writeBufferFLVPreviousTagSize(&flv->onlastkeyframe, flv->onlastkeyframe.used);
1276 
1277 	bufferFree(&b);
1278 
1279 	return YAMDI_OK;
1280 }
1281 
writeBufferFLVScriptDataTag(buffer_t * buffer,int timestamp,size_t datasize)1282 int writeBufferFLVScriptDataTag(buffer_t *buffer, int timestamp, size_t datasize) {
1283 	unsigned char bytes[FLV_SIZE_TAGHEADER];
1284 
1285 	bytes[ 0] = FLV_TAG_SCRIPTDATA;
1286 
1287 	// DataSize
1288 	bytes[ 1] = ((datasize >> 16) & 0xff);
1289 	bytes[ 2] = ((datasize >>  8) & 0xff);
1290 	bytes[ 3] = ((datasize >>  0) & 0xff);
1291 
1292 	// Timestamp
1293 	bytes[ 4] = ((timestamp >> 16) & 0xff);
1294 	bytes[ 5] = ((timestamp >>  8) & 0xff);
1295 	bytes[ 6] = ((timestamp >>  0) & 0xff);
1296 
1297 	// TimestampExtended
1298 	bytes[ 7] = ((timestamp >> 24) & 0xff);
1299 
1300 	// StreamID
1301 	bytes[ 8] = 0;
1302 	bytes[ 9] = 0;
1303 	bytes[10] = 0;
1304 
1305 	bufferAppendBytes(buffer, bytes, FLV_SIZE_TAGHEADER);
1306 
1307 	return YAMDI_OK;
1308 }
1309 
writeFLVDataTag(FILE * fp,int type,int timestamp,size_t datasize)1310 int writeFLVDataTag(FILE *fp, int type, int timestamp, size_t datasize) {
1311 	unsigned char bytes[FLV_SIZE_TAGHEADER];
1312 
1313 	bytes[ 0] = type;
1314 
1315 	// DataSize
1316 	bytes[ 1] = ((datasize >> 16) & 0xff);
1317 	bytes[ 2] = ((datasize >>  8) & 0xff);
1318 	bytes[ 3] = ((datasize >>  0) & 0xff);
1319 
1320 	// Timestamp
1321 	bytes[ 4] = ((timestamp >> 16) & 0xff);
1322 	bytes[ 5] = ((timestamp >>  8) & 0xff);
1323 	bytes[ 6] = ((timestamp >>  0) & 0xff);
1324 
1325 	// TimestampExtended
1326 	bytes[ 7] = ((timestamp >> 24) & 0xff);
1327 
1328 	// StreamID
1329 	bytes[ 8] = 0;
1330 	bytes[ 9] = 0;
1331 	bytes[10] = 0;
1332 
1333 	fwrite(bytes, FLV_SIZE_TAGHEADER, 1, fp);
1334 
1335 	return YAMDI_OK;
1336 }
1337 
writeBufferFLVPreviousTagSize(buffer_t * buffer,size_t tagsize)1338 int writeBufferFLVPreviousTagSize(buffer_t *buffer, size_t tagsize) {
1339 	unsigned char bytes[4];
1340 
1341 	bytes[0] = ((tagsize >> 24) & 0xff);
1342 	bytes[1] = ((tagsize >> 16) & 0xff);
1343 	bytes[2] = ((tagsize >>  8) & 0xff);
1344 	bytes[3] = ((tagsize >>  0) & 0xff);
1345 
1346 	bufferAppendBytes(buffer, bytes, 4);
1347 
1348 	return YAMDI_OK;
1349 }
1350 
writeFLVPreviousTagSize(FILE * fp,size_t tagsize)1351 int writeFLVPreviousTagSize(FILE *fp, size_t tagsize) {
1352 	unsigned char bytes[4];
1353 
1354 	bytes[0] = ((tagsize >> 24) & 0xff);
1355 	bytes[1] = ((tagsize >> 16) & 0xff);
1356 	bytes[2] = ((tagsize >>  8) & 0xff);
1357 	bytes[3] = ((tagsize >>  0) & 0xff);
1358 
1359 	fwrite(bytes, 4, 1, fp);
1360 
1361 	return YAMDI_OK;
1362 }
1363 
analyzeFLVH263VideoPacket(FLV_t * flv,FLVTag_t * flvtag,FILE * fp)1364 int analyzeFLVH263VideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp) {
1365 	int startcode, picturesize;
1366 	unsigned char *buffer, data[10];
1367 
1368 	readFLVTagData(data, sizeof(data), flvtag, fp);
1369 	// Skip the VIDEODATA header
1370 	buffer = &data[1];
1371 
1372 	// 8bit  |pppppppp|pppppppp|pvvvvvrr|rrrrrrss|swwwwwww|whhhhhhh|h
1373 	// 16bit |pppppppp|pppppppp|pvvvvvrr|rrrrrrss|swwwwwww|wwwwwwww|whhhhhhh|hhhhhhhh|h
1374 
1375 	startcode = FLV_UI24(buffer) >> 7;
1376 	if(startcode != 1)
1377 		return YAMDI_ERROR;
1378 
1379 	picturesize = ((buffer[3] & 0x3) << 1) + ((buffer[4] >> 7) & 0x1);
1380 
1381 	switch(picturesize) {
1382 		case 0: // Custom 8bit
1383 			flv->video.width = ((buffer[4] & 0x7f) << 1) + ((buffer[5] >> 7) & 0x1);
1384 			flv->video.height = ((buffer[5] & 0x7f) << 1) + ((buffer[6] >> 7) & 0x1);
1385 			break;
1386 		case 1: // Custom 16bit
1387 			flv->video.width = ((buffer[4] & 0x7f) << 9) + (buffer[5] << 1) + ((buffer[6] >> 7) & 0x1);
1388 			flv->video.height = ((buffer[6] & 0x7f) << 9) + (buffer[7] << 1) + ((buffer[8] >> 7) & 0x1);
1389 			break;
1390 		case 2: // CIF
1391 			flv->video.width = 352.0;
1392 			flv->video.height = 288.0;
1393 			break;
1394 		case 3: // QCIF
1395 			flv->video.width = 176.0;
1396 			flv->video.height = 144.0;
1397 			break;
1398 		case 4: // SQCIF
1399 			flv->video.width = 128.0;
1400 			flv->video.height = 96.0;
1401 			break;
1402 		case 5:
1403 			flv->video.width = 320.0;
1404 			flv->video.height = 240.0;
1405 			break;
1406 		case 6:
1407 			flv->video.width = 160.0;
1408 			flv->video.height = 120.0;
1409 			break;
1410 		default:
1411 			break;
1412 	}
1413 
1414 	return YAMDI_OK;
1415 }
1416 
analyzeFLVScreenVideoPacket(FLV_t * flv,FLVTag_t * flvtag,FILE * fp)1417 int analyzeFLVScreenVideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp) {
1418 	unsigned char *buffer, data[5];
1419 
1420 	// |1111wwww|wwwwwwww|2222hhhh|hhhhhhhh|
1421 
1422 	readFLVTagData(data, sizeof(data), flvtag, fp);
1423 	// Skip the VIDEODATA header
1424 	buffer = &data[1];
1425 
1426 	flv->video.width = ((buffer[0] & 0xf) << 8) + buffer[1];
1427 	flv->video.height = ((buffer[2] & 0xf) << 8) + buffer[3];
1428 
1429 	return YAMDI_OK;
1430 }
1431 
analyzeFLVVP6VideoPacket(FLV_t * flv,FLVTag_t * flvtag,FILE * fp)1432 int analyzeFLVVP6VideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp) {
1433 	int offset = 3;	// default buffer offset for dim_y
1434 	unsigned char *buffer, data[10];
1435 
1436 	readFLVTagData(data, sizeof(data), flvtag, fp);
1437 
1438 #if DEBUG
1439 	fprintf(stderr, "\n");
1440 
1441 	fprintf(stderr, "[VP6] ");
1442 	int i = 0;
1443 	for(i = 0; i < sizeof(data); i++)
1444 		fprintf(stderr, "%d=%d ", i, data[i]);
1445 	fprintf(stderr, "\n");
1446 #endif
1447 
1448 	// Skip the VIDEODATA header
1449 	buffer = &data[1];
1450 
1451 	// VP6FLVVIDEOPACKET header (as described in the SWF Specs v10, page 249)
1452 	int hadjust = ((buffer[0] >> 4) & 0x0f);
1453 	int vadjust = (buffer[0] & 0x0f);
1454 
1455 	// Raw vp6 video data (http://wiki.multimedia.cx/index.php?title=On2_VP6)
1456 	int frame_mode = ((buffer[1] >> 7) & 0x01);
1457 
1458 	if(frame_mode != 0)	// We need an iframe
1459 		return YAMDI_ERROR;
1460 
1461 	int marker = (buffer[1] & 0x01);	// Without checking this value, we support all VP6 variants
1462 
1463 	int version2 = ((buffer[2] >> 1) & 0x03);
1464 
1465 #if DEBUG
1466 	int version = ((buffer[2] >> 3) & 0x1f);
1467 	int interlace = (buffer[2] & 0x01);
1468 
1469 	fprintf(stderr, "[VP6] marker = %d\n", marker);
1470 	fprintf(stderr, "[VP6] version = %d\n", version);
1471 	fprintf(stderr, "[VP6] version2 = %d\n", version2);
1472 	fprintf(stderr, "[VP6] interlace = %d\n", interlace);
1473 #endif
1474 
1475 	// In these cases there are 2 more bytes that we have to skip
1476 	if(marker == 1 || version2 == 0)
1477 		offset += 2;
1478 
1479 #if DEBUG
1480 	fprintf(stderr, "[VP6] offset = %d\n", offset);
1481 	fprintf(stderr, "[VP6] dim_y = %d\n", buffer[offset]);
1482 	fprintf(stderr, "[VP6] dim_x = %d\n", buffer[offset + 1]);
1483 	fprintf(stderr, "[VP6] render_y = %d\n", buffer[offset + 2]);
1484 	fprintf(stderr, "[VP6] render_x = %d\n", buffer[offset + 3]);
1485 #endif
1486 
1487 	// Now offset points to the resolution values: [dim_y, dim_x, render_y, render_x]
1488 	// Values represent macroblocks
1489 	flv->video.height = (buffer[offset + 0] * 16) - vadjust;
1490 	flv->video.width = (buffer[offset + 1] * 16) - hadjust;
1491 
1492 	return YAMDI_OK;
1493 }
1494 
analyzeFLVVP6AlphaVideoPacket(FLV_t * flv,FLVTag_t * flvtag,FILE * fp)1495 int analyzeFLVVP6AlphaVideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp) {
1496 	unsigned char *buffer, data[9];
1497 
1498 	readFLVTagData(data, sizeof(data), flvtag, fp);
1499 	// Skip the VIDEODATA header
1500 	buffer = &data[1];
1501 
1502 	flv->video.width = buffer[7] * 16 - (buffer[0] >> 4);
1503 	flv->video.height = buffer[6] * 16 - (buffer[0] & 0x0f);
1504 
1505 	return YAMDI_OK;
1506 }
1507 
analyzeFLVH264VideoPacket(FLV_t * flv,FLVTag_t * flvtag,FILE * fp)1508 int analyzeFLVH264VideoPacket(FLV_t *flv, FLVTag_t *flvtag, FILE *fp) {
1509 	int avcpackettype;
1510 	int i, length, offset, nSPS;
1511 	unsigned char *avcc;
1512 	unsigned char *buffer, data[flvtag->datasize];
1513 	h264data_t h264data;
1514 
1515 	readFLVTagData(data, sizeof(data), flvtag, fp);
1516 	// Skip the VIDEODATA header
1517 	buffer = &data[1];
1518 
1519 	avcpackettype = buffer[0];
1520 
1521 #ifdef DEBUG
1522 	fprintf(stderr, "[FLV] AVCPacketType = %d\n", avcpackettype);
1523 #endif
1524 
1525 	if(avcpackettype != 0)
1526 		return YAMDI_ERROR;
1527 
1528 	// AVCDecoderConfigurationRecord (14496-15, 5.2.4.1.1)
1529 	avcc = (unsigned char *)&buffer[4];
1530 
1531 	nSPS = avcc[5] & 0x1f;
1532 
1533 #ifdef DEBUG
1534 	fprintf(stderr, "[AVC/H.264] AVCDecoderConfigurationRecord\n");
1535 	fprintf(stderr, "[AVC/H.264] configurationVersion = %d\n", avcc[0]);
1536 	fprintf(stderr, "[AVC/H.264] AVCProfileIndication = %d\n", avcc[1]);
1537 	fprintf(stderr, "[AVC/H.264] profile_compatibility = %d\n", avcc[2]);
1538 	fprintf(stderr, "[AVC/H.264] AVCLevelIndication = %d\n", avcc[3]);
1539 	fprintf(stderr, "[AVC/H.264] lengthSizeMinusOne = %d\n", avcc[4] & 0x3);
1540 	fprintf(stderr, "[AVC/H.264] numOfSequenceParameterSets = %d\n", nSPS);
1541 #endif
1542 
1543 	offset = 6;
1544 	for(i = 0; i < nSPS; i++) {
1545 		length = (avcc[offset] << 8) + avcc[offset + 1];
1546 #ifdef DEBUG
1547 		fprintf(stderr, "[AVC/H.264]\tsequenceParameterSetLength = %d bit\n", 8 * length);
1548 #endif
1549 		memset(&h264data, 0, sizeof(h264data_t));
1550 		if(readH264NALUnit(&h264data, &avcc[offset + 2], length) == YAMDI_OK)
1551 			break;
1552 
1553 		offset += (2 + length);
1554 	}
1555 
1556 	// There would be some Picture Parameter Sets, but we don't need them. Bail out.
1557 /*
1558 	int nPPS = avcc[offset++];
1559 	fprintf(stderr, "numOfPictureParameterSets = %d\n", nPPS);
1560 
1561 	for(i = 0; i < nPPS; i++) {
1562 		length = (avcc[offset] << 8) + avcc[offset + 1];
1563 #ifdef DEBUG
1564 		fprintf(stderr, "[AVC/H.264]\tpictureParameterSetLength = %d bit\n", 8 * length);
1565 #endif
1566 		readH264NALUnit(&avcc[offset + 2], length);
1567 
1568 		offset += (2 + length);
1569 	}
1570 */
1571 
1572 	if(h264data.valid == 0)
1573 		return YAMDI_ERROR;
1574 
1575 	flv->video.width = h264data.width;
1576 	flv->video.height = h264data.height;
1577 
1578 	return YAMDI_OK;
1579 }
1580 
writeBufferFLVScriptDataObject(buffer_t * buffer)1581 int writeBufferFLVScriptDataObject(buffer_t *buffer) {
1582 	unsigned char type = 2;
1583 
1584 	bufferAppendBytes(buffer, &type, 1);
1585 
1586 	return YAMDI_OK;
1587 }
1588 
writeBufferFLVScriptDataECMAArray(buffer_t * buffer,const char * name,size_t len)1589 int writeBufferFLVScriptDataECMAArray(buffer_t *buffer, const char *name, size_t len) {
1590 	unsigned char type, bytes[4];
1591 
1592 	writeBufferFLVScriptDataString(buffer, name);
1593 
1594 	type = 8;	// ECMAArray
1595 	bufferAppendBytes(buffer, &type, 1);
1596 
1597 	bytes[0] = ((len >> 24) & 0xff);
1598 	bytes[1] = ((len >> 16) & 0xff);
1599 	bytes[2] = ((len >>  8) & 0xff);
1600 	bytes[3] = ((len >>  0) & 0xff);
1601 
1602 	bufferAppendBytes(buffer, bytes, 4);
1603 
1604 	return YAMDI_OK;
1605 }
1606 
writeBufferFLVScriptDataValueArray(buffer_t * buffer,const char * name,size_t len)1607 int writeBufferFLVScriptDataValueArray(buffer_t *buffer, const char *name, size_t len) {
1608 	unsigned char type, bytes[4];
1609 
1610 	writeBufferFLVScriptDataString(buffer, name);
1611 
1612 	type = 10;	// Value Array
1613 	bufferAppendBytes(buffer, &type, 1);
1614 
1615 	bytes[0] = ((len >> 24) & 0xff);
1616 	bytes[1] = ((len >> 16) & 0xff);
1617 	bytes[2] = ((len >>  8) & 0xff);
1618 	bytes[3] = ((len >>  0) & 0xff);
1619 
1620 	bufferAppendBytes(buffer, bytes, 4);
1621 
1622 	return YAMDI_OK;
1623 }
1624 
writeBufferFLVScriptDataVariableArray(buffer_t * buffer,const char * name)1625 int writeBufferFLVScriptDataVariableArray(buffer_t *buffer, const char *name) {
1626 	unsigned char type;
1627 
1628 	writeBufferFLVScriptDataString(buffer, name);
1629 
1630 	type = 3;	// Variable Array
1631 	bufferAppendBytes(buffer, &type, 1);
1632 
1633 	return YAMDI_OK;
1634 }
1635 
writeBufferFLVScriptDataVariableArrayEnd(buffer_t * buffer)1636 int writeBufferFLVScriptDataVariableArrayEnd(buffer_t *buffer) {
1637 	unsigned char bytes[3];
1638 
1639 	bytes[0] = 0;
1640 	bytes[1] = 0;
1641 	bytes[2] = 9;
1642 
1643 	bufferAppendBytes(buffer, bytes, 3);
1644 
1645 	return YAMDI_OK;
1646 }
1647 
writeBufferFLVScriptDataValueString(buffer_t * buffer,const char * name,const char * value)1648 int writeBufferFLVScriptDataValueString(buffer_t *buffer, const char *name, const char *value) {
1649 	unsigned char type;
1650 
1651 	if(name != NULL)
1652 		writeBufferFLVScriptDataString(buffer, name);
1653 
1654 	type = 2;	// DataString
1655 	bufferAppendBytes(buffer, &type, 1);
1656 
1657 	writeBufferFLVScriptDataString(buffer, value);
1658 
1659 	return YAMDI_OK;
1660 }
1661 
writeBufferFLVScriptDataValueBool(buffer_t * buffer,const char * name,int value)1662 int writeBufferFLVScriptDataValueBool(buffer_t *buffer, const char *name, int value) {
1663 	unsigned char type;
1664 
1665 	if(name != NULL)
1666 		writeBufferFLVScriptDataString(buffer, name);
1667 
1668 	type = 1;	// Bool
1669 	bufferAppendBytes(buffer, &type, 1);
1670 
1671 	writeBufferFLVBool(buffer, value);
1672 
1673 	return YAMDI_OK;
1674 }
1675 
writeBufferFLVScriptDataValueDouble(buffer_t * buffer,const char * name,double value)1676 int writeBufferFLVScriptDataValueDouble(buffer_t *buffer, const char *name, double value) {
1677 	unsigned char type;
1678 
1679 	if(name != NULL)
1680 		writeBufferFLVScriptDataString(buffer, name);
1681 
1682 	type = 0;	// Double
1683 	bufferAppendBytes(buffer, &type, 1);
1684 
1685 	writeBufferFLVDouble(buffer, value);
1686 
1687 	return YAMDI_OK;
1688 }
1689 
writeBufferFLVScriptDataString(buffer_t * buffer,const char * s)1690 int writeBufferFLVScriptDataString(buffer_t *buffer, const char *s) {
1691 	size_t len;
1692 	unsigned char bytes[2];
1693 
1694 	len = strlen(s);
1695 
1696 	// critical, if only DataString is expected?
1697 	if(len > 0xffff)
1698 		writeBufferFLVScriptDataLongString(buffer, s);
1699 	else {
1700 		bytes[0] = ((len >> 8) & 0xff);
1701 		bytes[1] = ((len >> 0) & 0xff);
1702 
1703 		bufferAppendBytes(buffer, bytes, 2);
1704 		bufferAppendString(buffer, (unsigned char*)s);
1705 	}
1706 
1707 	return YAMDI_OK;
1708 }
1709 
writeBufferFLVScriptDataLongString(buffer_t * buffer,const char * s)1710 int writeBufferFLVScriptDataLongString(buffer_t *buffer, const char *s) {
1711 	size_t len;
1712 	unsigned char bytes[4];
1713 
1714 	len = strlen(s);
1715 
1716 	if(len > 0xffffffff)
1717 		len = 0xffffffff;
1718 
1719 	bytes[0] = ((len >> 24) & 0xff);
1720 	bytes[1] = ((len >> 16) & 0xff);
1721 	bytes[2] = ((len >>  8) & 0xff);
1722 	bytes[3] = ((len >>  0) & 0xff);
1723 
1724 	bufferAppendBytes(buffer, bytes, 4);
1725 	bufferAppendString(buffer, (unsigned char *)s);
1726 
1727 	return YAMDI_OK;
1728 }
1729 
writeBufferFLVBool(buffer_t * buffer,int value)1730 int writeBufferFLVBool(buffer_t *buffer, int value) {
1731 	unsigned char b;
1732 
1733 	b = (value & 1);
1734 
1735 	bufferAppendBytes(buffer, &b, 1);
1736 
1737 	return YAMDI_OK;
1738 }
1739 
writeBufferFLVDouble(buffer_t * buffer,double value)1740 int writeBufferFLVDouble(buffer_t *buffer, double value) {
1741 	union {
1742 		unsigned char dc[8];
1743 		double dd;
1744 	} d;
1745 	unsigned char b[8];
1746 
1747 	d.dd = value;
1748 
1749 	if(isBigEndian()) {
1750 		b[0] = d.dc[0];
1751 		b[1] = d.dc[1];
1752 		b[2] = d.dc[2];
1753 		b[3] = d.dc[3];
1754 		b[4] = d.dc[4];
1755 		b[5] = d.dc[5];
1756 		b[6] = d.dc[6];
1757 		b[7] = d.dc[7];
1758 	}
1759 	else {
1760 		b[0] = d.dc[7];
1761 		b[1] = d.dc[6];
1762 		b[2] = d.dc[5];
1763 		b[3] = d.dc[4];
1764 		b[4] = d.dc[3];
1765 		b[5] = d.dc[2];
1766 		b[6] = d.dc[1];
1767 		b[7] = d.dc[0];
1768 	}
1769 
1770 	bufferAppendBytes(buffer, b, 8);
1771 
1772 	return YAMDI_OK;
1773 }
1774 
readFLVTag(FLVTag_t * flvtag,off_t offset,FILE * fp)1775 int readFLVTag(FLVTag_t *flvtag, off_t offset, FILE *fp) {
1776 	int rv;
1777 	unsigned char buffer[FLV_SIZE_TAGHEADER];
1778 
1779 	memset(flvtag, 0, sizeof(FLVTag_t));
1780 
1781 	rv = fseeko(fp, offset, SEEK_SET);
1782 	if(rv != 0) {
1783 #ifdef DEBUG
1784 		fprintf(stderr, "[FLV] %s\n", strerror(errno));
1785 #endif
1786 		return YAMDI_READ_ERROR;
1787 	}
1788 
1789 	flvtag->offset = offset;
1790 
1791 	// Read the header
1792 	if(readBytes(buffer, FLV_SIZE_TAGHEADER, fp) != YAMDI_OK)
1793 		return YAMDI_READ_ERROR;
1794 
1795 	flvtag->tagtype = FLV_UI8(buffer);
1796 
1797 	// Assuming only known tags. Otherwise we only process the
1798 	// input file up to this point. It is not possible to detect
1799 	// where the next valid tag could be.
1800 	switch(flvtag->tagtype) {
1801 		case FLV_TAG_VIDEO:
1802 		case FLV_TAG_AUDIO:
1803 		case FLV_TAG_SCRIPTDATA:
1804 			break;
1805 		default:
1806 			return YAMDI_INVALID_TAGTYPE;
1807 	}
1808 
1809 	flvtag->datasize = (size_t)FLV_UI24(&buffer[1]);
1810 	flvtag->timestamp = FLV_TIMESTAMP(&buffer[4]);
1811 
1812 	// Skip the data
1813 	readBytes(NULL, flvtag->datasize, fp);
1814 
1815 	// Read the previous tag size
1816 	readBytes(buffer, FLV_SIZE_PREVIOUSTAGSIZE, fp);
1817 
1818 	// Check the previous tag size
1819 	// This is too picky. We don't need it.
1820 /*
1821 	if(FLV_UI32(buffer) != (FLV_SIZE_TAGHEADER + flvtag->datasize))
1822 		return YAMDI_INVALID_PREVIOUSTAGSIZE;
1823 */
1824 
1825 	flvtag->tagsize = FLV_SIZE_TAGHEADER + flvtag->datasize;
1826 
1827 	return YAMDI_OK;
1828 }
1829 
readFLVTagData(unsigned char * ptr,size_t size,FLVTag_t * flvtag,FILE * stream)1830 int readFLVTagData(unsigned char *ptr, size_t size, FLVTag_t *flvtag, FILE *stream) {
1831 	// check for size <= flvtag->datasize?
1832 
1833 	fseeko(stream, flvtag->offset + FLV_SIZE_TAGHEADER, SEEK_SET);
1834 
1835 	return readBytes(ptr, size, stream);
1836 }
1837 
readBytes(unsigned char * ptr,size_t size,FILE * stream)1838 int readBytes(unsigned char *ptr, size_t size, FILE *stream) {
1839 	size_t bytesread;
1840 
1841 	if(ptr == NULL) {
1842 		fseeko(stream, (off_t)size, SEEK_CUR);
1843 		return YAMDI_OK;
1844 	}
1845 
1846 	bytesread = fread(ptr, 1, size, stream);
1847 	if(bytesread < size)
1848 		return YAMDI_READ_ERROR;
1849 
1850 	return YAMDI_OK;
1851 }
1852 
readH264NALUnit(h264data_t * h264data,unsigned char * nalu,int length)1853 int readH264NALUnit(h264data_t * h264data, unsigned char *nalu, int length) {
1854 	int i, numBytesInRBSP;
1855 	int nal_unit_type;
1856 	bitstream_t bitstream;
1857 
1858 	// See 14496-10, 7.3.1
1859 #ifdef DEBUG
1860 	fprintf(stderr, "[AVC/H.264]\tNALU Header: %02x\n", nalu[0]);
1861 	fprintf(stderr, "[AVC/H.264]\t\tforbidden_zero_bit = %d\n", (nalu[0] >> 7) & 0x1);
1862 	fprintf(stderr, "[AVC/H.264]\t\tnal_ref_idc = %d\n", (nalu[0] >> 5) & 0x3);
1863 	fprintf(stderr, "[AVC/H.264]\t\tnal_unit_type = %d\n", nalu[0] & 0x1f);
1864 	fprintf(stderr, "[AVC/H.264]\tRBSP: ");
1865 	for(i = 1; i < length; i++)
1866 		fprintf(stderr, "%02x ", nalu[i]);
1867 	fprintf(stderr, "\n");
1868 #endif
1869 
1870 	nal_unit_type = nalu[0] & 0x1f;
1871 
1872 	// We are only interested in NALUnits of type 7 (sequence parameter set, SPS)
1873 	if(nal_unit_type != 7)
1874 		return YAMDI_H264_USELESS_NALU;
1875 
1876 	bitstream.bytes = (unsigned char *)calloc(1, length - 1);
1877 
1878 	numBytesInRBSP = 0;
1879 	for(i = 1; i < length; i++) {
1880 		if(i + 2 < length && nalu[i] == 0x00 && nalu[i + 1] == 0x00 && nalu[i + 2] == 0x03) {
1881 			bitstream.bytes[numBytesInRBSP++] = nalu[i];
1882 			bitstream.bytes[numBytesInRBSP++] = nalu[i + 1];
1883 
1884 			i += 2;
1885 		}
1886 		else
1887 			bitstream.bytes[numBytesInRBSP++] = nalu[i];
1888 	}
1889 
1890 	bitstream.length = numBytesInRBSP;
1891 	bitstream.byte = 0;
1892 	bitstream.bit = 0;
1893 
1894 #ifdef DEBUG
1895 	fprintf(stderr, "[AVC/H.264]\tSODB: ");
1896 	for(i = 0; i < bitstream.length; i++)
1897 		fprintf(stderr, "%02x ", bitstream.bytes[i]);
1898 	fprintf(stderr, "\n");
1899 #endif
1900 
1901 	readH264SPS(h264data, &bitstream);
1902 
1903 	free(bitstream.bytes);
1904 
1905 	return YAMDI_OK;
1906 }
1907 
readH264SPS(h264data_t * h264data,bitstream_t * bitstream)1908 void readH264SPS(h264data_t *h264data, bitstream_t *bitstream) {
1909 	int i, j;
1910 	unsigned int profile_idc;
1911 	unsigned int chroma_format_idc = 1, separate_color_plane_flag = 0;
1912 
1913 	unsigned int pic_width_in_mbs_minus1, pic_height_in_map_units_minus1;
1914 	unsigned int frame_mbs_only_flag;
1915 	unsigned int frame_cropping_flag;
1916 	unsigned int frame_crop_left_offset = 0, frame_crop_right_offset = 0, frame_crop_top_offset = 0, frame_crop_bottom_offset = 0;
1917 
1918 	unsigned int chromaArrayType;
1919 /*
1920 	We need these values from SPS
1921 
1922 	chroma_format_idc
1923 	separate_color_plane_flag
1924 	pic_width_in_mbs_minus1
1925 	pic_height_in_map_units_minus1
1926 	frame_mbs_only_flag
1927 	frame_cropping_flag
1928 	frame_crop_left_offset
1929 	frame_crop_right_offset
1930 	frame_crop_top_offset
1931 	frame_crop_bottom_offset
1932 */
1933 
1934 	profile_idc = readCodedU(bitstream, 8, "profile_idc");
1935 	readCodedU(bitstream, 1, "constraint_set0_flag");
1936 	readCodedU(bitstream, 1, "constraint_set1_flag");
1937 	readCodedU(bitstream, 1, "constraint_set2_flag");
1938 	readCodedU(bitstream, 1, "constraint_set3_flag");
1939 	readCodedU(bitstream, 4, "reserved_zero_4bits");
1940 	readCodedU(bitstream, 8, "level_idc");
1941 	readCodedUE(bitstream, "seq_parameter_set_id");
1942 
1943 	if(
1944 		profile_idc == 100 ||
1945 		profile_idc == 110 ||
1946 		profile_idc == 122 ||
1947 		profile_idc == 244 ||
1948 		profile_idc == 44 ||
1949 		profile_idc == 83 ||
1950 		profile_idc == 86
1951 	) {
1952 		chroma_format_idc = readCodedUE(bitstream, "chroma_format_idc");
1953 
1954 		if(chroma_format_idc == 3)
1955 			separate_color_plane_flag = readCodedU(bitstream, 1, "separate_color_plane_flag");
1956 
1957 		readCodedUE(bitstream, "bit_depth_luma_minus8");
1958 		readCodedUE(bitstream, "bit_depth_chroma_minus8");
1959 		readCodedU(bitstream, 1, "qpprime_y_zero_transform_bypass_flag");
1960 
1961 		unsigned int seq_scaling_matrix_present_flag = readCodedU(bitstream, 1, "seq_scaling_matrix_present_flag");
1962 		if(seq_scaling_matrix_present_flag == 1) {
1963 			int sizeOfScalingList, delta_scale, lastScale, nextScale;
1964 
1965 			int seq_scaling_matrix_count = (chroma_format_idc != 3) ? 8 : 12;
1966 			unsigned int seq_scaling_list_present_flag;
1967 			for(i = 0; i < seq_scaling_matrix_count; i++) {
1968 				seq_scaling_list_present_flag = readCodedU(bitstream, 1, "seq_scaling_list_present_flag");
1969 
1970 				if(seq_scaling_list_present_flag == 1) {
1971 					sizeOfScalingList = (i < 6) ? 16 : 64;
1972 					lastScale = nextScale = 8;
1973 					for(j = 0; j < sizeOfScalingList; j++) {
1974 						if(nextScale != 0) {
1975 							delta_scale = readCodedSE(bitstream, "delta_scale");
1976 
1977 							nextScale = (lastScale + delta_scale + 256) % 256;
1978 						}
1979 
1980 						lastScale = (nextScale == 0) ? lastScale : nextScale;
1981 					}
1982 				}
1983 			}
1984 		}
1985 	}
1986 
1987 	readCodedUE(bitstream, "log2_max_frame_num_minus4");
1988 	unsigned int pic_order_cnt_type = readCodedUE(bitstream, "pic_order_cnt_type");
1989 
1990 	if(pic_order_cnt_type == 1) {
1991 		readCodedU(bitstream, 1, "delta_pic_order_always_zero_flag");
1992 		readCodedSE(bitstream, "offset_for_non_ref_pic");
1993 		readCodedSE(bitstream, "offset_for_top_to_bottom_field");
1994 
1995 		unsigned int num_ref_frames_in_pic_order_cnt_cycle = readCodedUE(bitstream, "num_ref_frames_in_pic_order_cnt_cycle");
1996 		for(i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++)
1997 			readCodedSE(bitstream, "offset_for_ref_frame");
1998 	}
1999 	else if(pic_order_cnt_type == 0)
2000 		readCodedUE(bitstream, "log2_max_pic_order_cnt_lsb_minus4");
2001 
2002 	readCodedUE(bitstream, "max_num_ref_frames");
2003 	readCodedU(bitstream, 1, "gaps_in_frame_num_value_allowed_flag");
2004 
2005 	pic_width_in_mbs_minus1 = readCodedUE(bitstream, "pic_width_in_mbs_minus1");
2006 	pic_height_in_map_units_minus1 = readCodedUE(bitstream, "pic_height_in_map_units_minus1");
2007 
2008 	frame_mbs_only_flag = readCodedU(bitstream, 1, "frame_mbs_only_flag");
2009 	if(frame_mbs_only_flag == 0)
2010 		readCodedU(bitstream, 1, "mb_adaptive_frame_field_flag");
2011 
2012 	readCodedU(bitstream, 1, "direct_8x8_inference_flag");
2013 
2014 	frame_cropping_flag = readCodedU(bitstream, 1, "frame_cropping_flag");
2015 	if(frame_cropping_flag == 1) {
2016 		frame_crop_left_offset = readCodedUE(bitstream, "frame_crop_left_offset");
2017 		frame_crop_right_offset = readCodedUE(bitstream, "frame_crop_right_offset");
2018 		frame_crop_top_offset = readCodedUE(bitstream, "frame_crop_top_offset");
2019 		frame_crop_bottom_offset = readCodedUE(bitstream, "frame_crop_bottom_offset");
2020 	}
2021 
2022 	readCodedU(bitstream, 1, "vui_parameters_present_flag");
2023 
2024 	// and so on ... VUI is not interesting for us. We have everything we need.
2025 
2026 	// Now we have enough information to compute the width and height of this video stream
2027 
2028 	unsigned int picWidthInMbs = (pic_width_in_mbs_minus1 + 1);
2029 	unsigned int picHeightInMapUnits = (pic_height_in_map_units_minus1 + 1);
2030 	unsigned int frameHeightInMbs = (2 - frame_mbs_only_flag) * picHeightInMapUnits;
2031 
2032 	unsigned int width = picWidthInMbs * 16;
2033 	unsigned int height = frameHeightInMbs * 16;
2034 
2035 #ifdef DEBUG
2036 	fprintf(stderr, "[AVC/H.264] width = %u (pre crop)\n", width);
2037 	fprintf(stderr, "[AVC/H.264] height = %u (pre crop)\n", height);
2038 #endif
2039 
2040 	// Cropping
2041 
2042 	int cropLeft, cropRight;
2043 	int cropTop, cropBottom;
2044 
2045 	if(frame_cropping_flag == 1) {
2046 		// See 14496-10, Table 6-1
2047 		int subWidthC[4] = {1, 2, 2, 1};
2048 		int subHeightC[4] = {1, 2, 1, 1};
2049 
2050 		unsigned int cropUnitX, cropUnitY;
2051 
2052 		if(separate_color_plane_flag == 0)
2053 			chromaArrayType = chroma_format_idc;
2054 		else
2055 			chromaArrayType = 0;
2056 
2057 		if(chromaArrayType == 0) {
2058 			cropUnitX = 1;
2059 			cropUnitY = 2 - frame_mbs_only_flag;
2060 		}
2061 		else {
2062 			cropUnitX = subWidthC[chroma_format_idc];
2063 			cropUnitY = subHeightC[chroma_format_idc] * (2 - frame_mbs_only_flag);
2064 		}
2065 
2066 		cropLeft = cropUnitX * frame_crop_left_offset;
2067 		cropRight = cropUnitX * frame_crop_right_offset;
2068 		cropTop = cropUnitY * frame_crop_top_offset;
2069 		cropBottom = cropUnitY * frame_crop_bottom_offset;
2070 	}
2071 	else {
2072 		cropLeft = 0;
2073 		cropRight = 0;
2074 		cropTop = 0;
2075 		cropBottom = 0;
2076 	}
2077 
2078 	width = width - cropLeft - cropRight;
2079 	height = height - cropTop - cropBottom;
2080 
2081 #ifdef DEBUG
2082 	fprintf(stderr, "[AVC/H.264] width = %u\n", width);
2083 	fprintf(stderr, "[AVC/H.264] height = %u\n", height);
2084 #endif
2085 
2086 	h264data->valid = 1;
2087 	h264data->width = width;
2088 	h264data->height = height;
2089 
2090 	return;
2091 }
2092 
readCodedU(bitstream_t * bitstream,int nbits,const char * name)2093 unsigned int readCodedU(bitstream_t *bitstream, int nbits, const char *name) {
2094 	// unsigned integer with n bits
2095 	unsigned int bits = (unsigned int)readBits(bitstream, nbits);
2096 
2097 #ifdef DEBUG
2098 	if(name != NULL)
2099 		fprintf(stderr, "[AVC/H.264]\t\t%s = %u\n", name, bits);
2100 #endif
2101 
2102 	return bits;
2103 }
2104 
readCodedUE(bitstream_t * bitstream,const char * name)2105 unsigned int readCodedUE(bitstream_t *bitstream, const char *name) {
2106 	// unsigned integer Exp-Golomb coded (see 14496-10, 9.1)
2107 	int leadingZeroBits = -1;
2108 	int bit;
2109 	unsigned int codeNum = 0;
2110 
2111 	for(bit = 0; bit == 0; leadingZeroBits++) {
2112 		bit = readBit(bitstream);
2113 		if (bitstream->byte == bitstream->length) break;
2114 	}
2115 
2116 	codeNum = ((1 << leadingZeroBits) - 1 + (unsigned int)readBits(bitstream, leadingZeroBits));
2117 
2118 #ifdef DEBUG
2119 	if(name != NULL)
2120 		fprintf(stderr, "[AVC/H.264]\t\t%s = %u\n", name, codeNum);
2121 #endif
2122 
2123 	return codeNum;
2124 }
2125 
readCodedSE(bitstream_t * bitstream,const char * name)2126 int readCodedSE(bitstream_t *bitstream, const char *name) {
2127 	// signed integer Exp-Golomb coded (see 14496-10, 9.1 and 9.1.1)
2128 	unsigned int codeNum;
2129 	int codeNumSigned, sign;
2130 
2131 	codeNum = readCodedUE(bitstream, NULL);
2132 
2133 	sign = (codeNum % 2) + 1;
2134 	codeNumSigned = codeNum >> 1;
2135 	if(sign == 0)
2136 		codeNumSigned++;
2137 	else
2138 		codeNumSigned *= -1;
2139 
2140 #ifdef DEBUG
2141 	if(name != NULL)
2142 		fprintf(stderr, "[AVC/H.264]\t\t%s = %d\n", name, codeNumSigned);
2143 #endif
2144 
2145 	return codeNumSigned;
2146 }
2147 
readBits(bitstream_t * bitstream,int nbits)2148 int readBits(bitstream_t *bitstream, int nbits) {
2149 	int i, rv = 0;
2150 
2151 	for(i = 0; i < nbits; i++) {
2152 		rv = (rv << 1);
2153 		rv += readBit(bitstream);
2154 	}
2155 
2156 	return rv;
2157 }
2158 
readBit(bitstream_t * bitstream)2159 int readBit(bitstream_t *bitstream) {
2160 	int bit;
2161 
2162 	if(bitstream->byte == bitstream->length)
2163 		return 0;
2164 
2165 	bit = (bitstream->bytes[bitstream->byte] >> (7 - bitstream->bit)) & 0x01;
2166 
2167 	bitstream->bit++;
2168 	if(bitstream->bit == 8) {
2169 		bitstream->byte++;
2170 		bitstream->bit = 0;
2171 	}
2172 
2173 	return bit;
2174 }
2175 
bufferInit(buffer_t * buffer)2176 int bufferInit(buffer_t *buffer) {
2177 	if(buffer == NULL)
2178 		return YAMDI_ERROR;
2179 
2180 	buffer->data = NULL;
2181 	buffer->size = 0;
2182 	buffer->used = 0;
2183 
2184 	return YAMDI_OK;
2185 }
2186 
bufferFree(buffer_t * buffer)2187 int bufferFree(buffer_t *buffer) {
2188 	if(buffer == NULL)
2189 		return YAMDI_ERROR;
2190 
2191 	if(buffer->data != NULL) {
2192 		free(buffer->data);
2193 		buffer->data = NULL;
2194 	}
2195 
2196 	return YAMDI_OK;
2197 }
2198 
bufferReset(buffer_t * buffer)2199 int bufferReset(buffer_t *buffer) {
2200 	if(buffer == NULL)
2201 		return YAMDI_ERROR;
2202 
2203 	buffer->used = 0;
2204 
2205 	return YAMDI_OK;
2206 }
2207 
bufferAppendString(buffer_t * dst,const unsigned char * string)2208 int bufferAppendString(buffer_t *dst, const unsigned char *string) {
2209 	if(string == NULL)
2210 		return YAMDI_OK;
2211 
2212 	return bufferAppendBytes(dst, string, strlen((char *)string));
2213 }
2214 
bufferAppendBuffer(buffer_t * dst,buffer_t * src)2215 int bufferAppendBuffer(buffer_t *dst, buffer_t *src) {
2216 	if(src == NULL)
2217 		return YAMDI_OK;
2218 
2219 	return bufferAppendBytes(dst, src->data, src->used);
2220 }
2221 
bufferAppendBytes(buffer_t * dst,const unsigned char * bytes,size_t nbytes)2222 int bufferAppendBytes(buffer_t *dst, const unsigned char *bytes, size_t nbytes) {
2223 	size_t size;
2224 	unsigned char *data;
2225 
2226 	if(dst == NULL)
2227 		return YAMDI_ERROR;
2228 
2229 	if(bytes == NULL)
2230 		return YAMDI_OK;
2231 
2232 	if(nbytes == 0)
2233 		return YAMDI_OK;
2234 
2235 	// Check if we have to increase the buffer size
2236 	if(dst->size < dst->used + nbytes) {
2237 		// Pre-allocating some memory. Round up to the next 1024 bound
2238 		size = ((dst->used + nbytes) / 1024 + 1) * 1024;
2239 
2240 		data = (unsigned char *)realloc(dst->data, size);
2241 		if(data == NULL)
2242 			return YAMDI_ERROR;
2243 
2244 		dst->data = data;
2245 		dst->size = size;
2246 	}
2247 
2248 	// Copy the stuff into the buffer
2249 	memcpy(&dst->data[dst->used], bytes, nbytes);
2250 
2251 	dst->used += nbytes;
2252 
2253 	return YAMDI_OK;
2254 }
2255 
isBigEndian(void)2256 int isBigEndian(void) {
2257 	long one = 1;
2258 	return !(*((char *)(&one)));
2259 }
2260 
writeXMLMetadata(FILE * fp,const char * infile,const char * outfile,FLV_t * flv)2261 void writeXMLMetadata(FILE *fp, const char *infile, const char *outfile, FLV_t *flv) {
2262 	size_t i;
2263 
2264 	fprintf(fp, "<?xml version='1.0' encoding='UTF-8'?>\n");
2265 	fprintf(fp, "<fileset>\n");
2266 
2267 	if(outfile != NULL)
2268 		fprintf(fp, "<flv name=\"%s\">\n", outfile);
2269 	else
2270 		fprintf(fp, "<flv name=\"%s\">\n", infile);
2271 
2272 	fprintf(fp, "<hasKeyframes>%s</hasKeyframes>\n", (flv->haskeyframes != 0) ? "true" : "false");
2273 	fprintf(fp, "<hasVideo>%s</hasVideo>\n", (flv->hasvideo != 0) ? "true" : "false");
2274 	fprintf(fp, "<hasAudio>%s</hasAudio>\n", (flv->hasaudio != 0) ? "true" : "false");
2275 	fprintf(fp, "<hasMetadata>true</hasMetadata>\n");
2276 	fprintf(fp, "<hasCuePoints>%s</hasCuePoints>\n", (flv->hascuepoints != 0) ? "true" : "false");
2277 	fprintf(fp, "<canSeekToEnd>%s</canSeekToEnd>\n", (flv->canseektoend != 0) ? "true" : "false");
2278 
2279 	fprintf(fp, "<audiocodecid>%d</audiocodecid>\n", flv->audio.codecid);
2280 	fprintf(fp, "<audiosamplerate>%d</audiosamplerate>\n", flv->audio.samplerate);
2281 	fprintf(fp, "<audiodatarate>%d</audiodatarate>\n", (int)flv->audio.datarate);
2282 	fprintf(fp, "<audiosamplesize>%d</audiosamplesize>\n", flv->audio.samplesize);
2283 	fprintf(fp, "<audiodelay>%.2f</audiodelay>\n", (double)flv->audio.delay);
2284 	fprintf(fp, "<stereo>%s</stereo>\n", (flv->audio.stereo != 0) ? "true" : "false");
2285 
2286 	fprintf(fp, "<videocodecid>%d</videocodecid>\n", flv->video.codecid);
2287 	fprintf(fp, "<framerate>%.2f</framerate>\n", flv->video.framerate);
2288 	fprintf(fp, "<videodatarate>%d</videodatarate>\n", (int)flv->video.datarate);
2289 	fprintf(fp, "<height>%d</height>\n", (int)flv->video.height);
2290 	fprintf(fp, "<width>%d</width>\n", (int)flv->video.width);
2291 
2292 	fprintf(fp, "<datasize>%" PRIu64 "</datasize>\n", flv->datasize);
2293 	fprintf(fp, "<audiosize>%" PRIu64 "</audiosize>\n", flv->audio.size);
2294 	fprintf(fp, "<videosize>%" PRIu64 "</videosize>\n", flv->video.size);
2295 	fprintf(fp, "<filesize>%" PRIu64 "</filesize>\n", flv->filesize);
2296 
2297 	fprintf(fp, "<lasttimestamp>%.2f</lasttimestamp>\n", (double)flv->lasttimestamp / 1000.0);
2298 	fprintf(fp, "<lastvideoframetimestamp>%.2f</lastvideoframetimestamp>\n", (double)flv->video.lasttimestamp / 1000.0);
2299 	fprintf(fp, "<lastkeyframetimestamp>%.2f</lastkeyframetimestamp>\n", (double)flv->keyframes.lastkeyframetimestamp / 1000.0);
2300 	fprintf(fp, "<lastkeyframelocation>%" PRIu64 "</lastkeyframelocation>\n", (uint64_t)flv->keyframes.lastkeyframelocation);
2301 
2302 	if(flv->options.xmlomitkeyframes == 0) {
2303 		fprintf(fp, "<keyframes>\n");
2304 		fprintf(fp, "<times>\n");
2305 
2306 		for(i = 0; i < flv->keyframes.nkeyframes; i++)
2307 			fprintf(fp, "<value id=\"%" PRIu64 "\">%.2f</value>\n", (uint64_t)i, (double)flv->keyframes.keyframetimestamps[i] / 1000.0);
2308 
2309 		fprintf(fp, "</times>\n");
2310 		fprintf(fp, "<filepositions>\n");
2311 
2312 		for(i = 0; i < flv->keyframes.nkeyframes; i++)
2313 			fprintf(fp, "<value id=\"%" PRIu64 "\">%" PRIu64 "</value>\n", (uint64_t)i, (uint64_t)flv->keyframes.keyframelocations[i]);
2314 
2315 		fprintf(fp, "</filepositions>\n");
2316 		fprintf(fp, "</keyframes>\n");
2317 	}
2318 
2319 	fprintf(fp, "<duration>%.2f</duration>\n", (double)flv->lasttimestamp / 1000.0);
2320 	fprintf(fp, "</flv>\n");
2321 	fprintf(fp, "</fileset>\n");
2322 
2323 	return;
2324 }
2325 
printUsage(void)2326 void printUsage(void) {
2327 	fprintf(stderr, "NAME\n");
2328 	fprintf(stderr, "\tyamdi -- Yet Another Metadata Injector for FLV\n");
2329 	fprintf(stderr, "\tVersion: " YAMDI_VERSION "\n");
2330 	fprintf(stderr, "\n");
2331 
2332 	fprintf(stderr, "SYNOPSIS\n");
2333 	fprintf(stderr, "\tyamdi -i input file [-x xml file | -o output file [-x xml file]]\n");
2334 	fprintf(stderr, "\t      [-t temporary file] [-c creator] [-a interval] [-skMXw] [-h]\n");
2335 	fprintf(stderr, "\n");
2336 
2337 	fprintf(stderr, "DESCRIPTION\n");
2338 	fprintf(stderr, "\tyamdi is a metadata injector for FLV files.\n");
2339 	fprintf(stderr, "\n");
2340 	fprintf(stderr, "\tOptions:\n");
2341 	fprintf(stderr, "\n");
2342 	fprintf(stderr, "\t-i\tThe source FLV file. If the file name is '-' the input\n");
2343 	fprintf(stderr, "\t\tfile will be read from stdin. Use the -t option to specify\n");
2344 	fprintf(stderr, "\t\ta temporary file.\n");
2345 	fprintf(stderr, "\n");
2346 	fprintf(stderr, "\t-o\tThe resulting FLV file with the metatags. If the file\n");
2347 	fprintf(stderr, "\t\tname is '-' the output will be written to stdout.\n");
2348 	fprintf(stderr, "\n");
2349 	fprintf(stderr, "\t-x\tAn XML file with the resulting metadata information. If the\n");
2350 	fprintf(stderr, "\t\toutput file is ommited, only metadata will be generated.\n");
2351 	fprintf(stderr, "\n");
2352 	fprintf(stderr, "\t-t\tA temporary file to store the source FLV file in if the\n");
2353 	fprintf(stderr, "\t\tinput file is read from stdin.\n");
2354 	fprintf(stderr, "\n");
2355 	fprintf(stderr, "\t-c\tA string that will be written into the creator tag.\n");
2356 	fprintf(stderr, "\n");
2357 	fprintf(stderr, "\t-s, -l\tAdd the onLastSecond event.\n");
2358 	fprintf(stderr, "\t\tThe -l option is deprecated and will be removed in a future\n");
2359 	fprintf(stderr, "\t\tversion.\n");
2360 	fprintf(stderr, "\n");
2361 	fprintf(stderr, "\t-k\tAdd the onLastKeyframe event.\n");
2362 	fprintf(stderr, "\n");
2363 /*
2364 	fprintf(stderr, "\t-m\tLeave the existing metadata intact.\n");
2365 	fprintf(stderr, "\t\tMetadata that yamdi does not add is left untouched, e.g. onCuepoint.\n");
2366 	fprintf(stderr, "\n");
2367 */
2368 	fprintf(stderr, "\t-M\tStrip all metadata from the FLV. The -s and -k options will\n");
2369 	fprintf(stderr, "\t\tbe ignored.\n");
2370 	fprintf(stderr, "\n");
2371 	fprintf(stderr, "\t-X\tOmit the keyframes tag in the XML output.\n");
2372 	fprintf(stderr, "\n");
2373 	fprintf(stderr, "\t-a\tTime in milliseconds between keyframes if there is only audio.\n");
2374 	fprintf(stderr, "\t\tThis option will be ignored if there is a video stream. No\n");
2375 	fprintf(stderr, "\t\tkeyframes will be added if this option is omitted.\n");
2376 	fprintf(stderr, "\n");
2377 	fprintf(stderr, "\t-w\tReplace the input file with the output file. -i and -o are\n");
2378 	fprintf(stderr, "\t\trequired to be different files otherwise this option will be\n");
2379 	fprintf(stderr, "\t\tignored.\n");
2380 	fprintf(stderr, "\n");
2381 	fprintf(stderr, "\t-h\tThis description.\n");
2382 	fprintf(stderr, "\n");
2383 
2384 	fprintf(stderr, "COPYRIGHT\n");
2385 	fprintf(stderr, "\t(c) 2007+ Ingo Oppermann\n");
2386 	fprintf(stderr, "\n");
2387 	return;
2388 }
2389