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
49 unsigned char* vrbuffer;
50 unsigned char* buffer;
51 unsigned char* lastbitmap;
58 int keyframe_interval;
95 static int verbose = 0;
96 static int filelog = 0;
98 static void msg(char*format, ...)
105 va_start(arglist, format);
106 vsprintf(buf, format, arglist);
109 while(l && buf[l-1]=='\n') {
115 FILE*fi = fopen("debug.log", "ab+");
116 fprintf(fi, "(v2swf) %s\n", buf);
121 printf("(v2swf) %s\n", buf);
125 extern int swf_mp3_in_samplerate;
126 extern int swf_mp3_out_samplerate;
127 extern int swf_mp3_channels;
128 extern int swf_mp3_bitrate;
131 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
139 swf_ResetTag(i->tag, ST_DEFINESHAPE);
140 swf_ShapeNew(&shape);
141 rgb.b = rgb.g = rgb.r = 0xff;
143 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
144 swf_GetMatrix(NULL,&m);
148 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
149 swf_SetU16(i->tag,id); // ID
154 swf_SetRect(i->tag,&r);
156 swf_SetShapeStyles(i->tag,shape);
157 swf_ShapeCountBits(shape,NULL,NULL);
158 swf_SetShapeBits(i->tag,shape);
160 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
162 swf_ShapeSetLine(i->tag,shape,width*20,0);
163 swf_ShapeSetLine(i->tag,shape,0,height*20);
164 swf_ShapeSetLine(i->tag,shape,-width*20,0);
165 swf_ShapeSetLine(i->tag,shape,0,-height*20);
166 swf_ShapeSetEnd(i->tag);
167 i->filesize += swf_WriteTag2(&i->out, i->tag);
168 swf_ShapeFree(shape);
171 /* returns 0 on partial read */
172 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
175 double ratio = (double) video->samplerate * speedup / swf_mp3_in_samplerate;
176 int rlen = (int)(len * ratio);
179 int r = /*resampled len */ rlen *
183 memset(tmp, 0, sizeof(tmp));
184 l = videoreader_getsamples(video, tmp, r);
188 msg("%d samples read", l);
190 /* convert to 1 channel */
191 for(t=0;t<rlen;t++) {
194 for(s=0;s<video->channels;s++)
195 a += tmp[t*video->channels+s];
196 tmp[t] = a/video->channels;
199 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
201 data[t] = tmp[(int)pos];
207 static void writeAudioForOneFrame(v2swf_internal_t* i)
210 double blockspersecond;
211 double framespersecond, framesperblock, samplesperframe, samplesperblock;
214 double speedup = i->audio_fix;
217 S16 block1[576*4 * 2];
219 msg("writeAudioForOneFrame()");
221 if(i->audio_eof || i->video->channels<=0 || i->video->samplerate<=0) {
223 return; /* no sound in video */
226 blocksize = (i->samplerate > 22050) ? 1152 : 576;
227 blockspersecond = ((double)i->samplerate)/blocksize;
229 /* notice: for framerates greater than about 35, audio starts getting choppy. */
230 framespersecond = i->framerate;
232 framesperblock = framespersecond / blockspersecond;
233 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
234 samplesperblock = samplesperframe * framesperblock;
236 msg("samplesperblock: %f", samplesperblock);
238 if(!i->soundstreamhead) {
239 swf_mp3_out_samplerate = i->samplerate;
240 /* The pre-processing of sound samples in getSamples(..) above
241 re-samples the sound to swf_mp3_in_samplerate. It is best to
242 simply make it the original samplerate: */
243 swf_mp3_in_samplerate = i->video->samplerate;
245 /* first run - initialize */
246 swf_mp3_channels = 1;//i->video->channels;
247 swf_mp3_bitrate = i->bitrate;
248 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
249 /* samplesperframe overrides the movie framerate: */
250 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
251 swf_SetSoundStreamHead(i->tag, samplesperframe);
252 msg("swf_SetSoundStreamHead() done");
253 i->filesize += swf_WriteTag2(&i->out, i->tag);
254 i->soundstreamhead = 1;
257 /* for framerates greater than 19.14, every now and then a frame
258 hasn't a soundstreamblock. Determine whether this is the case.
260 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
261 if(i->frames < i->soundframepos) {
262 msg("SOUND: block skipped\n");
263 i->samplepos += samplesperframe;
269 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
271 i->samplewritepos += blocksize;
272 i->soundframepos += framesperblock;
275 while(i->samplewritepos < i->samplepos);
277 msg("SOUND: number of blocks: %d", num);
279 /* write num frames, max 1 block */
280 for(pos=0;pos<num;pos++) {
281 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
282 i->audio_eof = 1; i->video->samplerate = i->video->channels = 0; //end of soundtrack
283 /* fall through, this probably was a partial read. (We did, after all,
284 come to this point, so i->audio_eof must have been false so far) */
287 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
288 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
290 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
293 i->filesize += swf_WriteTag2(&i->out, i->tag);
295 i->seek = blocksize - (i->samplewritepos - i->samplepos);
296 i->samplepos += samplesperframe;
299 static void writeShowFrame(v2swf_internal_t* i)
302 writeAudioForOneFrame(i);
304 swf_ResetTag(i->tag, ST_SHOWFRAME);
305 i->filesize += swf_WriteTag2(&i->out, i->tag);
310 while(i->fpspos >= 1.0);
314 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
316 writeShape(i, shapeid, bmid, width, height);
318 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
321 swf_GetMatrix(0, &m);
322 m.sx = m.sy = i->scale;
323 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
325 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
327 i->filesize += swf_WriteTag2(&i->out, i->tag);
332 static int wwrite(struct writer_t*w, void*data, int len)
334 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
335 ringbuffer_put(&i->r, data, len);
339 static void wfinish(struct writer_t*w)
341 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
344 static void writehead(v2swf_internal_t*i)
346 char header[]="FWS\6\0\0\0\4";
351 header[3] = i->version;
352 if(i->version >= 6) { //MX
355 i->out2.write = wwrite;
356 i->out2.finish = wfinish;
357 i->out2.internal = i;
362 writer_init_zlibdeflate(&i->out, &i->out2);
364 i->out.write = wwrite;
365 i->out.finish = wfinish;
375 i->width = (int)(i->video->width*(i->scale/65536.0));
376 i->height = (int)(i->video->height*(i->scale/65536.0));
378 i->width = i->video->width;
379 i->height = i->video->height;
385 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
386 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
388 memset(&swf, 0, sizeof(SWF));
389 swf.fileVersion=i->version;
391 swf.frameCount = 65535;
392 swf.movieSize.xmax=i->width*20;
393 swf.movieSize.ymax=i->height*20;
394 swf.compressed = 8; /* 8 = compression done by caller (us) */
395 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
397 /* write the first 8 bytes to out */
398 i->out2.write(&i->out2, header, 8);
400 i->filesize += swf_WriteHeader2(&i->out, &swf);
401 i->headersize = i->filesize;
403 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
404 swf_SetU8(i->tag, 0); //black
405 swf_SetU8(i->tag, 0);
406 swf_SetU8(i->tag, 0);
407 i->filesize += swf_WriteTag2(&i->out, i->tag);
410 static void finish(v2swf_internal_t*i)
412 msg("finish(): i->finished=%d\n", i->finished);
414 msg("write endtag\n", i->finished);
416 swf_ResetTag(i->tag, ST_END);
417 i->filesize += swf_WriteTag2(&i->out, i->tag);
418 i->out.finish(&i->out);
421 swf_VideoStreamClear(&i->stream);
424 free(i->buffer);i->buffer = 0;
427 free(i->vrbuffer);i->vrbuffer = 0;
430 free(i->lastbitmap);i->lastbitmap = 0;
433 /* FIXME: we shouldn't be doing this. the caller should */
434 msg("call videoreader_close(%08x)\n", i->video);
435 videoreader_close(i->video);
439 msg("finishing done\n");
441 static void cleanup(v2swf_internal_t*i)
444 for(t=i->lastid;t<i->id;t++) {
446 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
447 swf_SetU16(i->tag, t);
448 i->filesize += swf_WriteTag2(&i->out, i->tag);
450 swf_ResetTag(i->tag, ST_FREECHARACTER);
451 swf_SetU16(i->tag, t);
452 i->filesize += swf_WriteTag2(&i->out, i->tag);
457 #define DIFFMODE_MAX 1
458 #define DIFFMODE_MEAN 2
459 #define DIFFMODE_EXACT 3
460 #define DIFFMODE_QMEAN 4
462 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
467 int rd = d1[1] - d2[1];
468 int gd = d1[2] - d2[2];
469 int bd = d1[3] - d2[3];
478 d1 += yadd; d2 += yadd;
483 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
489 int rd = d1[1] - d2[1];
490 int gd = d1[2] - d2[2];
491 int bd = d1[3] - d2[3];
499 d1 += yadd; d2 += yadd;
501 if(mean/(xl*yl) > maxdiff)
506 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
512 int rd = d1[1] - d2[1];
513 int gd = d1[2] - d2[2];
514 int bd = d1[3] - d2[3];
524 d1 += yadd; d2 += yadd;
526 if(mean/(xl*yl) > maxdiff*maxdiff)
531 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
536 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
541 d1 += yadd; d2 += yadd;
546 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
547 U32 g = ((r << 3) ^ r)&0x80808080;
551 static void checkInit(v2swf_internal_t*i)
556 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
557 swf_SetU16(i->tag, 99);
558 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
559 i->filesize += swf_WriteTag2(&i->out, i->tag);
561 i->stream.do_motion = 1;
568 static void scaleimage(v2swf_internal_t*i)
572 int xm = (i->video->width*65536)/i->width;
573 int ym = (i->video->height*65536)/i->height;
574 msg("scaling from %dx%d to %dx%d\n",
575 i->video->width, i->video->height,
579 memset(i->buffer, 255, i->width*i->height*4);
580 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
581 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
582 int*dest = &((int*)i->buffer)[y*i->width];
583 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
584 dest[x] = src[xv>>16];
587 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
590 static int writeAudioOnly(v2swf_internal_t*i)
593 i->fpspos += i->fpsratio;
604 static int encodeoneframe(v2swf_internal_t*i)
606 videoreader_t*video = i->video;
611 if(i->video_eof && i->audio_eof) {
617 if(!i->audio_eof && i->video_eof) {
618 return writeAudioOnly(i);
621 if(!videoreader_getimage(i->video, i->vrbuffer))
624 msg("videoreader returned eof\n");
629 return writeAudioOnly(i);
633 msg("encoding image for frame %d\n", i->frames);
635 i->fpspos += i->fpsratio;
645 msg("version is %d\n", i->version);
647 if(i->version <= 4) {
650 int shapeid = i->id++;
651 int width2 = i->width * 4;
654 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
655 swf_SetU16(i->tag, i->id-3);
656 i->filesize += swf_WriteTag2(&i->out, i->tag);
657 swf_ResetTag(i->tag, ST_FREECHARACTER);
658 swf_SetU16(i->tag, i->id-4);
659 i->filesize += swf_WriteTag2(&i->out, i->tag);
662 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
663 swf_SetU16(i->tag, bmid);
664 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
665 i->filesize += swf_WriteTag2(&i->out, i->tag);
667 writeShowTags(i, shapeid, bmid, i->width, i->height);
669 } else if(i->version == 5) {
670 int width2 = i->width * 4;
671 int width8 = (i->width+7)/8;
672 int height8 = (i->height+7)/8;
674 /* the idea is here to only update those jpeg 8x8 blocks
675 which actually have changed. This means that we have to keep
676 the bitmap from the last frame for the comparison. */
679 if(!i->lastbitmap || !i->keyframe) {
684 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
685 i->lastbitmap = (U8*)malloc(width2*i->height);
687 memcpy(i->lastbitmap, i->buffer, width2*i->height);
689 i->keyframe = i->keyframe_interval;
693 width2 = i->width * 4;
694 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
695 swf_SetU16(i->tag, bmid);
696 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
697 i->filesize += swf_WriteTag2(&i->out, i->tag);
699 writeShowTags(i, shapeid, bmid, i->width, i->height);
702 /* The following looks so ugly because it's somewhat optimized.
703 What it does is walk through all the 8x8 blocks, find those
704 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
705 It also set's alpha to 255 in those who haven't changed, and
706 copies them to lastbitmap.
710 //int maxdiff = ((100 - i->quality)*256)/100;
711 int maxdiff = i->blockdiff*3;
712 for(y8=0;y8<height8;y8++)
713 for(x8=0;x8<width8;x8++) {
718 if(x8*8+xl > i->width)
719 xl = i->width - x8*8;
720 if(y8*8+yl > i->height)
721 yl = i->height - y8*8;
722 d1 = &i->buffer[width2*y8*8+x8*8*4];
724 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
726 yadd = width2 - (xl*4);
728 if(i->diffmode == DIFFMODE_MAX) {
729 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
731 } else if(i->diffmode == DIFFMODE_MEAN) {
732 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
734 } else if(i->diffmode == DIFFMODE_EXACT) {
735 if(blockdiff_exact(d1, d2, yadd, xl, yl))
737 } else if(i->diffmode == DIFFMODE_QMEAN) {
738 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
753 *(U32*)d2b = *(U32*)d1b;
757 d1b += yadd; d2b += yadd;
761 /* ok, done. Now a) data is zeroed out in regions which haven't changed
762 b) lastbitmap equals the bitmap we were called with
763 c) data's alpha value is set to 255 in regions which did change */
769 int shapeid = i->id++;
771 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
772 swf_SetU16(i->tag, bmid);
773 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
774 i->filesize += swf_WriteTag2(&i->out, i->tag);
776 writeShowTags(i, shapeid, bmid, i->width, i->height);
779 int quant = 1+(30-(30*i->quality)/100);
782 swf_GetPlaceObject(0, &obj);
784 obj.matrix.sx = obj.matrix.sy = i->scale;
787 if(i->stream.frame==0) {
793 obj.ratio = i->stream.frame;
796 swf_ResetTag(i->tag, ST_VIDEOFRAME);
797 swf_SetU16(i->tag, 99);
798 if(!(--i->keyframe)) {
799 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
800 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
801 i->keyframe = i->keyframe_interval;
803 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
804 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
806 i->filesize += swf_WriteTag2(&i->out, i->tag);
808 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
809 swf_SetPlaceObject(i->tag,&obj);
810 i->filesize += swf_WriteTag2(&i->out, i->tag);
816 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
821 msg("v2swf_init()\n");
822 memset(v2swf, 0, sizeof(v2swf_t));
823 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
824 memset(i, 0, sizeof(v2swf_internal_t));
827 ringbuffer_init(&i->r);
829 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
833 i->keyframe_interval = 8;
836 i->samplerate = 11025;
839 i->diffmode = DIFFMODE_QMEAN;
842 i->framerate = video->fps;
843 i->fpsratio = 1.00000000000;
856 memset(&i->out, 0, sizeof(struct writer_t));
857 memset(&i->out2, 0, sizeof(struct writer_t));
861 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
865 msg("v2swf_read(%d)\n", len);
866 i = (v2swf_internal_t*)v2swf->internal;
868 while(!i->finished && i->r.available < len) {
869 if(!encodeoneframe(i)) {
873 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
874 l = ringbuffer_read(&i->r, buffer, len);
878 void v2swf_close(v2swf_t*v2swf)
880 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
881 msg("close(): i->finished=%d\n", i->finished);
883 /* needed only if aborting: */
886 msg("freeing memory\n");
887 free(v2swf->internal);
888 memset(v2swf, 0, sizeof(v2swf_t));
889 msg("close() done\n");
892 static int mp3_bitrates[] =
893 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
895 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
899 msg("set parameters %s to %s\n", name, value);
901 if(!strcmp(name, "verbose")) {
903 msg("set parameters %s to %s\n", name, value);
907 if(!v2swf || !v2swf->internal) {
908 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
911 i = (v2swf_internal_t*)v2swf->internal;
913 if(!strcmp(name, "flash_version")) {
914 i->version = atoi(value);
915 } else if(!strcmp(name, "audiosync")) {
916 i->audio_fix = (int)(atof(value));
917 } else if(!strcmp(name, "scale")) {
918 i->scale = (int)(atof(value)*65536);
919 } else if(!strcmp(name, "scale65536")) {
920 i->scale = atoi(value);
921 } else if(!strcmp(name, "quality")) {
922 i->quality = atoi(value);
923 } else if(!strcmp(name, "motioncompensation")) {
924 i->domotion = atoi(value);
925 } else if(!strcmp(name, "prescale")) {
926 i->prescale = atoi(value);
927 } else if(!strcmp(name, "blockdiff")) {
928 i->blockdiff = atoi(value);
929 } else if(!strcmp(name, "fixheader")) {
930 i->fixheader = atoi(value);
931 } else if(!strcmp(name, "samplerate")) {
932 i->samplerate = atoi(value);
933 } else if(!strcmp(name, "framerate")) {
934 i->framerate = atof(value);
935 i->fpsratio = i->framerate / i->video->fps;
937 else if(!strcmp(name, "mp3_bitrate")) {
939 i->bitrate = o = atoi(value);
942 while(mp3_bitrates[t]) {
943 if(i->bitrate <= mp3_bitrates[t]) {
944 i->bitrate = mp3_bitrates[t];
949 msg("bitrate %d requested, setting to %d", o, i->bitrate);
951 else if(!strcmp(name, "blockdiff_mode")) {
952 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
953 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
954 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
955 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
957 printf("diffmode %s not recognized\n", value);
958 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
961 else if(!strcmp(name, "keyframe_interval")
962 || !strcmp(name, "keyframe")) {
963 int k = atoi(value);if(k<=0) k=1;
964 i->keyframe_interval = k;
967 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
971 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
975 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
976 msg("v2swf_backpatch %s\n", filename);
978 printf("call backpatch before close\n");fflush(stdout);
980 fi = fopen(filename, "rb+");
982 printf("can't open %s\n", filename);
985 fseek(fi, 4, SEEK_SET);
986 f = i->filesize ;fwrite(&f,1,1,fi);
987 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
988 f = i->filesize >> 16;fwrite(&f,1,1,fi);
989 f = i->filesize >> 24;fwrite(&f,1,1,fi);
991 /* no compression- we can backpatch the frames too */
992 fseek(fi, i->headersize-2, SEEK_SET);
993 f = i->frames ;fwrite(&f,1,1,fi);
994 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
1000 msg("v2swf_backpatch %s - fix header\n", filename);
1001 memset(&tmp, 0, sizeof(tmp));
1002 fi = open(filename, O_RDONLY|O_BINARY);
1004 if(swf_ReadSWF(fi, &tmp)>=0) {
1006 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
1008 swf_WriteSWC(fi, &tmp);
1010 msg("v2swf_backpatch %s - fix header: success\n", filename);
1017 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
1019 msg("v2swf_setvideoparameter()");
1020 videoreader_setparameter(v, name, value);