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));
188 l = videoreader_getsamples(video, tmp, r);
192 msg("%d samples read", l);
194 /* convert to 1 channel */
195 for(t=0;t<rlen;t++) {
198 for(s=0;s<video->channels;s++)
199 a += tmp[t*video->channels+s];
200 tmp[t] = a/video->channels;
203 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
205 data[t] = tmp[(int)pos];
211 static void writeAudioForOneFrame(v2swf_internal_t* i)
214 double blockspersecond;
215 double framespersecond, framesperblock, samplesperframe, samplesperblock;
218 double speedup = i->audio_fix;
221 S16 block1[576*4 * 2];
223 msg("writeAudioForOneFrame()");
225 if(i->audio_eof || i->video->channels<=0 || i->video->samplerate<=0) {
227 return; /* no sound in video */
230 blocksize = (i->samplerate > 22050) ? 1152 : 576;
231 blockspersecond = ((double)i->samplerate)/blocksize;
233 /* notice: for framerates greater than about 35, audio starts getting choppy. */
234 framespersecond = i->framerate;
236 framesperblock = framespersecond / blockspersecond;
237 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
238 samplesperblock = samplesperframe * framesperblock;
240 msg("samplesperblock: %f", samplesperblock);
242 if(!i->soundstreamhead) {
243 swf_mp3_out_samplerate = i->samplerate;
244 /* The pre-processing of sound samples in getSamples(..) above
245 re-samples the sound to swf_mp3_in_samplerate. It is best to
246 simply make it the original samplerate: */
247 swf_mp3_in_samplerate = i->video->samplerate;
249 /* first run - initialize */
250 swf_mp3_channels = 1;//i->video->channels;
251 swf_mp3_bitrate = i->bitrate;
252 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
253 /* samplesperframe overrides the movie framerate: */
254 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
255 swf_SetSoundStreamHead(i->tag, samplesperframe);
256 msg("swf_SetSoundStreamHead() done");
257 i->filesize += swf_WriteTag2(&i->out, i->tag);
258 i->soundstreamhead = 1;
261 /* for framerates greater than 19.14, every now and then a frame
262 hasn't a soundstreamblock. Determine whether this is the case.
264 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
265 if(i->frames < i->soundframepos) {
266 msg("SOUND: block skipped\n");
267 i->samplepos += samplesperframe;
273 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
275 i->samplewritepos += blocksize;
276 i->soundframepos += framesperblock;
279 while(i->samplewritepos < i->samplepos);
281 msg("SOUND: number of blocks: %d", num);
283 /* write num frames, max 1 block */
284 for(pos=0;pos<num;pos++) {
285 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
286 i->audio_eof = 1; i->video->samplerate = i->video->channels = 0; //end of soundtrack
287 /* fall through, this probably was a partial read. (We did, after all,
288 come to this point, so i->audio_eof must have been false so far) */
291 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
292 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
294 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
297 i->filesize += swf_WriteTag2(&i->out, i->tag);
299 i->seek = blocksize - (i->samplewritepos - i->samplepos);
300 i->samplepos += samplesperframe;
303 static void writeShowFrame(v2swf_internal_t* i)
306 writeAudioForOneFrame(i);
308 swf_ResetTag(i->tag, ST_SHOWFRAME);
309 i->filesize += swf_WriteTag2(&i->out, i->tag);
314 while(i->fpspos >= 1.0);
318 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
320 writeShape(i, shapeid, bmid, width, height);
322 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
325 swf_GetMatrix(0, &m);
326 m.sx = m.sy = i->scale;
327 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
329 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
331 i->filesize += swf_WriteTag2(&i->out, i->tag);
336 static int wwrite(struct writer_t*w, void*data, int len)
338 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
339 ringbuffer_put(&i->r, data, len);
343 static void wfinish(struct writer_t*w)
345 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
348 static void writehead(v2swf_internal_t*i)
350 char header[]="FWS\6\0\0\0\4";
355 header[3] = i->version;
356 if(i->version >= 6) { //MX
359 i->out2.write = wwrite;
360 i->out2.finish = wfinish;
361 i->out2.internal = i;
366 writer_init_zlibdeflate(&i->out, &i->out2);
368 i->out.write = wwrite;
369 i->out.finish = wfinish;
379 i->width = (int)(i->video->width*(i->scale/65536.0));
380 i->height = (int)(i->video->height*(i->scale/65536.0));
382 i->width = i->video->width;
383 i->height = i->video->height;
389 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
390 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
392 memset(&swf, 0, sizeof(SWF));
393 swf.fileVersion=i->version;
395 swf.frameCount = 65535;
396 swf.movieSize.xmax=i->width*20;
397 swf.movieSize.ymax=i->height*20;
398 swf.compressed = 8; /* 8 = compression done by caller (us) */
399 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
401 /* write the first 8 bytes to out */
402 i->out2.write(&i->out2, header, 8);
404 i->filesize += swf_WriteHeader2(&i->out, &swf);
405 i->headersize = i->filesize;
407 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
408 swf_SetU8(i->tag, 0); //black
409 swf_SetU8(i->tag, 0);
410 swf_SetU8(i->tag, 0);
411 i->filesize += swf_WriteTag2(&i->out, i->tag);
414 static void finish(v2swf_internal_t*i)
416 msg("finish(): i->finished=%d\n", i->finished);
418 msg("write endtag\n", i->finished);
421 swf_ResetTag(i->tag, ST_SHOWFRAME);
422 i->filesize += swf_WriteTag2(&i->out, i->tag);
424 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
425 swf_SetU16(i->tag, 1); //depth
426 i->filesize += swf_WriteTag2(&i->out, i->tag);
428 swf_ResetTag(i->tag, ST_DOACTION);
429 swf_SetU16(i->tag, 0x0007);
430 i->filesize += swf_WriteTag2(&i->out, i->tag);
433 swf_ResetTag(i->tag, ST_END);
434 i->filesize += swf_WriteTag2(&i->out, i->tag);
436 i->out.finish(&i->out);
439 swf_VideoStreamClear(&i->stream);
442 free(i->buffer);i->buffer = 0;
445 free(i->vrbuffer);i->vrbuffer = 0;
448 free(i->lastbitmap);i->lastbitmap = 0;
451 /* FIXME: we shouldn't be doing this. the caller should */
452 msg("call videoreader_close(%08x)\n", i->video);
453 videoreader_close(i->video);
457 msg("finishing done\n");
459 static void cleanup(v2swf_internal_t*i)
462 for(t=i->lastid;t<i->id;t++) {
464 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
465 swf_SetU16(i->tag, t);
466 i->filesize += swf_WriteTag2(&i->out, i->tag);
468 swf_ResetTag(i->tag, ST_FREECHARACTER);
469 swf_SetU16(i->tag, t);
470 i->filesize += swf_WriteTag2(&i->out, i->tag);
475 #define DIFFMODE_MAX 1
476 #define DIFFMODE_MEAN 2
477 #define DIFFMODE_EXACT 3
478 #define DIFFMODE_QMEAN 4
480 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
485 int rd = d1[1] - d2[1];
486 int gd = d1[2] - d2[2];
487 int bd = d1[3] - d2[3];
496 d1 += yadd; d2 += yadd;
501 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
507 int rd = d1[1] - d2[1];
508 int gd = d1[2] - d2[2];
509 int bd = d1[3] - d2[3];
517 d1 += yadd; d2 += yadd;
519 if(mean/(xl*yl) > maxdiff)
524 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
530 int rd = d1[1] - d2[1];
531 int gd = d1[2] - d2[2];
532 int bd = d1[3] - d2[3];
542 d1 += yadd; d2 += yadd;
544 if(mean/(xl*yl) > maxdiff*maxdiff)
549 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
554 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
559 d1 += yadd; d2 += yadd;
564 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
565 U32 g = ((r << 3) ^ r)&0x80808080;
569 static void checkInit(v2swf_internal_t*i)
574 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
575 swf_SetU16(i->tag, 99);
576 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
577 i->filesize += swf_WriteTag2(&i->out, i->tag);
579 i->stream.do_motion = 1;
586 static void scaleimage(v2swf_internal_t*i)
590 int xm = (i->video->width*65536)/i->width;
591 int ym = (i->video->height*65536)/i->height;
592 msg("scaling from %dx%d to %dx%d\n",
593 i->video->width, i->video->height,
597 memset(i->buffer, 255, i->width*i->height*4);
598 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
599 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
600 int*dest = &((int*)i->buffer)[y*i->width];
601 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
602 dest[x] = src[xv>>16];
605 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
608 static int writeAudioOnly(v2swf_internal_t*i)
611 i->fpspos += i->fpsratio;
622 static int encodeoneframe(v2swf_internal_t*i)
624 videoreader_t*video = i->video;
629 if(i->video_eof && i->audio_eof) {
635 if(!i->audio_eof && i->video_eof) {
636 return writeAudioOnly(i);
639 if(!videoreader_getimage(i->video, i->vrbuffer))
642 msg("videoreader returned eof\n");
647 return writeAudioOnly(i);
651 msg("encoding image for frame %d\n", i->frames);
653 i->fpspos += i->fpsratio;
663 msg("version is %d\n", i->version);
665 if(i->version <= 4) {
668 int shapeid = i->id++;
669 int width2 = i->width * 4;
672 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
673 swf_SetU16(i->tag, i->id-3);
674 i->filesize += swf_WriteTag2(&i->out, i->tag);
675 swf_ResetTag(i->tag, ST_FREECHARACTER);
676 swf_SetU16(i->tag, i->id-4);
677 i->filesize += swf_WriteTag2(&i->out, i->tag);
680 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
681 swf_SetU16(i->tag, bmid);
682 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
683 i->filesize += swf_WriteTag2(&i->out, i->tag);
685 writeShowTags(i, shapeid, bmid, i->width, i->height);
687 } else if(i->version == 5) {
688 int width2 = i->width * 4;
689 int width8 = (i->width+7)/8;
690 int height8 = (i->height+7)/8;
692 /* the idea is here to only update those jpeg 8x8 blocks
693 which actually have changed. This means that we have to keep
694 the bitmap from the last frame for the comparison. */
697 if(!i->lastbitmap || !i->keyframe) {
702 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
703 i->lastbitmap = (U8*)malloc(width2*i->height);
705 memcpy(i->lastbitmap, i->buffer, width2*i->height);
707 i->keyframe = i->keyframe_interval;
711 width2 = i->width * 4;
712 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
713 swf_SetU16(i->tag, bmid);
714 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
715 i->filesize += swf_WriteTag2(&i->out, i->tag);
717 writeShowTags(i, shapeid, bmid, i->width, i->height);
720 /* The following looks so ugly because it's somewhat optimized.
721 What it does is walk through all the 8x8 blocks, find those
722 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
723 It also set's alpha to 255 in those who haven't changed, and
724 copies them to lastbitmap.
728 //int maxdiff = ((100 - i->quality)*256)/100;
729 int maxdiff = i->blockdiff*3;
730 for(y8=0;y8<height8;y8++)
731 for(x8=0;x8<width8;x8++) {
736 if(x8*8+xl > i->width)
737 xl = i->width - x8*8;
738 if(y8*8+yl > i->height)
739 yl = i->height - y8*8;
740 d1 = &i->buffer[width2*y8*8+x8*8*4];
742 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
744 yadd = width2 - (xl*4);
746 if(i->diffmode == DIFFMODE_MAX) {
747 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
749 } else if(i->diffmode == DIFFMODE_MEAN) {
750 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
752 } else if(i->diffmode == DIFFMODE_EXACT) {
753 if(blockdiff_exact(d1, d2, yadd, xl, yl))
755 } else if(i->diffmode == DIFFMODE_QMEAN) {
756 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
771 *(U32*)d2b = *(U32*)d1b;
775 d1b += yadd; d2b += yadd;
779 /* ok, done. Now a) data is zeroed out in regions which haven't changed
780 b) lastbitmap equals the bitmap we were called with
781 c) data's alpha value is set to 255 in regions which did change */
787 int shapeid = i->id++;
789 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
790 swf_SetU16(i->tag, bmid);
791 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
792 i->filesize += swf_WriteTag2(&i->out, i->tag);
794 writeShowTags(i, shapeid, bmid, i->width, i->height);
797 int quant = 1+(30-(30*i->quality)/100);
800 swf_GetPlaceObject(0, &obj);
802 obj.matrix.sx = obj.matrix.sy = i->scale;
805 if(i->stream.frame==0) {
811 obj.ratio = i->stream.frame;
814 swf_ResetTag(i->tag, ST_VIDEOFRAME);
815 swf_SetU16(i->tag, 99);
816 if(!(--i->keyframe)) {
817 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
818 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
819 i->keyframe = i->keyframe_interval;
821 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
822 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
824 i->filesize += swf_WriteTag2(&i->out, i->tag);
826 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
827 swf_SetPlaceObject(i->tag,&obj);
828 i->filesize += swf_WriteTag2(&i->out, i->tag);
834 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
839 msg("v2swf_init()\n");
840 memset(v2swf, 0, sizeof(v2swf_t));
841 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
842 memset(i, 0, sizeof(v2swf_internal_t));
845 ringbuffer_init(&i->r);
847 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
850 i->video_fps = ((int)(video->fps*256))/256.0;
852 i->keyframe_interval = 8;
856 i->samplerate = 11025;
859 i->diffmode = DIFFMODE_QMEAN;
862 i->framerate = i->video_fps;
863 i->fpsratio = 1.00000000000;
876 memset(&i->out, 0, sizeof(struct writer_t));
877 memset(&i->out2, 0, sizeof(struct writer_t));
881 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
885 msg("v2swf_read(%d)\n", len);
886 i = (v2swf_internal_t*)v2swf->internal;
888 while(!i->finished && i->r.available < len) {
889 if(!encodeoneframe(i)) {
893 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
894 l = ringbuffer_read(&i->r, buffer, len);
898 void v2swf_close(v2swf_t*v2swf)
900 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
901 msg("close(): i->finished=%d\n", i->finished);
903 /* needed only if aborting: */
906 msg("freeing memory\n");
907 free(v2swf->internal);
908 memset(v2swf, 0, sizeof(v2swf_t));
909 msg("close() done\n");
912 static int mp3_bitrates[] =
913 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
915 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
919 msg("set parameters %s to %s\n", name, value);
921 if(!strcmp(name, "verbose")) {
923 msg("set parameters %s to %s\n", name, value);
927 if(!v2swf || !v2swf->internal) {
928 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
931 i = (v2swf_internal_t*)v2swf->internal;
933 if(!strcmp(name, "flash_version")) {
934 i->version = atoi(value);
935 } else if(!strcmp(name, "audiosync")) {
936 i->audio_fix = (int)(atof(value));
937 } else if(!strcmp(name, "addcut")) {
938 i->add_cut = atoi(value);
939 } else if(!strcmp(name, "scale")) {
940 i->scale = (int)(atof(value)*65536);
941 } else if(!strcmp(name, "scale65536")) {
942 i->scale = atoi(value);
943 } else if(!strcmp(name, "quality")) {
944 i->quality = atoi(value);
945 } else if(!strcmp(name, "motioncompensation")) {
946 i->domotion = atoi(value);
947 } else if(!strcmp(name, "prescale")) {
948 i->prescale = atoi(value);
949 } else if(!strcmp(name, "blockdiff")) {
950 i->blockdiff = atoi(value);
951 } else if(!strcmp(name, "fixheader")) {
952 i->fixheader = atoi(value);
953 } else if(!strcmp(name, "samplerate")) {
954 i->samplerate = atoi(value);
955 } else if(!strcmp(name, "framerate")) {
956 i->framerate = atof(value);
957 i->fpsratio = i->framerate / i->video_fps;
959 else if(!strcmp(name, "mp3_bitrate")) {
961 i->bitrate = o = atoi(value);
964 while(mp3_bitrates[t]) {
965 if(i->bitrate <= mp3_bitrates[t]) {
966 i->bitrate = mp3_bitrates[t];
971 msg("bitrate %d requested, setting to %d", o, i->bitrate);
973 else if(!strcmp(name, "blockdiff_mode")) {
974 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
975 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
976 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
977 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
979 printf("diffmode %s not recognized\n", value);
980 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
983 else if(!strcmp(name, "keyframe_interval")
984 || !strcmp(name, "keyframe")) {
985 int k = atoi(value);if(k<=0) k=1;
986 i->keyframe_interval = k;
989 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
993 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
997 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
998 msg("v2swf_backpatch %s\n", filename);
1000 printf("call backpatch before close\n");fflush(stdout);
1002 fi = fopen(filename, "rb+");
1004 printf("can't open %s\n", filename);
1007 fseek(fi, 4, SEEK_SET);
1008 f = i->filesize ;fwrite(&f,1,1,fi);
1009 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
1010 f = i->filesize >> 16;fwrite(&f,1,1,fi);
1011 f = i->filesize >> 24;fwrite(&f,1,1,fi);
1013 /* no compression- we can backpatch the frames too */
1014 fseek(fi, i->headersize-2, SEEK_SET);
1015 f = i->frames ;fwrite(&f,1,1,fi);
1016 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
1022 msg("v2swf_backpatch %s - fix header\n", filename);
1023 memset(&tmp, 0, sizeof(tmp));
1024 fi = open(filename, O_RDONLY|O_BINARY);
1026 if(swf_ReadSWF(fi, &tmp)>=0) {
1028 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
1030 swf_WriteSWC(fi, &tmp);
1032 msg("v2swf_backpatch %s - fix header: success\n", filename);
1039 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
1041 msg("v2swf_setvideoparameter()");
1042 videoreader_setparameter(v, name, value);