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 */
24 #include "../lib/rfxswf.h"
27 typedef struct _v2swf_internal_t
50 unsigned char* vrbuffer;
51 unsigned char* buffer;
52 unsigned char* lastbitmap;
59 int keyframe_interval;
96 static int verbose = 0;
97 static int filelog = 0;
99 static void msg(char*format, ...)
106 va_start(arglist, format);
107 vsprintf(buf, format, arglist);
110 while(l && buf[l-1]=='\n') {
116 FILE*fi = fopen("debug.log", "ab+");
117 fprintf(fi, "(v2swf) %s\n", buf);
122 printf("(v2swf) %s\n", buf);
126 extern int swf_mp3_in_samplerate;
127 extern int swf_mp3_out_samplerate;
128 extern int swf_mp3_channels;
129 extern int swf_mp3_bitrate;
132 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
140 swf_ResetTag(i->tag, ST_DEFINESHAPE);
141 swf_ShapeNew(&shape);
142 rgb.b = rgb.g = rgb.r = 0xff;
144 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
145 swf_GetMatrix(NULL,&m);
149 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
150 swf_SetU16(i->tag,id); // ID
155 swf_SetRect(i->tag,&r);
157 swf_SetShapeStyles(i->tag,shape);
158 swf_ShapeCountBits(shape,NULL,NULL);
159 swf_SetShapeBits(i->tag,shape);
161 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
163 swf_ShapeSetLine(i->tag,shape,width*20,0);
164 swf_ShapeSetLine(i->tag,shape,0,height*20);
165 swf_ShapeSetLine(i->tag,shape,-width*20,0);
166 swf_ShapeSetLine(i->tag,shape,0,-height*20);
167 swf_ShapeSetEnd(i->tag);
168 i->filesize += swf_WriteTag2(&i->out, i->tag);
169 swf_ShapeFree(shape);
172 /* returns 0 on partial read */
173 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
176 double ratio = (double) video->samplerate * speedup / swf_mp3_in_samplerate;
177 int rlen = (int)(len * ratio);
180 int r = /*resampled len */ rlen *
184 memset(tmp, 0, sizeof(tmp));
185 l = videoreader_getsamples(video, tmp, r);
189 msg("%d samples read", l);
191 /* convert to 1 channel */
192 for(t=0;t<rlen;t++) {
195 for(s=0;s<video->channels;s++)
196 a += tmp[t*video->channels+s];
197 tmp[t] = a/video->channels;
200 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
202 data[t] = tmp[(int)pos];
208 static void writeAudioForOneFrame(v2swf_internal_t* i)
211 double blockspersecond;
212 double framespersecond, framesperblock, samplesperframe, samplesperblock;
215 double speedup = i->audio_fix;
218 S16 block1[576*4 * 2];
220 msg("writeAudioForOneFrame()");
222 if(i->audio_eof || i->video->channels<=0 || i->video->samplerate<=0) {
224 return; /* no sound in video */
227 blocksize = (i->samplerate > 22050) ? 1152 : 576;
228 blockspersecond = ((double)i->samplerate)/blocksize;
230 /* notice: for framerates greater than about 35, audio starts getting choppy. */
231 framespersecond = i->framerate;
233 framesperblock = framespersecond / blockspersecond;
234 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
235 samplesperblock = samplesperframe * framesperblock;
237 msg("samplesperblock: %f", samplesperblock);
239 if(!i->soundstreamhead) {
240 swf_mp3_out_samplerate = i->samplerate;
241 /* The pre-processing of sound samples in getSamples(..) above
242 re-samples the sound to swf_mp3_in_samplerate. It is best to
243 simply make it the original samplerate: */
244 swf_mp3_in_samplerate = i->video->samplerate;
246 /* first run - initialize */
247 swf_mp3_channels = 1;//i->video->channels;
248 swf_mp3_bitrate = i->bitrate;
249 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
250 /* samplesperframe overrides the movie framerate: */
251 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
252 swf_SetSoundStreamHead(i->tag, samplesperframe);
253 msg("swf_SetSoundStreamHead() done");
254 i->filesize += swf_WriteTag2(&i->out, i->tag);
255 i->soundstreamhead = 1;
258 /* for framerates greater than 19.14, every now and then a frame
259 hasn't a soundstreamblock. Determine whether this is the case.
261 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
262 if(i->frames < i->soundframepos) {
263 msg("SOUND: block skipped\n");
264 i->samplepos += samplesperframe;
270 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
272 i->samplewritepos += blocksize;
273 i->soundframepos += framesperblock;
276 while(i->samplewritepos < i->samplepos);
278 msg("SOUND: number of blocks: %d", num);
280 /* write num frames, max 1 block */
281 for(pos=0;pos<num;pos++) {
282 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
283 i->audio_eof = 1; i->video->samplerate = i->video->channels = 0; //end of soundtrack
284 /* fall through, this probably was a partial read. (We did, after all,
285 come to this point, so i->audio_eof must have been false so far) */
288 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
289 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
291 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
294 i->filesize += swf_WriteTag2(&i->out, i->tag);
296 i->seek = blocksize - (i->samplewritepos - i->samplepos);
297 i->samplepos += samplesperframe;
300 static void writeShowFrame(v2swf_internal_t* i)
303 writeAudioForOneFrame(i);
305 swf_ResetTag(i->tag, ST_SHOWFRAME);
306 i->filesize += swf_WriteTag2(&i->out, i->tag);
311 while(i->fpspos >= 1.0);
315 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
317 writeShape(i, shapeid, bmid, width, height);
319 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
322 swf_GetMatrix(0, &m);
323 m.sx = m.sy = i->scale;
324 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
326 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
328 i->filesize += swf_WriteTag2(&i->out, i->tag);
333 static int wwrite(struct writer_t*w, void*data, int len)
335 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
336 ringbuffer_put(&i->r, data, len);
340 static void wfinish(struct writer_t*w)
342 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
345 static void writehead(v2swf_internal_t*i)
347 char header[]="FWS\6\0\0\0\4";
352 header[3] = i->version;
353 if(i->version >= 6) { //MX
356 i->out2.write = wwrite;
357 i->out2.finish = wfinish;
358 i->out2.internal = i;
363 writer_init_zlibdeflate(&i->out, &i->out2);
365 i->out.write = wwrite;
366 i->out.finish = wfinish;
376 i->width = (int)(i->video->width*(i->scale/65536.0));
377 i->height = (int)(i->video->height*(i->scale/65536.0));
379 i->width = i->video->width;
380 i->height = i->video->height;
386 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
387 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
389 memset(&swf, 0, sizeof(SWF));
390 swf.fileVersion=i->version;
392 swf.frameCount = 65535;
393 swf.movieSize.xmax=i->width*20;
394 swf.movieSize.ymax=i->height*20;
395 swf.compressed = 8; /* 8 = compression done by caller (us) */
396 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
398 /* write the first 8 bytes to out */
399 i->out2.write(&i->out2, header, 8);
401 i->filesize += swf_WriteHeader2(&i->out, &swf);
402 i->headersize = i->filesize;
404 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
405 swf_SetU8(i->tag, 0); //black
406 swf_SetU8(i->tag, 0);
407 swf_SetU8(i->tag, 0);
408 i->filesize += swf_WriteTag2(&i->out, i->tag);
411 static void finish(v2swf_internal_t*i)
413 msg("finish(): i->finished=%d\n", i->finished);
415 msg("write endtag\n", i->finished);
417 swf_ResetTag(i->tag, ST_END);
418 i->filesize += swf_WriteTag2(&i->out, i->tag);
419 i->out.finish(&i->out);
422 swf_VideoStreamClear(&i->stream);
425 free(i->buffer);i->buffer = 0;
428 free(i->vrbuffer);i->vrbuffer = 0;
431 free(i->lastbitmap);i->lastbitmap = 0;
434 /* FIXME: we shouldn't be doing this. the caller should */
435 msg("call videoreader_close(%08x)\n", i->video);
436 videoreader_close(i->video);
440 msg("finishing done\n");
442 static void cleanup(v2swf_internal_t*i)
445 for(t=i->lastid;t<i->id;t++) {
447 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
448 swf_SetU16(i->tag, t);
449 i->filesize += swf_WriteTag2(&i->out, i->tag);
451 swf_ResetTag(i->tag, ST_FREECHARACTER);
452 swf_SetU16(i->tag, t);
453 i->filesize += swf_WriteTag2(&i->out, i->tag);
458 #define DIFFMODE_MAX 1
459 #define DIFFMODE_MEAN 2
460 #define DIFFMODE_EXACT 3
461 #define DIFFMODE_QMEAN 4
463 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
468 int rd = d1[1] - d2[1];
469 int gd = d1[2] - d2[2];
470 int bd = d1[3] - d2[3];
479 d1 += yadd; d2 += yadd;
484 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
490 int rd = d1[1] - d2[1];
491 int gd = d1[2] - d2[2];
492 int bd = d1[3] - d2[3];
500 d1 += yadd; d2 += yadd;
502 if(mean/(xl*yl) > maxdiff)
507 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
513 int rd = d1[1] - d2[1];
514 int gd = d1[2] - d2[2];
515 int bd = d1[3] - d2[3];
525 d1 += yadd; d2 += yadd;
527 if(mean/(xl*yl) > maxdiff*maxdiff)
532 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
537 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
542 d1 += yadd; d2 += yadd;
547 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
548 U32 g = ((r << 3) ^ r)&0x80808080;
552 static void checkInit(v2swf_internal_t*i)
557 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
558 swf_SetU16(i->tag, 99);
559 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
560 i->filesize += swf_WriteTag2(&i->out, i->tag);
562 i->stream.do_motion = 1;
569 static void scaleimage(v2swf_internal_t*i)
573 int xm = (i->video->width*65536)/i->width;
574 int ym = (i->video->height*65536)/i->height;
575 msg("scaling from %dx%d to %dx%d\n",
576 i->video->width, i->video->height,
580 memset(i->buffer, 255, i->width*i->height*4);
581 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
582 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
583 int*dest = &((int*)i->buffer)[y*i->width];
584 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
585 dest[x] = src[xv>>16];
588 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
591 static int writeAudioOnly(v2swf_internal_t*i)
594 i->fpspos += i->fpsratio;
605 static int encodeoneframe(v2swf_internal_t*i)
607 videoreader_t*video = i->video;
612 if(i->video_eof && i->audio_eof) {
618 if(!i->audio_eof && i->video_eof) {
619 return writeAudioOnly(i);
622 if(!videoreader_getimage(i->video, i->vrbuffer))
625 msg("videoreader returned eof\n");
630 return writeAudioOnly(i);
634 msg("encoding image for frame %d\n", i->frames);
636 i->fpspos += i->fpsratio;
646 msg("version is %d\n", i->version);
648 if(i->version <= 4) {
651 int shapeid = i->id++;
652 int width2 = i->width * 4;
655 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
656 swf_SetU16(i->tag, i->id-3);
657 i->filesize += swf_WriteTag2(&i->out, i->tag);
658 swf_ResetTag(i->tag, ST_FREECHARACTER);
659 swf_SetU16(i->tag, i->id-4);
660 i->filesize += swf_WriteTag2(&i->out, i->tag);
663 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
664 swf_SetU16(i->tag, bmid);
665 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
666 i->filesize += swf_WriteTag2(&i->out, i->tag);
668 writeShowTags(i, shapeid, bmid, i->width, i->height);
670 } else if(i->version == 5) {
671 int width2 = i->width * 4;
672 int width8 = (i->width+7)/8;
673 int height8 = (i->height+7)/8;
675 /* the idea is here to only update those jpeg 8x8 blocks
676 which actually have changed. This means that we have to keep
677 the bitmap from the last frame for the comparison. */
680 if(!i->lastbitmap || !i->keyframe) {
685 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
686 i->lastbitmap = (U8*)malloc(width2*i->height);
688 memcpy(i->lastbitmap, i->buffer, width2*i->height);
690 i->keyframe = i->keyframe_interval;
694 width2 = i->width * 4;
695 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
696 swf_SetU16(i->tag, bmid);
697 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
698 i->filesize += swf_WriteTag2(&i->out, i->tag);
700 writeShowTags(i, shapeid, bmid, i->width, i->height);
703 /* The following looks so ugly because it's somewhat optimized.
704 What it does is walk through all the 8x8 blocks, find those
705 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
706 It also set's alpha to 255 in those who haven't changed, and
707 copies them to lastbitmap.
711 //int maxdiff = ((100 - i->quality)*256)/100;
712 int maxdiff = i->blockdiff*3;
713 for(y8=0;y8<height8;y8++)
714 for(x8=0;x8<width8;x8++) {
719 if(x8*8+xl > i->width)
720 xl = i->width - x8*8;
721 if(y8*8+yl > i->height)
722 yl = i->height - y8*8;
723 d1 = &i->buffer[width2*y8*8+x8*8*4];
725 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
727 yadd = width2 - (xl*4);
729 if(i->diffmode == DIFFMODE_MAX) {
730 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
732 } else if(i->diffmode == DIFFMODE_MEAN) {
733 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
735 } else if(i->diffmode == DIFFMODE_EXACT) {
736 if(blockdiff_exact(d1, d2, yadd, xl, yl))
738 } else if(i->diffmode == DIFFMODE_QMEAN) {
739 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
754 *(U32*)d2b = *(U32*)d1b;
758 d1b += yadd; d2b += yadd;
762 /* ok, done. Now a) data is zeroed out in regions which haven't changed
763 b) lastbitmap equals the bitmap we were called with
764 c) data's alpha value is set to 255 in regions which did change */
770 int shapeid = i->id++;
772 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
773 swf_SetU16(i->tag, bmid);
774 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
775 i->filesize += swf_WriteTag2(&i->out, i->tag);
777 writeShowTags(i, shapeid, bmid, i->width, i->height);
780 int quant = 1+(30-(30*i->quality)/100);
783 swf_GetPlaceObject(0, &obj);
785 obj.matrix.sx = obj.matrix.sy = i->scale;
788 if(i->stream.frame==0) {
794 obj.ratio = i->stream.frame;
797 swf_ResetTag(i->tag, ST_VIDEOFRAME);
798 swf_SetU16(i->tag, 99);
799 if(!(--i->keyframe)) {
800 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
801 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
802 i->keyframe = i->keyframe_interval;
804 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
805 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
807 i->filesize += swf_WriteTag2(&i->out, i->tag);
809 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
810 swf_SetPlaceObject(i->tag,&obj);
811 i->filesize += swf_WriteTag2(&i->out, i->tag);
817 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
822 msg("v2swf_init()\n");
823 memset(v2swf, 0, sizeof(v2swf_t));
824 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
825 memset(i, 0, sizeof(v2swf_internal_t));
828 ringbuffer_init(&i->r);
830 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
833 i->video_fps = ((int)(video->fps*256))/256.0;
835 i->keyframe_interval = 8;
838 i->samplerate = 11025;
841 i->diffmode = DIFFMODE_QMEAN;
844 i->framerate = i->video_fps;
845 i->fpsratio = 1.00000000000;
858 memset(&i->out, 0, sizeof(struct writer_t));
859 memset(&i->out2, 0, sizeof(struct writer_t));
863 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
867 msg("v2swf_read(%d)\n", len);
868 i = (v2swf_internal_t*)v2swf->internal;
870 while(!i->finished && i->r.available < len) {
871 if(!encodeoneframe(i)) {
875 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
876 l = ringbuffer_read(&i->r, buffer, len);
880 void v2swf_close(v2swf_t*v2swf)
882 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
883 msg("close(): i->finished=%d\n", i->finished);
885 /* needed only if aborting: */
888 msg("freeing memory\n");
889 free(v2swf->internal);
890 memset(v2swf, 0, sizeof(v2swf_t));
891 msg("close() done\n");
894 static int mp3_bitrates[] =
895 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
897 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
901 msg("set parameters %s to %s\n", name, value);
903 if(!strcmp(name, "verbose")) {
905 msg("set parameters %s to %s\n", name, value);
909 if(!v2swf || !v2swf->internal) {
910 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
913 i = (v2swf_internal_t*)v2swf->internal;
915 if(!strcmp(name, "flash_version")) {
916 i->version = atoi(value);
917 } else if(!strcmp(name, "audiosync")) {
918 i->audio_fix = (int)(atof(value));
919 } else if(!strcmp(name, "scale")) {
920 i->scale = (int)(atof(value)*65536);
921 } else if(!strcmp(name, "scale65536")) {
922 i->scale = atoi(value);
923 } else if(!strcmp(name, "quality")) {
924 i->quality = atoi(value);
925 } else if(!strcmp(name, "motioncompensation")) {
926 i->domotion = atoi(value);
927 } else if(!strcmp(name, "prescale")) {
928 i->prescale = atoi(value);
929 } else if(!strcmp(name, "blockdiff")) {
930 i->blockdiff = atoi(value);
931 } else if(!strcmp(name, "fixheader")) {
932 i->fixheader = atoi(value);
933 } else if(!strcmp(name, "samplerate")) {
934 i->samplerate = atoi(value);
935 } else if(!strcmp(name, "framerate")) {
936 i->framerate = atof(value);
937 i->fpsratio = i->framerate / i->video_fps;
939 else if(!strcmp(name, "mp3_bitrate")) {
941 i->bitrate = o = atoi(value);
944 while(mp3_bitrates[t]) {
945 if(i->bitrate <= mp3_bitrates[t]) {
946 i->bitrate = mp3_bitrates[t];
951 msg("bitrate %d requested, setting to %d", o, i->bitrate);
953 else if(!strcmp(name, "blockdiff_mode")) {
954 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
955 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
956 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
957 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
959 printf("diffmode %s not recognized\n", value);
960 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
963 else if(!strcmp(name, "keyframe_interval")
964 || !strcmp(name, "keyframe")) {
965 int k = atoi(value);if(k<=0) k=1;
966 i->keyframe_interval = k;
969 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
973 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
977 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
978 msg("v2swf_backpatch %s\n", filename);
980 printf("call backpatch before close\n");fflush(stdout);
982 fi = fopen(filename, "rb+");
984 printf("can't open %s\n", filename);
987 fseek(fi, 4, SEEK_SET);
988 f = i->filesize ;fwrite(&f,1,1,fi);
989 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
990 f = i->filesize >> 16;fwrite(&f,1,1,fi);
991 f = i->filesize >> 24;fwrite(&f,1,1,fi);
993 /* no compression- we can backpatch the frames too */
994 fseek(fi, i->headersize-2, SEEK_SET);
995 f = i->frames ;fwrite(&f,1,1,fi);
996 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
1002 msg("v2swf_backpatch %s - fix header\n", filename);
1003 memset(&tmp, 0, sizeof(tmp));
1004 fi = open(filename, O_RDONLY|O_BINARY);
1006 if(swf_ReadSWF(fi, &tmp)>=0) {
1008 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
1010 swf_WriteSWC(fi, &tmp);
1012 msg("v2swf_backpatch %s - fix header: success\n", filename);
1019 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
1021 msg("v2swf_setvideoparameter()");
1022 videoreader_setparameter(v, name, value);