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 extern int swf_mp3_in_samplerate;
123 extern int swf_mp3_out_samplerate;
124 extern int swf_mp3_channels;
125 extern int swf_mp3_bitrate;
128 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
136 swf_ResetTag(i->tag, ST_DEFINESHAPE);
137 swf_ShapeNew(&shape);
138 rgb.b = rgb.g = rgb.r = 0xff;
140 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
141 swf_GetMatrix(NULL,&m);
145 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
146 swf_SetU16(i->tag,id); // ID
151 swf_SetRect(i->tag,&r);
153 swf_SetShapeStyles(i->tag,shape);
154 swf_ShapeCountBits(shape,NULL,NULL);
155 swf_SetShapeBits(i->tag,shape);
157 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
159 swf_ShapeSetLine(i->tag,shape,width*20,0);
160 swf_ShapeSetLine(i->tag,shape,0,height*20);
161 swf_ShapeSetLine(i->tag,shape,-width*20,0);
162 swf_ShapeSetLine(i->tag,shape,0,-height*20);
163 swf_ShapeSetEnd(i->tag);
164 i->filesize += swf_WriteTag2(&i->out, i->tag);
165 swf_ShapeFree(shape);
168 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
171 double ratio = (double) video->rate * speedup / swf_mp3_in_samplerate;
172 int rlen = (int)(len * ratio);
175 int r = /*resampled len */ rlen *
178 if(videoreader_getsamples(video, tmp, r) < r)
181 /* convert to 1 channel */
182 for(t=0;t<rlen;t++) {
185 for(s=0;s<video->channels;s++)
186 a += tmp[t*video->channels+s];
187 tmp[t] = a/video->channels;
190 /* down/up-sample to the desired input samplerate (swf_mp3_in_samplerate) */
192 data[t] = tmp[(int)pos];
198 static void writeAudioForOneFrame(v2swf_internal_t* i)
201 double blockspersecond;
202 double framespersecond, framesperblock, samplesperframe, samplesperblock;
205 double speedup = i->audio_fix;
208 S16 block1[576*4 * 2];
210 msg("writeAudioForOneFrame()");
212 if(i->video->channels<=0 || i->video->rate<=0)
213 return; /* no sound in video */
215 blocksize = (i->samplerate > 22050) ? 1152 : 576;
216 blockspersecond = ((double)i->samplerate)/blocksize;
218 /* notice: for framerates greater than about 35, audio starts getting choppy. */
219 framespersecond = i->framerate;
221 framesperblock = framespersecond / blockspersecond;
222 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
223 samplesperblock = samplesperframe * framesperblock;
225 msg("samplesperblock: %f", samplesperblock);
227 if(!i->soundstreamhead) {
228 swf_mp3_out_samplerate = i->samplerate;
229 /* The pre-processing of sound samples in getSamples(..) above
230 re-samples the sound to swf_mp3_in_samplerate. It is best to
231 simply make it the original samplerate: */
232 swf_mp3_in_samplerate = i->video->rate;
234 /* first run - initialize */
235 swf_mp3_channels = 1;//i->video->channels;
236 swf_mp3_bitrate = i->bitrate;
237 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
238 /* samplesperframe overrides the movie framerate: */
239 msg("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
240 swf_SetSoundStreamHead(i->tag, samplesperframe);
241 msg("swf_SetSoundStreamHead() done");
242 i->filesize += swf_WriteTag2(&i->out, i->tag);
243 i->soundstreamhead = 1;
246 /* for framerates greater than 19.14, every now and then a frame
247 hasn't a soundstreamblock. Determine whether this is the case.
249 msg("SOUND: frame:%d soundframepos:%f samplewritepos:%d samplepos:%f\n", i->frames, i->soundframepos, i->samplewritepos, i->samplepos);
250 if(i->frames < i->soundframepos) {
251 msg("SOUND: block skipped\n");
252 i->samplepos += samplesperframe;
258 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
260 i->samplewritepos += blocksize;
261 i->soundframepos += framesperblock;
264 while(i->samplewritepos < i->samplepos);
266 msg("SOUND: number of blocks: %d", num);
268 /* write num frames, max 1 block */
269 for(pos=0;pos<num;pos++) {
270 if(!getSamples(i->video, block1, blocksize * (double)swf_mp3_in_samplerate/swf_mp3_out_samplerate, speedup)) {
271 i->video->rate = i->video->channels = 0; //end of soundtrack
275 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
276 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
278 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
281 i->filesize += swf_WriteTag2(&i->out, i->tag);
283 i->seek = blocksize - (i->samplewritepos - i->samplepos);
284 i->samplepos += samplesperframe;
287 static void writeShowFrame(v2swf_internal_t* i)
290 writeAudioForOneFrame(i);
292 swf_ResetTag(i->tag, ST_SHOWFRAME);
293 i->filesize += swf_WriteTag2(&i->out, i->tag);
298 while(i->fpspos >= 1.0);
302 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
304 writeShape(i, shapeid, bmid, width, height);
306 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
309 swf_GetMatrix(0, &m);
310 m.sx = m.sy = i->scale;
311 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
313 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
315 i->filesize += swf_WriteTag2(&i->out, i->tag);
320 static int wwrite(struct writer_t*w, void*data, int len)
322 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
323 ringbuffer_put(&i->r, data, len);
327 static void wfinish(struct writer_t*w)
329 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
332 static void writehead(v2swf_internal_t*i)
334 char header[]="FWS\6\0\0\0\4";
339 header[3] = i->version;
340 if(i->version >= 6) { //MX
343 i->out2.write = wwrite;
344 i->out2.finish = wfinish;
345 i->out2.internal = i;
350 writer_init_zlibdeflate(&i->out, &i->out2);
352 i->out.write = wwrite;
353 i->out.finish = wfinish;
363 i->width = (int)(i->video->width*(i->scale/65536.0));
364 i->height = (int)(i->video->height*(i->scale/65536.0));
366 i->width = i->video->width;
367 i->height = i->video->height;
373 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
374 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
376 memset(&swf, 0, sizeof(SWF));
377 swf.fileVersion=i->version;
379 swf.frameCount = 65535;
380 swf.movieSize.xmax=i->width*20;
381 swf.movieSize.ymax=i->height*20;
382 swf.compressed = 8; /* 8 = compression done by caller (us) */
383 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
385 /* write the first 8 bytes to out */
386 i->out2.write(&i->out2, header, 8);
388 i->filesize += swf_WriteHeader2(&i->out, &swf);
389 i->headersize = i->filesize;
391 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
392 swf_SetU8(i->tag, 0); //black
393 swf_SetU8(i->tag, 0);
394 swf_SetU8(i->tag, 0);
395 i->filesize += swf_WriteTag2(&i->out, i->tag);
398 static void finish(v2swf_internal_t*i)
400 msg("finish(): i->finished=%d\n", i->finished);
402 msg("write endtag\n", i->finished);
404 swf_ResetTag(i->tag, ST_END);
405 i->filesize += swf_WriteTag2(&i->out, i->tag);
406 i->out.finish(&i->out);
409 swf_VideoStreamClear(&i->stream);
412 free(i->buffer);i->buffer = 0;
415 free(i->vrbuffer);i->vrbuffer = 0;
418 free(i->lastbitmap);i->lastbitmap = 0;
421 /* FIXME: we shouldn't be doing this. the caller should */
422 msg("call videoreader_close(%08x)\n", i->video);
423 videoreader_close(i->video);
427 msg("finishing done\n");
429 static void cleanup(v2swf_internal_t*i)
432 for(t=i->lastid;t<i->id;t++) {
434 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
435 swf_SetU16(i->tag, t);
436 i->filesize += swf_WriteTag2(&i->out, i->tag);
438 swf_ResetTag(i->tag, ST_FREECHARACTER);
439 swf_SetU16(i->tag, t);
440 i->filesize += swf_WriteTag2(&i->out, i->tag);
445 #define DIFFMODE_MAX 1
446 #define DIFFMODE_MEAN 2
447 #define DIFFMODE_EXACT 3
448 #define DIFFMODE_QMEAN 4
450 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
455 int rd = d1[1] - d2[1];
456 int gd = d1[2] - d2[2];
457 int bd = d1[3] - d2[3];
466 d1 += yadd; d2 += yadd;
471 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
477 int rd = d1[1] - d2[1];
478 int gd = d1[2] - d2[2];
479 int bd = d1[3] - d2[3];
487 d1 += yadd; d2 += yadd;
489 if(mean/(xl*yl) > maxdiff)
494 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
500 int rd = d1[1] - d2[1];
501 int gd = d1[2] - d2[2];
502 int bd = d1[3] - d2[3];
512 d1 += yadd; d2 += yadd;
514 if(mean/(xl*yl) > maxdiff*maxdiff)
519 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
524 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
529 d1 += yadd; d2 += yadd;
534 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
535 U32 g = ((r << 3) ^ r)&0x80808080;
539 static void checkInit(v2swf_internal_t*i)
544 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
545 swf_SetU16(i->tag, 99);
546 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
547 i->filesize += swf_WriteTag2(&i->out, i->tag);
549 i->stream.do_motion = 1;
556 static void scaleimage(v2swf_internal_t*i)
560 int xm = (i->video->width*65536)/i->width;
561 int ym = (i->video->height*65536)/i->height;
562 memset(i->buffer, 255, i->width*i->height*4);
563 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
564 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
565 int*dest = &((int*)i->buffer)[y*i->width];
566 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
567 dest[x] = src[xv>>16];
570 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
573 static int encodeoneframe(v2swf_internal_t*i)
575 videoreader_t*video = i->video;
580 if(videoreader_eof(i->video) || !videoreader_getimage(i->video, i->vrbuffer))
582 msg("videoreader returned eof\n");
587 i->fpspos += i->fpsratio;
594 msg("encoding image for frame %d\n", i->frames);
603 msg("version is %d\n", i->version);
605 if(i->version <= 4) {
608 int shapeid = i->id++;
609 int width2 = i->width * 4;
612 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
613 swf_SetU16(i->tag, i->id-3);
614 i->filesize += swf_WriteTag2(&i->out, i->tag);
615 swf_ResetTag(i->tag, ST_FREECHARACTER);
616 swf_SetU16(i->tag, i->id-4);
617 i->filesize += swf_WriteTag2(&i->out, i->tag);
620 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
621 swf_SetU16(i->tag, bmid);
622 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
623 i->filesize += swf_WriteTag2(&i->out, i->tag);
625 writeShowTags(i, shapeid, bmid, i->width, i->height);
627 } else if(i->version == 5) {
628 int width2 = i->width * 4;
629 int width8 = (i->width+7)/8;
630 int height8 = (i->height+7)/8;
632 /* the idea is here to only update those jpeg 8x8 blocks
633 which actually have changed. This means that we have to keep
634 the bitmap from the last frame for the comparison. */
637 if(!i->lastbitmap || !i->keyframe) {
642 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
643 i->lastbitmap = (U8*)malloc(width2*i->height);
645 memcpy(i->lastbitmap, i->buffer, width2*i->height);
647 i->keyframe = i->keyframe_interval;
651 width2 = i->width * 4;
652 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
653 swf_SetU16(i->tag, bmid);
654 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
655 i->filesize += swf_WriteTag2(&i->out, i->tag);
657 writeShowTags(i, shapeid, bmid, i->width, i->height);
660 /* The following looks so ugly because it's somewhat optimized.
661 What it does is walk through all the 8x8 blocks, find those
662 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
663 It also set's alpha to 255 in those who haven't changed, and
664 copies them to lastbitmap.
668 //int maxdiff = ((100 - i->quality)*256)/100;
669 int maxdiff = i->blockdiff*3;
670 for(y8=0;y8<height8;y8++)
671 for(x8=0;x8<width8;x8++) {
676 if(x8*8+xl > i->width)
677 xl = i->width - x8*8;
678 if(y8*8+yl > i->height)
679 yl = i->height - y8*8;
680 d1 = &i->buffer[width2*y8*8+x8*8*4];
682 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
684 yadd = width2 - (xl*4);
686 if(i->diffmode == DIFFMODE_MAX) {
687 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
689 } else if(i->diffmode == DIFFMODE_MEAN) {
690 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
692 } else if(i->diffmode == DIFFMODE_EXACT) {
693 if(blockdiff_exact(d1, d2, yadd, xl, yl))
695 } else if(i->diffmode == DIFFMODE_QMEAN) {
696 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
711 *(U32*)d2b = *(U32*)d1b;
715 d1b += yadd; d2b += yadd;
719 /* ok, done. Now a) data is zeroed out in regions which haven't changed
720 b) lastbitmap equals the bitmap we were called with
721 c) data's alpha value is set to 255 in regions which did change */
727 int shapeid = i->id++;
729 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
730 swf_SetU16(i->tag, bmid);
731 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
732 i->filesize += swf_WriteTag2(&i->out, i->tag);
734 writeShowTags(i, shapeid, bmid, i->width, i->height);
737 int quant = 1+(30-(30*i->quality)/100);
740 swf_GetPlaceObject(0, &obj);
742 obj.matrix.sx = obj.matrix.sy = i->scale;
745 if(i->stream.frame==0) {
751 obj.ratio = i->stream.frame;
754 swf_ResetTag(i->tag, ST_VIDEOFRAME);
755 swf_SetU16(i->tag, 99);
756 if(!(--i->keyframe)) {
757 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
758 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
759 i->keyframe = i->keyframe_interval;
761 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
762 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
764 i->filesize += swf_WriteTag2(&i->out, i->tag);
766 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
767 swf_SetPlaceObject(i->tag,&obj);
768 i->filesize += swf_WriteTag2(&i->out, i->tag);
774 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
779 msg("v2swf_init()\n");
780 memset(v2swf, 0, sizeof(v2swf_t));
781 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
782 memset(i, 0, sizeof(v2swf_internal_t));
785 ringbuffer_init(&i->r);
787 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
791 i->keyframe_interval = 8;
794 i->samplerate = 11025;
797 i->diffmode = DIFFMODE_QMEAN;
800 i->framerate = video->fps;
801 i->fpsratio = 1.00000000;
814 memset(&i->out, 0, sizeof(struct writer_t));
815 memset(&i->out2, 0, sizeof(struct writer_t));
819 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
823 msg("v2swf_read(%d)\n", len);
824 i = (v2swf_internal_t*)v2swf->internal;
826 while(!i->finished && i->r.available < len) {
827 if(!encodeoneframe(i)) {
831 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
832 l = ringbuffer_read(&i->r, buffer, len);
836 void v2swf_close(v2swf_t*v2swf)
838 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
839 msg("close(): i->finished=%d\n", i->finished);
841 /* needed only if aborting: */
844 msg("freeing memory\n");
845 free(v2swf->internal);
846 memset(v2swf, 0, sizeof(v2swf_t));
847 msg("close() done\n");
850 static int mp3_bitrates[] =
851 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
853 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
857 msg("set parameters %s to %s\n", name, value);
859 if(!strcmp(name, "verbose")) {
861 msg("set parameters %s to %s\n", name, value);
865 if(!v2swf || !v2swf->internal) {
866 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
869 i = (v2swf_internal_t*)v2swf->internal;
871 if(!strcmp(name, "flash_version")) {
872 i->version = atoi(value);
873 } else if(!strcmp(name, "audiosync")) {
874 i->audio_fix = (int)(atof(value));
875 } else if(!strcmp(name, "scale")) {
876 i->scale = (int)(atof(value)*65536);
877 } else if(!strcmp(name, "scale65536")) {
878 i->scale = atoi(value);
879 } else if(!strcmp(name, "quality")) {
880 i->quality = atoi(value);
881 } else if(!strcmp(name, "motioncompensation")) {
882 i->domotion = atoi(value);
883 } else if(!strcmp(name, "prescale")) {
884 i->prescale = atoi(value);
885 } else if(!strcmp(name, "blockdiff")) {
886 i->blockdiff = atoi(value);
887 } else if(!strcmp(name, "fixheader")) {
888 i->fixheader = atoi(value);
889 } else if(!strcmp(name, "samplerate")) {
890 i->samplerate = atoi(value);
891 } else if(!strcmp(name, "framerate")) {
892 i->framerate = atof(value);
893 i->fpsratio = i->framerate / i->video->fps;
895 else if(!strcmp(name, "mp3_bitrate")) {
897 i->bitrate = o = atoi(value);
900 while(mp3_bitrates[t]) {
901 if(i->bitrate <= mp3_bitrates[t]) {
902 i->bitrate = mp3_bitrates[t];
907 msg("bitrate %d requested, setting to %d", o, i->bitrate);
909 else if(!strcmp(name, "blockdiff_mode")) {
910 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
911 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
912 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
913 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
915 printf("diffmode %s not recognized\n", value);
916 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
919 else if(!strcmp(name, "keyframe_interval")
920 || !strcmp(name, "keyframe")) {
921 int k = atoi(value);if(k<=0) k=1;
922 i->keyframe_interval = k;
925 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
929 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
933 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
934 msg("v2swf_backpatch %s\n", filename);
936 printf("call backpatch before close\n");fflush(stdout);
938 fi = fopen(filename, "rb+");
940 printf("can't open %s\n", filename);
943 fseek(fi, 4, SEEK_SET);
944 f = i->filesize ;fwrite(&f,1,1,fi);
945 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
946 f = i->filesize >> 16;fwrite(&f,1,1,fi);
947 f = i->filesize >> 24;fwrite(&f,1,1,fi);
949 /* no compression- we can backpatch the frames too */
950 fseek(fi, i->headersize-2, SEEK_SET);
951 f = i->frames ;fwrite(&f,1,1,fi);
952 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
958 msg("v2swf_backpatch %s - fix header\n", filename);
959 memset(&tmp, 0, sizeof(tmp));
960 fi = open(filename, O_RDONLY|O_BINARY);
962 if(swf_ReadSWF(fi, &tmp)>=0) {
964 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
966 swf_WriteSWC(fi, &tmp);
968 msg("v2swf_backpatch %s - fix header: success\n", filename);
975 float v2swf_getprogress(v2swf_t*v2swf)
979 msg("v2swf_getprogress()");
980 if(!v2swf || !v2swf->internal) {
983 i = (v2swf_internal_t*)v2swf->internal;
985 p = (float*)videoreader_getinfo(i->video, "position");
990 float f = i->frames/1500.0; /*fake*/
998 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
1000 msg("v2swf_setvideoparameter()");
1001 videoreader_setparameter(v, name, value);