added swf_SetVideoStreamBlackFrame().
[swftools.git] / avi2swf / v2swf.c
blobe983c36a4964994010a05133d277b11b1aa63ff5
1 /* v2swf.c
2 part of swftools
4 Copyright (C) 2003 Matthias Kramm <kramm@quiss.org>
6 This program 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.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include "v2swf.h"
24 #include "../lib/rfxswf.h"
25 #include "../lib/q.h"
27 typedef struct _v2swf_internal_t
29 TAG*tag;
31 int filesize;
32 int headersize;
33 int frames;
35 int myframes;
37 struct writer_t out;
38 struct writer_t out2;
40 ringbuffer_t r;
41 videoreader_t* video;
43 int width;
44 int height;
46 unsigned char* vrbuffer;
47 unsigned char* buffer;
48 unsigned char* lastbitmap;
50 int id;
51 int lastid;
53 int quality;
54 int blockdiff;
55 int keyframe_interval;
56 int diffmode;
58 float framerate;
59 float fpsratio;
60 float fpspos;
62 int bitrate;
63 int samplerate;
65 int finished;
66 int keyframe;
67 int showframe;
69 float samplepos;
70 float framesamplepos;
71 int samplewritepos;
72 double soundframepos;
73 int soundstreamhead;
74 int seek;
76 double audio_fix;
77 int fixheader;
78 int prescale;
80 int scale;
82 int domotion;
84 int head_done;
86 int version;
88 VIDEOSTREAM stream;
90 } v2swf_internal_t;
92 static int verbose = 0;
93 static int filelog = 0;
95 static void msg(char*format, ...)
97 char buf[1024];
98 int l;
99 va_list arglist;
100 if(!verbose)
101 return;
102 va_start(arglist, format);
103 vsprintf(buf, format, arglist);
104 va_end(arglist);
105 l = strlen(buf);
106 while(l && buf[l-1]=='\n') {
107 buf[l-1] = 0;
108 l--;
110 if(filelog)
112 FILE*fi = fopen("debug.log", "ab+");
113 fprintf(fi, "(v2swf) %s\n", buf);
114 fflush(fi);
115 fclose(fi);
118 printf("(v2swf) %s\n", buf);
119 fflush(stdout);
122 extern int swf_mp3_in_samplerate;
123 extern int swf_mp3_out_samplerate;
124 extern int swf_mp3_channels;
125 extern int swf_mp3_bitrate;
128 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
130 RGBA rgb;
131 MATRIX m;
132 SHAPE*shape;
133 SRECT r;
134 int lines = 0;
135 int ls,fs;
136 swf_ResetTag(i->tag, ST_DEFINESHAPE);
137 swf_ShapeNew(&shape);
138 rgb.b = rgb.g = rgb.r = 0xff;
139 if(lines)
140 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
141 swf_GetMatrix(NULL,&m);
142 m.sx = 20*65536;
143 m.sy = 20*65536;
145 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
146 swf_SetU16(i->tag,id); // ID
147 r.xmin = 0;
148 r.ymin = 0;
149 r.xmax = width*20;
150 r.ymax = height*20;
151 swf_SetRect(i->tag,&r);
153 swf_SetShapeStyles(i->tag,shape);
154 swf_ShapeCountBits(shape,NULL,NULL);
155 swf_SetShapeBits(i->tag,shape);
157 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
159 swf_ShapeSetLine(i->tag,shape,width*20,0);
160 swf_ShapeSetLine(i->tag,shape,0,height*20);
161 swf_ShapeSetLine(i->tag,shape,-width*20,0);
162 swf_ShapeSetLine(i->tag,shape,0,-height*20);
163 swf_ShapeSetEnd(i->tag);
164 i->filesize += swf_WriteTag2(&i->out, i->tag);
165 swf_ShapeFree(shape);
168 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
170 double pos = 0;
171 double ratio = (double) video->rate * speedup / swf_mp3_in_samplerate;
172 int rlen = (int)(len * ratio);
173 int t;
174 S16 tmp[576*32];
175 int r = /*resampled len */ rlen *
176 /* s16_le */ 2 *
177 video->channels;
178 if(videoreader_getsamples(video, tmp, r) < r)
179 return 0;
181 /* convert to 1 channel */
182 for(t=0;t<rlen;t++) {
183 int s;
184 int a=0;
185 for(s=0;s<video->channels;s++)
186 a += tmp[t*video->channels+s];
187 tmp[t] = a/video->channels;
190 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
191 for(t=0;t<len;t++) {
192 data[t] = tmp[(int)pos];
193 pos+=ratio;
195 return 1;
198 static void writeAudioForOneFrame(v2swf_internal_t* i)
200 int blocksize;
201 double blockspersecond;
202 double framespersecond, framesperblock, samplesperframe, samplesperblock;
203 int seek;
204 int s;
205 double speedup = i->audio_fix;
206 int num = 0;
207 int pos = 0;
208 S16 block1[576*4 * 2];
210 msg("writeAudioForOneFrame()");
212 if(i->video->channels<=0 || i->video->rate<=0)
213 return; /* no sound in video */
215 blocksize = (i->samplerate > 22050) ? 1152 : 576;
216 blockspersecond = ((double)i->samplerate)/blocksize;
218 /* notice: for framerates greater than about 35, audio starts getting choppy. */
219 framespersecond = i->framerate;
221 framesperblock = framespersecond / blockspersecond;
222 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
223 samplesperblock = samplesperframe * framesperblock;
225 msg("samplesperblock: %f", samplesperblock);
227 if(!i->soundstreamhead) {
228 swf_mp3_out_samplerate = i->samplerate;
229 /* The pre-processing of sound samples in getSamples(..) above
230 re-samples the sound to swf_mp3_in_samplerate. It is best to
231 simply make it the original samplerate: */
232 swf_mp3_in_samplerate = i->video->rate;
234 /* first run - initialize */
235 swf_mp3_channels = 1;//i->video->channels;
236 swf_mp3_bitrate = i->bitrate;
237 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
238 /* samplesperframe overrides the movie framerate: */
239 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
240 swf_SetSoundStreamHead(i->tag, samplesperframe);
241 msg("swf_SetSoundStreamHead() done");
242 i->filesize += swf_WriteTag2(&i->out, i->tag);
243 i->soundstreamhead = 1;
246 /* for framerates greater than 19.14, every now and then a frame
247 hasn't a soundstreamblock. Determine whether this is the case.
249 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
250 if(i->frames < i->soundframepos) {
251 msg("SOUND: block skipped\n");
252 i->samplepos += samplesperframe;
253 return;
256 seek = i->seek;
258 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
259 do {
260 i->samplewritepos += blocksize;
261 i->soundframepos += framesperblock;
262 num++;
264 while(i->samplewritepos < i->samplepos);
266 msg("SOUND: number of blocks: %d", num);
268 /* write num frames, max 1 block */
269 for(pos=0;pos<num;pos++) {
270 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
271 i->video->rate = i->video->channels = 0; //end of soundtrack
272 return;
274 if(!pos) {
275 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
276 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
277 } else {
278 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
281 i->filesize += swf_WriteTag2(&i->out, i->tag);
283 i->seek = blocksize - (i->samplewritepos - i->samplepos);
284 i->samplepos += samplesperframe;
287 static void writeShowFrame(v2swf_internal_t* i)
289 do {
290 writeAudioForOneFrame(i);
292 swf_ResetTag(i->tag, ST_SHOWFRAME);
293 i->filesize += swf_WriteTag2(&i->out, i->tag);
295 i->fpspos -= 1.0;
296 i->frames ++;
298 while(i->fpspos >= 1.0);
299 i->showframe = 0;
302 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
304 writeShape(i, shapeid, bmid, width, height);
306 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
307 if(!i->prescale) {
308 MATRIX m;
309 swf_GetMatrix(0, &m);
310 m.sx = m.sy = i->scale;
311 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
312 } else {
313 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
315 i->filesize += swf_WriteTag2(&i->out, i->tag);
317 i->showframe = 1;
320 static int wwrite(struct writer_t*w, void*data, int len)
322 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
323 ringbuffer_put(&i->r, data, len);
324 return len;
327 static void wfinish(struct writer_t*w)
329 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
332 static void writehead(v2swf_internal_t*i)
334 char header[]="FWS\6\0\0\0\4";
335 SWF swf;
336 int ret;
337 int id;
339 header[3] = i->version;
340 if(i->version >= 6) { //MX
341 header[0] = 'C';
343 i->out2.write = wwrite;
344 i->out2.finish = wfinish;
345 i->out2.internal = i;
346 i->out2.type = 77;
347 i->out2.bitpos = 0;
348 i->out2.mybyte = 0;
349 i->out2.pos = 0;
350 writer_init_zlibdeflate(&i->out, &i->out2);
351 } else {
352 i->out.write = wwrite;
353 i->out.finish = wfinish;
354 i->out.internal = i;
355 i->out.type = 77;
356 i->out.bitpos = 0;
357 i->out.mybyte = 0;
358 i->out.pos = 0;
359 i->out2 = i->out;
362 if(i->prescale) {
363 i->width = (int)(i->video->width*(i->scale/65536.0));
364 i->height = (int)(i->video->height*(i->scale/65536.0));
365 } else {
366 i->width = i->video->width;
367 i->height = i->video->height;
369 if(!i->width)
370 i->width = 1;
371 if(!i->height)
372 i->height = 1;
373 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
374 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
376 memset(&swf, 0, sizeof(SWF));
377 swf.fileVersion=i->version;
378 swf.fileSize = 0;
379 swf.frameCount = 65535;
380 swf.movieSize.xmax=i->width*20;
381 swf.movieSize.ymax=i->height*20;
382 swf.compressed = 8; /* 8 = compression done by caller (us) */
383 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
385 /* write the first 8 bytes to out */
386 i->out2.write(&i->out2, header, 8);
388 i->filesize += swf_WriteHeader2(&i->out, &swf);
389 i->headersize = i->filesize;
391 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
392 swf_SetU8(i->tag, 0); //black
393 swf_SetU8(i->tag, 0);
394 swf_SetU8(i->tag, 0);
395 i->filesize += swf_WriteTag2(&i->out, i->tag);
398 static void finish(v2swf_internal_t*i)
400 msg("finish(): i->finished=%d\n", i->finished);
401 if(!i->finished) {
402 msg("write endtag\n", i->finished);
404 swf_ResetTag(i->tag, ST_END);
405 i->filesize += swf_WriteTag2(&i->out, i->tag);
406 i->out.finish(&i->out);
408 if(i->version>=6) {
409 swf_VideoStreamClear(&i->stream);
411 if(i->buffer) {
412 free(i->buffer);i->buffer = 0;
414 if(i->vrbuffer) {
415 free(i->vrbuffer);i->vrbuffer = 0;
417 if(i->lastbitmap) {
418 free(i->lastbitmap);i->lastbitmap = 0;
421 /* FIXME: we shouldn't be doing this. the caller should */
422 msg("call videoreader_close(%08x)\n", i->video);
423 videoreader_close(i->video);
425 i->finished = 1;
427 msg("finishing done\n");
429 static void cleanup(v2swf_internal_t*i)
431 int t;
432 for(t=i->lastid;t<i->id;t++) {
433 if(!(t&1)) {
434 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
435 swf_SetU16(i->tag, t);
436 i->filesize += swf_WriteTag2(&i->out, i->tag);
438 swf_ResetTag(i->tag, ST_FREECHARACTER);
439 swf_SetU16(i->tag, t);
440 i->filesize += swf_WriteTag2(&i->out, i->tag);
442 i->lastid = i->id;
445 #define DIFFMODE_MAX 1
446 #define DIFFMODE_MEAN 2
447 #define DIFFMODE_EXACT 3
448 #define DIFFMODE_QMEAN 4
450 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
452 int x,y;
453 for(y=0;y<yl;y++) {
454 for(x=0;x<xl;x++) {
455 int rd = d1[1] - d2[1];
456 int gd = d1[2] - d2[2];
457 int bd = d1[3] - d2[3];
458 if(rd < 0) rd = -rd;
459 if(gd < 0) gd = -gd;
460 if(bd < 0) bd = -bd;
461 if(rd+gd+bd>maxdiff)
462 return 1;
464 d1+=4; d2+=4;
466 d1 += yadd; d2 += yadd;
468 return 0;
471 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
473 int mean = 0;
474 int x,y;
475 for(y=0;y<yl;y++) {
476 for(x=0;x<xl;x++) {
477 int rd = d1[1] - d2[1];
478 int gd = d1[2] - d2[2];
479 int bd = d1[3] - d2[3];
480 if(rd < 0) rd = -rd;
481 if(gd < 0) gd = -gd;
482 if(bd < 0) bd = -bd;
483 mean += rd+gd+bd;
485 d1+=4; d2+=4;
487 d1 += yadd; d2 += yadd;
489 if(mean/(xl*yl) > maxdiff)
490 return 1;
491 return 0;
494 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
496 int mean = 0;
497 int x,y;
498 for(y=0;y<yl;y++) {
499 for(x=0;x<xl;x++) {
500 int rd = d1[1] - d2[1];
501 int gd = d1[2] - d2[2];
502 int bd = d1[3] - d2[3];
503 int q;
504 if(rd < 0) rd = -rd;
505 if(gd < 0) gd = -gd;
506 if(bd < 0) bd = -bd;
507 q = rd+gd+bd;
508 mean += q*q;
510 d1+=4; d2+=4;
512 d1 += yadd; d2 += yadd;
514 if(mean/(xl*yl) > maxdiff*maxdiff)
515 return 1;
516 return 0;
519 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
521 int x,y;
522 for(y=0;y<yl;y++) {
523 for(x=0;x<xl;x++) {
524 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
525 return 1;
527 d1+=4; d2+=4;
529 d1 += yadd; d2 += yadd;
531 return 0;
534 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
535 U32 g = ((r << 3) ^ r)&0x80808080;
536 if(g)
537 goto differ;*/
539 static void checkInit(v2swf_internal_t*i)
541 if(!i->head_done) {
542 writehead(i);
543 if(i->version>=6) {
544 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
545 swf_SetU16(i->tag, 99);
546 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
547 i->filesize += swf_WriteTag2(&i->out, i->tag);
548 if(i->domotion) {
549 i->stream.do_motion = 1;
552 i->head_done = 1;
556 static void scaleimage(v2swf_internal_t*i)
558 int x,y;
559 int xv,yv;
560 int xm = (i->video->width*65536)/i->width;
561 int ym = (i->video->height*65536)/i->height;
562 memset(i->buffer, 255, i->width*i->height*4);
563 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
564 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
565 int*dest = &((int*)i->buffer)[y*i->width];
566 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
567 dest[x] = src[xv>>16];
570 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
573 static int encodeoneframe(v2swf_internal_t*i)
575 videoreader_t*video = i->video;
576 int ret;
578 checkInit(i);
580 if(videoreader_eof(i->video) || !videoreader_getimage(i->video, i->vrbuffer))
582 msg("videoreader returned eof\n");
583 finish(i);
584 return 0;
587 msg("encoding image for frame %d\n", i->frames);
588 if(i->showframe) {
589 i->fpspos += i->fpsratio;
590 /* skip frames */
591 if(i->fpspos<1.0) {
592 return 0;
594 writeShowFrame(i);
597 msg("scaling\n");
599 scaleimage(i);
601 msg("version is %d\n", i->version);
603 if(i->version <= 4) {
605 int bmid = i->id++;
606 int shapeid = i->id++;
607 int width2 = i->width * 4;
609 if(i->id>=4) {
610 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
611 swf_SetU16(i->tag, i->id-3);
612 i->filesize += swf_WriteTag2(&i->out, i->tag);
613 swf_ResetTag(i->tag, ST_FREECHARACTER);
614 swf_SetU16(i->tag, i->id-4);
615 i->filesize += swf_WriteTag2(&i->out, i->tag);
618 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
619 swf_SetU16(i->tag, bmid);
620 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
621 i->filesize += swf_WriteTag2(&i->out, i->tag);
623 writeShowTags(i, shapeid, bmid, i->width, i->height);
625 } else if(i->version == 5) {
626 int width2 = i->width * 4;
627 int width8 = (i->width+7)/8;
628 int height8 = (i->height+7)/8;
630 /* the idea is here to only update those jpeg 8x8 blocks
631 which actually have changed. This means that we have to keep
632 the bitmap from the last frame for the comparison. */
634 (i->keyframe)--;
635 if(!i->lastbitmap || !i->keyframe) {
636 int t, bmid,shapeid;
637 cleanup(i);
639 if(!i->lastbitmap) {
640 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
641 i->lastbitmap = (U8*)malloc(width2*i->height);
643 memcpy(i->lastbitmap, i->buffer, width2*i->height);
645 i->keyframe = i->keyframe_interval;
647 bmid = i->id++;
648 shapeid = i->id++;
649 width2 = i->width * 4;
650 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
651 swf_SetU16(i->tag, bmid);
652 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
653 i->filesize += swf_WriteTag2(&i->out, i->tag);
655 writeShowTags(i, shapeid, bmid, i->width, i->height);
656 return 1;
657 } else {
658 /* The following looks so ugly because it's somewhat optimized.
659 What it does is walk through all the 8x8 blocks, find those
660 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
661 It also set's alpha to 255 in those who haven't changed, and
662 copies them to lastbitmap.
665 int x8, y8;
666 //int maxdiff = ((100 - i->quality)*256)/100;
667 int maxdiff = i->blockdiff*3;
668 for(y8=0;y8<height8;y8++)
669 for(x8=0;x8<width8;x8++) {
670 int x,y;
671 int xl=8,yl=8;
672 int yadd;
673 U8*d1,*d1b,*d2,*d2b;
674 if(x8*8+xl > i->width)
675 xl = i->width - x8*8;
676 if(y8*8+yl > i->height)
677 yl = i->height - y8*8;
678 d1 = &i->buffer[width2*y8*8+x8*8*4];
679 d1b = d1;
680 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
681 d2b = d2;
682 yadd = width2 - (xl*4);
684 if(i->diffmode == DIFFMODE_MAX) {
685 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
686 goto differ;
687 } else if(i->diffmode == DIFFMODE_MEAN) {
688 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
689 goto differ;
690 } else if(i->diffmode == DIFFMODE_EXACT) {
691 if(blockdiff_exact(d1, d2, yadd, xl, yl))
692 goto differ;
693 } else if(i->diffmode == DIFFMODE_QMEAN) {
694 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
695 goto differ;
698 for(y=0;y<yl;y++) {
699 for(x=0;x<xl;x++) {
700 *(U32*)d1b = 0;
701 d1b+=4;
703 d1b += yadd;
705 continue;
706 differ:
707 for(y=0;y<yl;y++) {
708 for(x=0;x<xl;x++) {
709 *(U32*)d2b = *(U32*)d1b;
710 d1b[0] = 255;
711 d1b+=4;d2b+=4;
713 d1b += yadd; d2b += yadd;
717 /* ok, done. Now a) data is zeroed out in regions which haven't changed
718 b) lastbitmap equals the bitmap we were called with
719 c) data's alpha value is set to 255 in regions which did change */
724 int bmid = i->id++;
725 int shapeid = i->id++;
727 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
728 swf_SetU16(i->tag, bmid);
729 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
730 i->filesize += swf_WriteTag2(&i->out, i->tag);
732 writeShowTags(i, shapeid, bmid, i->width, i->height);
734 } else {
735 int quant = 1+(30-(30*i->quality)/100);
736 SWFPLACEOBJECT obj;
738 swf_GetPlaceObject(0, &obj);
739 if(!i->prescale) {
740 obj.matrix.sx = obj.matrix.sy = i->scale;
743 if(i->stream.frame==0) {
744 obj.depth = 1;
745 obj.id = 99;
746 } else {
747 obj.move = 1;
748 obj.depth = 1;
749 obj.ratio = i->stream.frame;
752 swf_ResetTag(i->tag, ST_VIDEOFRAME);
753 swf_SetU16(i->tag, 99);
754 if(!(--i->keyframe)) {
755 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
756 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
757 i->keyframe = i->keyframe_interval;
758 } else {
759 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
760 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
762 i->filesize += swf_WriteTag2(&i->out, i->tag);
764 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
765 swf_SetPlaceObject(i->tag,&obj);
766 i->filesize += swf_WriteTag2(&i->out, i->tag);
767 i->showframe = 1;
769 return 1;
772 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
774 int ret = 0;
775 int t=0;
776 v2swf_internal_t* i;
777 msg("v2swf_init()\n");
778 memset(v2swf, 0, sizeof(v2swf_t));
779 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
780 memset(i, 0, sizeof(v2swf_internal_t));
781 v2swf->internal = i;
783 ringbuffer_init(&i->r);
785 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
787 i->video = video;
788 i->blockdiff = 64;
789 i->keyframe_interval = 8;
790 i->quality = 20;
791 i->scale = 65536;
792 i->samplerate = 11025;
793 i->prescale = 0;
794 i->head_done = 0;
795 i->diffmode = DIFFMODE_QMEAN;
796 i->audio_fix = 1.0;
797 i->fixheader = 0;
798 i->framerate = video->fps;
799 i->fpsratio = 1.00000000000;
800 i->fpspos = 0.0;
801 i->bitrate = 32;
802 i->version = 6;
803 i->buffer = 0;
804 i->lastbitmap = 0;
805 i->filesize = 8;
806 i->frames = 0;
807 i->id = 1;
808 i->lastid = 1;
809 i->keyframe = 1;
810 i->showframe = 0;
812 memset(&i->out, 0, sizeof(struct writer_t));
813 memset(&i->out2, 0, sizeof(struct writer_t));
815 return 0;
817 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
819 v2swf_internal_t* i;
820 int l;
821 msg("v2swf_read(%d)\n", len);
822 i = (v2swf_internal_t*)v2swf->internal;
824 while(!i->finished && i->r.available < len) {
825 if(!encodeoneframe(i)) {
826 break;
829 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
830 l = ringbuffer_read(&i->r, buffer, len);
832 return l;
834 void v2swf_close(v2swf_t*v2swf)
836 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
837 msg("close(): i->finished=%d\n", i->finished);
839 /* needed only if aborting: */
840 finish(i);
842 msg("freeing memory\n");
843 free(v2swf->internal);
844 memset(v2swf, 0, sizeof(v2swf_t));
845 msg("close() done\n");
848 static int mp3_bitrates[] =
849 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
851 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
853 v2swf_internal_t* i;
855 msg("set parameters %s to %s\n", name, value);
857 if(!strcmp(name, "verbose")) {
858 verbose = 1;
859 msg("set parameters %s to %s\n", name, value);
860 return;
863 if(!v2swf || !v2swf->internal) {
864 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
865 return;
867 i = (v2swf_internal_t*)v2swf->internal;
869 if(!strcmp(name, "flash_version")) {
870 i->version = atoi(value);
871 } else if(!strcmp(name, "audiosync")) {
872 i->audio_fix = (int)(atof(value));
873 } else if(!strcmp(name, "scale")) {
874 i->scale = (int)(atof(value)*65536);
875 } else if(!strcmp(name, "scale65536")) {
876 i->scale = atoi(value);
877 } else if(!strcmp(name, "quality")) {
878 i->quality = atoi(value);
879 } else if(!strcmp(name, "motioncompensation")) {
880 i->domotion = atoi(value);
881 } else if(!strcmp(name, "prescale")) {
882 i->prescale = atoi(value);
883 } else if(!strcmp(name, "blockdiff")) {
884 i->blockdiff = atoi(value);
885 } else if(!strcmp(name, "fixheader")) {
886 i->fixheader = atoi(value);
887 } else if(!strcmp(name, "samplerate")) {
888 i->samplerate = atoi(value);
889 } else if(!strcmp(name, "framerate")) {
890 i->framerate = atof(value);
891 i->fpsratio = i->framerate / i->video->fps;
893 else if(!strcmp(name, "mp3_bitrate")) {
894 int t=0,o;
895 i->bitrate = o = atoi(value);
896 if(i->bitrate>160)
897 i->bitrate = 160;
898 while(mp3_bitrates[t]) {
899 if(i->bitrate <= mp3_bitrates[t]) {
900 i->bitrate = mp3_bitrates[t];
901 break;
903 t++;
905 msg("bitrate %d requested, setting to %d", o, i->bitrate);
907 else if(!strcmp(name, "blockdiff_mode")) {
908 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
909 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
910 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
911 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
912 else {
913 printf("diffmode %s not recognized\n", value);
914 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
917 else if(!strcmp(name, "keyframe_interval")
918 || !strcmp(name, "keyframe")) {
919 int k = atoi(value);if(k<=0) k=1;
920 i->keyframe_interval = k;
922 else {
923 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
924 return;
927 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
929 FILE* fi;
930 unsigned char f;
931 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
932 msg("v2swf_backpatch %s\n", filename);
933 if(!i) {
934 printf("call backpatch before close\n");fflush(stdout);
936 fi = fopen(filename, "rb+");
937 if(!fi) {
938 printf("can't open %s\n", filename);
939 exit(1);
941 fseek(fi, 4, SEEK_SET);
942 f = i->filesize ;fwrite(&f,1,1,fi);
943 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
944 f = i->filesize >> 16;fwrite(&f,1,1,fi);
945 f = i->filesize >> 24;fwrite(&f,1,1,fi);
946 if(i->version<6) {
947 /* no compression- we can backpatch the frames too */
948 fseek(fi, i->headersize-2, SEEK_SET);
949 f = i->frames ;fwrite(&f,1,1,fi);
950 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
952 fclose(fi);
953 if(i->fixheader) {
954 SWF tmp;
955 int fi;
956 msg("v2swf_backpatch %s - fix header\n", filename);
957 memset(&tmp, 0, sizeof(tmp));
958 fi = open(filename, O_RDONLY|O_BINARY);
959 if(fi>=0) {
960 if(swf_ReadSWF(fi, &tmp)>=0) {
961 close(fi);
962 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
963 if(fi>=0) {
964 swf_WriteSWC(fi, &tmp);
965 close(fi);
966 msg("v2swf_backpatch %s - fix header: success\n", filename);
973 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
975 msg("v2swf_setvideoparameter()");
976 videoreader_setparameter(v, name, value);