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
46 unsigned char* vrbuffer;
47 unsigned char* buffer;
48 unsigned char* lastbitmap;
55 int keyframe_interval;
92 static int verbose = 0;
93 static int filelog = 0;
95 static void msg(char*format, ...)
102 va_start(arglist, format);
103 vsprintf(buf, format, arglist);
106 while(l && buf[l-1]=='\n') {
112 FILE*fi = fopen("debug.log", "ab+");
113 fprintf(fi, "(v2swf) %s\n", buf);
118 printf("(v2swf) %s\n", buf);
122 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
130 swf_ResetTag(i->tag, ST_DEFINESHAPE);
131 swf_ShapeNew(&shape);
132 rgb.b = rgb.g = rgb.r = 0xff;
134 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
135 swf_GetMatrix(NULL,&m);
139 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
140 swf_SetU16(i->tag,id); // ID
145 swf_SetRect(i->tag,&r);
147 swf_SetShapeStyles(i->tag,shape);
148 swf_ShapeCountBits(shape,NULL,NULL);
149 swf_SetShapeBits(i->tag,shape);
151 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
153 swf_ShapeSetLine(i->tag,shape,width*20,0);
154 swf_ShapeSetLine(i->tag,shape,0,height*20);
155 swf_ShapeSetLine(i->tag,shape,-width*20,0);
156 swf_ShapeSetLine(i->tag,shape,0,-height*20);
157 swf_ShapeSetEnd(i->tag);
158 i->filesize += swf_WriteTag2(&i->out, i->tag);
159 swf_ShapeFree(shape);
162 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
165 double ratio = (double) video->rate * speedup / swf_mp3_in_samplerate;
166 int rlen = (int)(len * ratio);
169 int r = /*resampled len */ rlen *
172 if(videoreader_getsamples(video, tmp, r) < r)
175 /* convert to 1 channel */
176 for(t=0;t<rlen;t++) {
179 for(s=0;s<video->channels;s++)
180 a += tmp[t*video->channels+s];
181 tmp[t] = a/video->channels;
184 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
186 data[t] = tmp[(int)pos];
192 extern int swf_mp3_channels;
193 extern int swf_mp3_bitrate;
194 extern int swf_mp3_out_samplerate;
195 extern int swf_mp3_in_samplerate;
197 static void writeAudioForOneFrame(v2swf_internal_t* i)
200 double blockspersecond;
201 double framespersecond, framesperblock, samplesperframe, samplesperblock;
204 double speedup = i->audio_fix;
207 S16 block1[576*4 * 2];
209 msg("writeAudioForOneFrame()");
211 if(i->video->channels<=0 || i->video->rate<=0)
212 return; /* no sound in video */
214 blocksize = (i->samplerate > 22050) ? 1152 : 576;
215 blockspersecond = ((double)i->samplerate)/blocksize;
217 /* notice: for framerates greater than about 35, audio starts getting choppy. */
218 framespersecond = i->framerate;
220 framesperblock = framespersecond / blockspersecond;
221 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
222 samplesperblock = samplesperframe * framesperblock;
224 msg("samplesperblock: %f", samplesperblock);
226 if(!i->soundstreamhead) {
227 swf_mp3_out_samplerate = i->samplerate;
228 /* The pre-processing of sound samples in getSamples(..) above
229 re-samples the sound to swf_mp3_in_samplerate. It is best to
230 simply make it the original samplerate: */
231 swf_mp3_in_samplerate = i->video->rate;
233 /* first run - initialize */
234 swf_mp3_channels = 1;//i->video->channels;
235 swf_mp3_bitrate = i->bitrate;
236 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
237 /* samplesperframe overrides the movie framerate: */
238 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
239 swf_SetSoundStreamHead(i->tag, samplesperframe);
240 msg("swf_SetSoundStreamHead() done");
241 i->filesize += swf_WriteTag2(&i->out, i->tag);
242 i->soundstreamhead = 1;
245 /* for framerates greater than 19.14, every now and then a frame
246 hasn't a soundstreamblock. Determine whether this is the case.
248 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
249 if(i->frames < i->soundframepos) {
250 msg("SOUND: block skipped\n");
251 i->samplepos += samplesperframe;
257 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
259 i->samplewritepos += blocksize;
260 i->soundframepos += framesperblock;
263 while(i->samplewritepos < i->samplepos);
265 msg("SOUND: number of blocks: %d", num);
267 /* write num frames, max 1 block */
268 for(pos=0;pos<num;pos++) {
269 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
270 i->video->rate = i->video->channels = 0; //end of soundtrack
274 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
275 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
277 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
280 i->filesize += swf_WriteTag2(&i->out, i->tag);
282 i->seek = blocksize - (i->samplewritepos - i->samplepos);
283 i->samplepos += samplesperframe;
286 static void writeShowFrame(v2swf_internal_t* i)
289 writeAudioForOneFrame(i);
291 swf_ResetTag(i->tag, ST_SHOWFRAME);
292 i->filesize += swf_WriteTag2(&i->out, i->tag);
297 while(i->fpspos >= 1.0);
301 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
303 writeShape(i, shapeid, bmid, width, height);
305 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
308 swf_GetMatrix(0, &m);
309 m.sx = m.sy = i->scale;
310 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
312 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
314 i->filesize += swf_WriteTag2(&i->out, i->tag);
319 static int wwrite(struct writer_t*w, void*data, int len)
321 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
322 ringbuffer_put(&i->r, data, len);
326 static void wfinish(struct writer_t*w)
328 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
331 static void writehead(v2swf_internal_t*i)
333 char header[]="FWS\6\0\0\0\4";
338 header[3] = i->version;
339 if(i->version >= 6) { //MX
342 i->out2.write = wwrite;
343 i->out2.finish = wfinish;
344 i->out2.internal = i;
349 writer_init_zlibdeflate(&i->out, &i->out2);
351 i->out.write = wwrite;
352 i->out.finish = wfinish;
362 i->width = (int)(i->video->width*(i->scale/65536.0));
363 i->height = (int)(i->video->height*(i->scale/65536.0));
365 i->width = i->video->width;
366 i->height = i->video->height;
372 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
373 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
375 memset(&swf, 0, sizeof(SWF));
376 swf.fileVersion=i->version;
378 swf.frameCount = 65535;
379 swf.movieSize.xmax=i->width*20;
380 swf.movieSize.ymax=i->height*20;
381 swf.compressed = 8; /* 8 = compression done by caller (us) */
382 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
384 /* write the first 8 bytes to out */
385 i->out2.write(&i->out2, header, 8);
387 i->filesize += swf_WriteHeader2(&i->out, &swf);
388 i->headersize = i->filesize;
390 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
391 swf_SetU8(i->tag, 0); //black
392 swf_SetU8(i->tag, 0);
393 swf_SetU8(i->tag, 0);
394 i->filesize += swf_WriteTag2(&i->out, i->tag);
397 static void finish(v2swf_internal_t*i)
399 msg("finish(): i->finished=%d\n", i->finished);
401 msg("write endtag\n", i->finished);
403 swf_ResetTag(i->tag, ST_END);
404 i->filesize += swf_WriteTag2(&i->out, i->tag);
405 i->out.finish(&i->out);
408 swf_VideoStreamClear(&i->stream);
411 free(i->buffer);i->buffer = 0;
414 free(i->vrbuffer);i->vrbuffer = 0;
417 free(i->lastbitmap);i->lastbitmap = 0;
420 /* FIXME: we shouldn't be doing this. the caller should */
421 msg("call videoreader_close(%08x)\n", i->video);
422 videoreader_close(i->video);
426 msg("finishing done\n");
428 static void cleanup(v2swf_internal_t*i)
431 for(t=i->lastid;t<i->id;t++) {
433 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
434 swf_SetU16(i->tag, t);
435 i->filesize += swf_WriteTag2(&i->out, i->tag);
437 swf_ResetTag(i->tag, ST_FREECHARACTER);
438 swf_SetU16(i->tag, t);
439 i->filesize += swf_WriteTag2(&i->out, i->tag);
444 #define DIFFMODE_MAX 1
445 #define DIFFMODE_MEAN 2
446 #define DIFFMODE_EXACT 3
447 #define DIFFMODE_QMEAN 4
449 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
454 int rd = d1[1] - d2[1];
455 int gd = d1[2] - d2[2];
456 int bd = d1[3] - d2[3];
465 d1 += yadd; d2 += yadd;
470 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
476 int rd = d1[1] - d2[1];
477 int gd = d1[2] - d2[2];
478 int bd = d1[3] - d2[3];
486 d1 += yadd; d2 += yadd;
488 if(mean/(xl*yl) > maxdiff)
493 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
499 int rd = d1[1] - d2[1];
500 int gd = d1[2] - d2[2];
501 int bd = d1[3] - d2[3];
511 d1 += yadd; d2 += yadd;
513 if(mean/(xl*yl) > maxdiff*maxdiff)
518 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
523 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
528 d1 += yadd; d2 += yadd;
533 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
534 U32 g = ((r << 3) ^ r)&0x80808080;
538 static void checkInit(v2swf_internal_t*i)
543 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
544 swf_SetU16(i->tag, 99);
545 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
546 i->filesize += swf_WriteTag2(&i->out, i->tag);
548 i->stream.do_motion = 1;
555 static void scaleimage(v2swf_internal_t*i)
559 int xm = (i->video->width*65536)/i->width;
560 int ym = (i->video->height*65536)/i->height;
561 memset(i->buffer, 255, i->width*i->height*4);
562 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
563 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
564 int*dest = &((int*)i->buffer)[y*i->width];
565 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
566 dest[x] = src[xv>>16];
569 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
572 static int encodeoneframe(v2swf_internal_t*i)
574 videoreader_t*video = i->video;
579 if(videoreader_eof(i->video) || !videoreader_getimage(i->video, i->vrbuffer))
581 msg("videoreader returned eof\n");
586 i->fpspos += i->fpsratio;
593 msg("encoding image for frame %d\n", i->frames);
602 msg("version is %d\n", i->version);
604 if(i->version <= 4) {
607 int shapeid = i->id++;
608 int width2 = i->width * 4;
611 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
612 swf_SetU16(i->tag, i->id-3);
613 i->filesize += swf_WriteTag2(&i->out, i->tag);
614 swf_ResetTag(i->tag, ST_FREECHARACTER);
615 swf_SetU16(i->tag, i->id-4);
616 i->filesize += swf_WriteTag2(&i->out, i->tag);
619 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
620 swf_SetU16(i->tag, bmid);
621 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
622 i->filesize += swf_WriteTag2(&i->out, i->tag);
624 writeShowTags(i, shapeid, bmid, i->width, i->height);
626 } else if(i->version == 5) {
627 int width2 = i->width * 4;
628 int width8 = (i->width+7)/8;
629 int height8 = (i->height+7)/8;
631 /* the idea is here to only update those jpeg 8x8 blocks
632 which actually have changed. This means that we have to keep
633 the bitmap from the last frame for the comparison. */
636 if(!i->lastbitmap || !i->keyframe) {
641 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
642 i->lastbitmap = (U8*)malloc(width2*i->height);
644 memcpy(i->lastbitmap, i->buffer, width2*i->height);
646 i->keyframe = i->keyframe_interval;
650 width2 = i->width * 4;
651 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
652 swf_SetU16(i->tag, bmid);
653 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
654 i->filesize += swf_WriteTag2(&i->out, i->tag);
656 writeShowTags(i, shapeid, bmid, i->width, i->height);
659 /* The following looks so ugly because it's somewhat optimized.
660 What it does is walk through all the 8x8 blocks, find those
661 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
662 It also set's alpha to 255 in those who haven't changed, and
663 copies them to lastbitmap.
667 //int maxdiff = ((100 - i->quality)*256)/100;
668 int maxdiff = i->blockdiff*3;
669 for(y8=0;y8<height8;y8++)
670 for(x8=0;x8<width8;x8++) {
675 if(x8*8+xl > i->width)
676 xl = i->width - x8*8;
677 if(y8*8+yl > i->height)
678 yl = i->height - y8*8;
679 d1 = &i->buffer[width2*y8*8+x8*8*4];
681 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
683 yadd = width2 - (xl*4);
685 if(i->diffmode == DIFFMODE_MAX) {
686 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
688 } else if(i->diffmode == DIFFMODE_MEAN) {
689 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
691 } else if(i->diffmode == DIFFMODE_EXACT) {
692 if(blockdiff_exact(d1, d2, yadd, xl, yl))
694 } else if(i->diffmode == DIFFMODE_QMEAN) {
695 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
710 *(U32*)d2b = *(U32*)d1b;
714 d1b += yadd; d2b += yadd;
718 /* ok, done. Now a) data is zeroed out in regions which haven't changed
719 b) lastbitmap equals the bitmap we were called with
720 c) data's alpha value is set to 255 in regions which did change */
726 int shapeid = i->id++;
728 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
729 swf_SetU16(i->tag, bmid);
730 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
731 i->filesize += swf_WriteTag2(&i->out, i->tag);
733 writeShowTags(i, shapeid, bmid, i->width, i->height);
736 int quant = 1+(30-(30*i->quality)/100);
739 swf_GetPlaceObject(0, &obj);
741 obj.matrix.sx = obj.matrix.sy = i->scale;
744 if(i->stream.frame==0) {
750 obj.ratio = i->stream.frame;
753 swf_ResetTag(i->tag, ST_VIDEOFRAME);
754 swf_SetU16(i->tag, 99);
755 if(!(--i->keyframe)) {
756 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
757 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
758 i->keyframe = i->keyframe_interval;
760 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
761 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
763 i->filesize += swf_WriteTag2(&i->out, i->tag);
765 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
766 swf_SetPlaceObject(i->tag,&obj);
767 i->filesize += swf_WriteTag2(&i->out, i->tag);
773 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
778 msg("v2swf_init()\n");
779 memset(v2swf, 0, sizeof(v2swf_t));
780 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
781 memset(i, 0, sizeof(v2swf_internal_t));
784 ringbuffer_init(&i->r);
786 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
790 i->keyframe_interval = 8;
793 i->samplerate = 11025;
796 i->diffmode = DIFFMODE_QMEAN;
799 i->framerate = video->fps;
800 i->fpsratio = 1.00000000;
813 memset(&i->out, 0, sizeof(struct writer_t));
814 memset(&i->out2, 0, sizeof(struct writer_t));
818 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
822 msg("v2swf_read(%d)\n", len);
823 i = (v2swf_internal_t*)v2swf->internal;
825 while(!i->finished && i->r.available < len) {
826 if(!encodeoneframe(i)) {
830 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
831 l = ringbuffer_read(&i->r, buffer, len);
835 void v2swf_close(v2swf_t*v2swf)
837 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
838 msg("close(): i->finished=%d\n", i->finished);
840 /* needed only if aborting: */
843 msg("freeing memory\n");
844 free(v2swf->internal);
845 memset(v2swf, 0, sizeof(v2swf_t));
846 msg("close() done\n");
849 static int mp3_bitrates[] =
850 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
852 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
856 msg("set parameters %s to %s\n", name, value);
858 if(!strcmp(name, "verbose")) {
860 msg("set parameters %s to %s\n", name, value);
864 if(!v2swf || !v2swf->internal) {
865 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
868 i = (v2swf_internal_t*)v2swf->internal;
870 if(!strcmp(name, "flash_version")) {
871 i->version = atoi(value);
872 } else if(!strcmp(name, "audiosync")) {
873 i->audio_fix = (int)(atof(value));
874 } else if(!strcmp(name, "scale")) {
875 i->scale = (int)(atof(value)*65536);
876 } else if(!strcmp(name, "scale65536")) {
877 i->scale = atoi(value);
878 } else if(!strcmp(name, "quality")) {
879 i->quality = atoi(value);
880 } else if(!strcmp(name, "motioncompensation")) {
881 i->domotion = atoi(value);
882 } else if(!strcmp(name, "prescale")) {
883 i->prescale = atoi(value);
884 } else if(!strcmp(name, "blockdiff")) {
885 i->blockdiff = atoi(value);
886 } else if(!strcmp(name, "fixheader")) {
887 i->fixheader = atoi(value);
888 } else if(!strcmp(name, "samplerate")) {
889 i->samplerate = atoi(value);
890 } else if(!strcmp(name, "framerate")) {
891 i->framerate = atof(value);
892 i->fpsratio = i->framerate / i->video->fps;
894 else if(!strcmp(name, "mp3_bitrate")) {
896 i->bitrate = o = atoi(value);
899 while(mp3_bitrates[t]) {
900 if(i->bitrate <= mp3_bitrates[t]) {
901 i->bitrate = mp3_bitrates[t];
906 msg("bitrate %d requested, setting to %d", o, i->bitrate);
908 else if(!strcmp(name, "blockdiff_mode")) {
909 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
910 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
911 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
912 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
914 printf("diffmode %s not recognized\n", value);
915 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
918 else if(!strcmp(name, "keyframe_interval")
919 || !strcmp(name, "keyframe")) {
920 int k = atoi(value);if(k<=0) k=1;
921 i->keyframe_interval = k;
924 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
928 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
932 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
933 msg("v2swf_backpatch %s\n", filename);
935 printf("call backpatch before close\n");fflush(stdout);
937 fi = fopen(filename, "rb+");
939 printf("can't open %s\n", filename);
942 fseek(fi, 4, SEEK_SET);
943 f = i->filesize ;fwrite(&f,1,1,fi);
944 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
945 f = i->filesize >> 16;fwrite(&f,1,1,fi);
946 f = i->filesize >> 24;fwrite(&f,1,1,fi);
948 /* no compression- we can backpatch the frames too */
949 fseek(fi, i->headersize-2, SEEK_SET);
950 f = i->frames ;fwrite(&f,1,1,fi);
951 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
957 msg("v2swf_backpatch %s - fix header\n", filename);
958 memset(&tmp, 0, sizeof(tmp));
959 fi = open(filename, O_RDONLY|O_BINARY);
961 if(swf_ReadSWF(fi, &tmp)>=0) {
963 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
965 swf_WriteSWC(fi, &tmp);
967 msg("v2swf_backpatch %s - fix header: success\n", filename);
974 float v2swf_getprogress(v2swf_t*v2swf)
978 msg("v2swf_getprogress()");
979 if(!v2swf || !v2swf->internal) {
982 i = (v2swf_internal_t*)v2swf->internal;
984 p = (float*)videoreader_getinfo(i->video, "position");
989 float f = i->frames/1500.0; /*fake*/
997 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
999 msg("v2swf_setvideoparameter()");
1000 videoreader_setparameter(v, name, value);