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;
98 static int verbose = 0;
99 static int filelog = 0;
101 static void msg(char*format, ...)
108 va_start(arglist, format);
109 vsprintf(buf, format, arglist);
112 while(l && buf[l-1]=='\n') {
118 FILE*fi = fopen("debug.log", "ab+");
119 fprintf(fi, "(v2swf) %s\n", buf);
124 printf("(v2swf) %s\n", buf);
128 extern int swf_mp3_in_samplerate;
129 extern int swf_mp3_out_samplerate;
130 extern int swf_mp3_channels;
131 extern int swf_mp3_bitrate;
134 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
142 swf_ResetTag(i->tag, ST_DEFINESHAPE);
143 swf_ShapeNew(&shape);
144 rgb.b = rgb.g = rgb.r = 0xff;
146 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
147 swf_GetMatrix(NULL,&m);
151 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
152 swf_SetU16(i->tag,id); // ID
157 swf_SetRect(i->tag,&r);
159 swf_SetShapeStyles(i->tag,shape);
160 swf_ShapeCountBits(shape,NULL,NULL);
161 swf_SetShapeBits(i->tag,shape);
163 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
165 swf_ShapeSetLine(i->tag,shape,width*20,0);
166 swf_ShapeSetLine(i->tag,shape,0,height*20);
167 swf_ShapeSetLine(i->tag,shape,-width*20,0);
168 swf_ShapeSetLine(i->tag,shape,0,-height*20);
169 swf_ShapeSetEnd(i->tag);
170 i->filesize += swf_WriteTag2(&i->out, i->tag);
171 swf_ShapeFree(shape);
174 /* returns 0 on partial read */
175 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
178 double ratio = (double) video->samplerate * speedup / swf_mp3_in_samplerate;
179 int rlen = (int)(len * ratio);
182 int r = /*resampled len */ rlen *
186 memset(tmp, 0, sizeof(tmp));
187 l = videoreader_getsamples(video, tmp, r);
191 msg("%d samples read", l);
193 /* convert to 1 channel */
194 for(t=0;t<rlen;t++) {
197 for(s=0;s<video->channels;s++)
198 a += tmp[t*video->channels+s];
199 tmp[t] = a/video->channels;
202 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
204 data[t] = tmp[(int)pos];
210 static void writeAudioForOneFrame(v2swf_internal_t* i)
213 double blockspersecond;
214 double framespersecond, framesperblock, samplesperframe, samplesperblock;
217 double speedup = i->audio_fix;
220 S16 block1[576*4 * 2];
222 msg("writeAudioForOneFrame()");
224 if(i->audio_eof || i->video->channels<=0 || i->video->samplerate<=0) {
226 return; /* no sound in video */
229 blocksize = (i->samplerate > 22050) ? 1152 : 576;
230 blockspersecond = ((double)i->samplerate)/blocksize;
232 /* notice: for framerates greater than about 35, audio starts getting choppy. */
233 framespersecond = i->framerate;
235 framesperblock = framespersecond / blockspersecond;
236 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
237 samplesperblock = samplesperframe * framesperblock;
239 msg("samplesperblock: %f", samplesperblock);
241 if(!i->soundstreamhead) {
242 swf_mp3_out_samplerate = i->samplerate;
243 /* The pre-processing of sound samples in getSamples(..) above
244 re-samples the sound to swf_mp3_in_samplerate. It is best to
245 simply make it the original samplerate: */
246 swf_mp3_in_samplerate = i->video->samplerate;
248 /* first run - initialize */
249 swf_mp3_channels = 1;//i->video->channels;
250 swf_mp3_bitrate = i->bitrate;
251 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
252 /* samplesperframe overrides the movie framerate: */
253 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
254 swf_SetSoundStreamHead(i->tag, samplesperframe);
255 msg("swf_SetSoundStreamHead() done");
256 i->filesize += swf_WriteTag2(&i->out, i->tag);
257 i->soundstreamhead = 1;
260 /* for framerates greater than 19.14, every now and then a frame
261 hasn't a soundstreamblock. Determine whether this is the case.
263 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
264 if(i->frames < i->soundframepos) {
265 msg("SOUND: block skipped\n");
266 i->samplepos += samplesperframe;
272 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
274 i->samplewritepos += blocksize;
275 i->soundframepos += framesperblock;
278 while(i->samplewritepos < i->samplepos);
280 msg("SOUND: number of blocks: %d", num);
282 /* write num frames, max 1 block */
283 for(pos=0;pos<num;pos++) {
284 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
285 i->audio_eof = 1; i->video->samplerate = i->video->channels = 0; //end of soundtrack
286 /* fall through, this probably was a partial read. (We did, after all,
287 come to this point, so i->audio_eof must have been false so far) */
290 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
291 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
293 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
296 i->filesize += swf_WriteTag2(&i->out, i->tag);
298 i->seek = blocksize - (i->samplewritepos - i->samplepos);
299 i->samplepos += samplesperframe;
302 static void writeShowFrame(v2swf_internal_t* i)
305 writeAudioForOneFrame(i);
307 swf_ResetTag(i->tag, ST_SHOWFRAME);
308 i->filesize += swf_WriteTag2(&i->out, i->tag);
313 while(i->fpspos >= 1.0);
317 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
319 writeShape(i, shapeid, bmid, width, height);
321 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
324 swf_GetMatrix(0, &m);
325 m.sx = m.sy = i->scale;
326 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
328 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
330 i->filesize += swf_WriteTag2(&i->out, i->tag);
335 static int wwrite(struct writer_t*w, void*data, int len)
337 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
338 ringbuffer_put(&i->r, data, len);
342 static void wfinish(struct writer_t*w)
344 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
347 static void writehead(v2swf_internal_t*i)
349 char header[]="FWS\6\0\0\0\4";
354 header[3] = i->version;
355 if(i->version >= 6) { //MX
358 i->out2.write = wwrite;
359 i->out2.finish = wfinish;
360 i->out2.internal = i;
365 writer_init_zlibdeflate(&i->out, &i->out2);
367 i->out.write = wwrite;
368 i->out.finish = wfinish;
378 i->width = (int)(i->video->width*(i->scale/65536.0));
379 i->height = (int)(i->video->height*(i->scale/65536.0));
381 i->width = i->video->width;
382 i->height = i->video->height;
388 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
389 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
391 memset(&swf, 0, sizeof(SWF));
392 swf.fileVersion=i->version;
394 swf.frameCount = 65535;
395 swf.movieSize.xmax=i->width*20;
396 swf.movieSize.ymax=i->height*20;
397 swf.compressed = 8; /* 8 = compression done by caller (us) */
398 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
400 /* write the first 8 bytes to out */
401 i->out2.write(&i->out2, header, 8);
403 i->filesize += swf_WriteHeader2(&i->out, &swf);
404 i->headersize = i->filesize;
406 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
407 swf_SetU8(i->tag, 0); //black
408 swf_SetU8(i->tag, 0);
409 swf_SetU8(i->tag, 0);
410 i->filesize += swf_WriteTag2(&i->out, i->tag);
413 static void finish(v2swf_internal_t*i)
415 msg("finish(): i->finished=%d\n", i->finished);
417 msg("write endtag\n", i->finished);
420 swf_ResetTag(i->tag, ST_SHOWFRAME);
421 i->filesize += swf_WriteTag2(&i->out, i->tag);
423 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
424 swf_SetU16(i->tag, 1); //depth
425 i->filesize += swf_WriteTag2(&i->out, i->tag);
427 swf_ResetTag(i->tag, ST_DOACTION);
428 swf_SetU16(i->tag, 0x0007);
429 i->filesize += swf_WriteTag2(&i->out, i->tag);
432 swf_ResetTag(i->tag, ST_END);
433 i->filesize += swf_WriteTag2(&i->out, i->tag);
435 i->out.finish(&i->out);
438 swf_VideoStreamClear(&i->stream);
441 free(i->buffer);i->buffer = 0;
444 free(i->vrbuffer);i->vrbuffer = 0;
447 free(i->lastbitmap);i->lastbitmap = 0;
450 /* FIXME: we shouldn't be doing this. the caller should */
451 msg("call videoreader_close(%08x)\n", i->video);
452 videoreader_close(i->video);
456 msg("finishing done\n");
458 static void cleanup(v2swf_internal_t*i)
461 for(t=i->lastid;t<i->id;t++) {
463 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
464 swf_SetU16(i->tag, t);
465 i->filesize += swf_WriteTag2(&i->out, i->tag);
467 swf_ResetTag(i->tag, ST_FREECHARACTER);
468 swf_SetU16(i->tag, t);
469 i->filesize += swf_WriteTag2(&i->out, i->tag);
474 #define DIFFMODE_MAX 1
475 #define DIFFMODE_MEAN 2
476 #define DIFFMODE_EXACT 3
477 #define DIFFMODE_QMEAN 4
479 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
484 int rd = d1[1] - d2[1];
485 int gd = d1[2] - d2[2];
486 int bd = d1[3] - d2[3];
495 d1 += yadd; d2 += yadd;
500 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
506 int rd = d1[1] - d2[1];
507 int gd = d1[2] - d2[2];
508 int bd = d1[3] - d2[3];
516 d1 += yadd; d2 += yadd;
518 if(mean/(xl*yl) > maxdiff)
523 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
529 int rd = d1[1] - d2[1];
530 int gd = d1[2] - d2[2];
531 int bd = d1[3] - d2[3];
541 d1 += yadd; d2 += yadd;
543 if(mean/(xl*yl) > maxdiff*maxdiff)
548 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
553 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
558 d1 += yadd; d2 += yadd;
563 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
564 U32 g = ((r << 3) ^ r)&0x80808080;
568 static void checkInit(v2swf_internal_t*i)
573 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
574 swf_SetU16(i->tag, 99);
575 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
576 i->filesize += swf_WriteTag2(&i->out, i->tag);
578 i->stream.do_motion = 1;
585 static void scaleimage(v2swf_internal_t*i)
589 int xm = (i->video->width*65536)/i->width;
590 int ym = (i->video->height*65536)/i->height;
591 msg("scaling from %dx%d to %dx%d\n",
592 i->video->width, i->video->height,
596 memset(i->buffer, 255, i->width*i->height*4);
597 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
598 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
599 int*dest = &((int*)i->buffer)[y*i->width];
600 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
601 dest[x] = src[xv>>16];
604 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
607 static int writeAudioOnly(v2swf_internal_t*i)
610 i->fpspos += i->fpsratio;
621 static int encodeoneframe(v2swf_internal_t*i)
623 videoreader_t*video = i->video;
628 if(i->video_eof && i->audio_eof) {
634 if(!i->audio_eof && i->video_eof) {
635 return writeAudioOnly(i);
638 if(!videoreader_getimage(i->video, i->vrbuffer))
641 msg("videoreader returned eof\n");
646 return writeAudioOnly(i);
650 msg("encoding image for frame %d\n", i->frames);
652 i->fpspos += i->fpsratio;
662 msg("version is %d\n", i->version);
664 if(i->version <= 4) {
667 int shapeid = i->id++;
668 int width2 = i->width * 4;
671 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
672 swf_SetU16(i->tag, i->id-3);
673 i->filesize += swf_WriteTag2(&i->out, i->tag);
674 swf_ResetTag(i->tag, ST_FREECHARACTER);
675 swf_SetU16(i->tag, i->id-4);
676 i->filesize += swf_WriteTag2(&i->out, i->tag);
679 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
680 swf_SetU16(i->tag, bmid);
681 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
682 i->filesize += swf_WriteTag2(&i->out, i->tag);
684 writeShowTags(i, shapeid, bmid, i->width, i->height);
686 } else if(i->version == 5) {
687 int width2 = i->width * 4;
688 int width8 = (i->width+7)/8;
689 int height8 = (i->height+7)/8;
691 /* the idea is here to only update those jpeg 8x8 blocks
692 which actually have changed. This means that we have to keep
693 the bitmap from the last frame for the comparison. */
696 if(!i->lastbitmap || !i->keyframe) {
701 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
702 i->lastbitmap = (U8*)malloc(width2*i->height);
704 memcpy(i->lastbitmap, i->buffer, width2*i->height);
706 i->keyframe = i->keyframe_interval;
710 width2 = i->width * 4;
711 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
712 swf_SetU16(i->tag, bmid);
713 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
714 i->filesize += swf_WriteTag2(&i->out, i->tag);
716 writeShowTags(i, shapeid, bmid, i->width, i->height);
719 /* The following looks so ugly because it's somewhat optimized.
720 What it does is walk through all the 8x8 blocks, find those
721 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
722 It also set's alpha to 255 in those who haven't changed, and
723 copies them to lastbitmap.
727 //int maxdiff = ((100 - i->quality)*256)/100;
728 int maxdiff = i->blockdiff*3;
729 for(y8=0;y8<height8;y8++)
730 for(x8=0;x8<width8;x8++) {
735 if(x8*8+xl > i->width)
736 xl = i->width - x8*8;
737 if(y8*8+yl > i->height)
738 yl = i->height - y8*8;
739 d1 = &i->buffer[width2*y8*8+x8*8*4];
741 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
743 yadd = width2 - (xl*4);
745 if(i->diffmode == DIFFMODE_MAX) {
746 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
748 } else if(i->diffmode == DIFFMODE_MEAN) {
749 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
751 } else if(i->diffmode == DIFFMODE_EXACT) {
752 if(blockdiff_exact(d1, d2, yadd, xl, yl))
754 } else if(i->diffmode == DIFFMODE_QMEAN) {
755 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
770 *(U32*)d2b = *(U32*)d1b;
774 d1b += yadd; d2b += yadd;
778 /* ok, done. Now a) data is zeroed out in regions which haven't changed
779 b) lastbitmap equals the bitmap we were called with
780 c) data's alpha value is set to 255 in regions which did change */
786 int shapeid = i->id++;
788 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
789 swf_SetU16(i->tag, bmid);
790 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
791 i->filesize += swf_WriteTag2(&i->out, i->tag);
793 writeShowTags(i, shapeid, bmid, i->width, i->height);
796 int quant = 1+(30-(30*i->quality)/100);
799 swf_GetPlaceObject(0, &obj);
801 obj.matrix.sx = obj.matrix.sy = i->scale;
804 if(i->stream.frame==0) {
810 obj.ratio = i->stream.frame;
813 swf_ResetTag(i->tag, ST_VIDEOFRAME);
814 swf_SetU16(i->tag, 99);
815 if(!(--i->keyframe)) {
816 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
817 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
818 i->keyframe = i->keyframe_interval;
820 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
821 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
823 i->filesize += swf_WriteTag2(&i->out, i->tag);
825 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
826 swf_SetPlaceObject(i->tag,&obj);
827 i->filesize += swf_WriteTag2(&i->out, i->tag);
833 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
838 msg("v2swf_init()\n");
839 memset(v2swf, 0, sizeof(v2swf_t));
840 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
841 memset(i, 0, sizeof(v2swf_internal_t));
844 ringbuffer_init(&i->r);
846 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
849 i->video_fps = ((int)(video->fps*256))/256.0;
851 i->keyframe_interval = 8;
855 i->samplerate = 11025;
858 i->diffmode = DIFFMODE_QMEAN;
861 i->framerate = i->video_fps;
862 i->fpsratio = 1.00000000000;
875 memset(&i->out, 0, sizeof(struct writer_t));
876 memset(&i->out2, 0, sizeof(struct writer_t));
880 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
884 msg("v2swf_read(%d)\n", len);
885 i = (v2swf_internal_t*)v2swf->internal;
887 while(!i->finished && i->r.available < len) {
888 if(!encodeoneframe(i)) {
892 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
893 l = ringbuffer_read(&i->r, buffer, len);
897 void v2swf_close(v2swf_t*v2swf)
899 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
900 msg("close(): i->finished=%d\n", i->finished);
902 /* needed only if aborting: */
905 msg("freeing memory\n");
906 free(v2swf->internal);
907 memset(v2swf, 0, sizeof(v2swf_t));
908 msg("close() done\n");
911 static int mp3_bitrates[] =
912 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
914 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
918 msg("set parameters %s to %s\n", name, value);
920 if(!strcmp(name, "verbose")) {
922 msg("set parameters %s to %s\n", name, value);
926 if(!v2swf || !v2swf->internal) {
927 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
930 i = (v2swf_internal_t*)v2swf->internal;
932 if(!strcmp(name, "flash_version")) {
933 i->version = atoi(value);
934 } else if(!strcmp(name, "audiosync")) {
935 i->audio_fix = (int)(atof(value));
936 } else if(!strcmp(name, "addcut")) {
937 i->add_cut = atoi(value);
938 } else if(!strcmp(name, "scale")) {
939 i->scale = (int)(atof(value)*65536);
940 } else if(!strcmp(name, "scale65536")) {
941 i->scale = atoi(value);
942 } else if(!strcmp(name, "quality")) {
943 i->quality = atoi(value);
944 } else if(!strcmp(name, "motioncompensation")) {
945 i->domotion = atoi(value);
946 } else if(!strcmp(name, "prescale")) {
947 i->prescale = atoi(value);
948 } else if(!strcmp(name, "blockdiff")) {
949 i->blockdiff = atoi(value);
950 } else if(!strcmp(name, "fixheader")) {
951 i->fixheader = atoi(value);
952 } else if(!strcmp(name, "samplerate")) {
953 i->samplerate = atoi(value);
954 } else if(!strcmp(name, "framerate")) {
955 i->framerate = atof(value);
956 i->fpsratio = i->framerate / i->video_fps;
958 else if(!strcmp(name, "mp3_bitrate")) {
960 i->bitrate = o = atoi(value);
963 while(mp3_bitrates[t]) {
964 if(i->bitrate <= mp3_bitrates[t]) {
965 i->bitrate = mp3_bitrates[t];
970 msg("bitrate %d requested, setting to %d", o, i->bitrate);
972 else if(!strcmp(name, "blockdiff_mode")) {
973 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
974 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
975 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
976 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
978 printf("diffmode %s not recognized\n", value);
979 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
982 else if(!strcmp(name, "keyframe_interval")
983 || !strcmp(name, "keyframe")) {
984 int k = atoi(value);if(k<=0) k=1;
985 i->keyframe_interval = k;
988 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
992 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
996 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
997 msg("v2swf_backpatch %s\n", filename);
999 printf("call backpatch before close\n");fflush(stdout);
1001 fi = fopen(filename, "rb+");
1003 printf("can't open %s\n", filename);
1006 fseek(fi, 4, SEEK_SET);
1007 f = i->filesize ;fwrite(&f,1,1,fi);
1008 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
1009 f = i->filesize >> 16;fwrite(&f,1,1,fi);
1010 f = i->filesize >> 24;fwrite(&f,1,1,fi);
1012 /* no compression- we can backpatch the frames too */
1013 fseek(fi, i->headersize-2, SEEK_SET);
1014 f = i->frames ;fwrite(&f,1,1,fi);
1015 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
1021 msg("v2swf_backpatch %s - fix header\n", filename);
1022 memset(&tmp, 0, sizeof(tmp));
1023 fi = open(filename, O_RDONLY|O_BINARY);
1025 if(swf_ReadSWF(fi, &tmp)>=0) {
1027 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
1029 swf_WriteSWC(fi, &tmp);
1031 msg("v2swf_backpatch %s - fix header: success\n", filename);
1038 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
1040 msg("v2swf_setvideoparameter()");
1041 videoreader_setparameter(v, name, value);