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 msg("encoding image for frame %d\n", i->frames);
589 i->fpspos += i->fpsratio;
601 msg("version is %d\n", i->version);
603 if(i->version <= 4) {
606 int shapeid = i->id++;
607 int width2 = i->width * 4;
610 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
611 swf_SetU16(i->tag, i->id-3);
612 i->filesize += swf_WriteTag2(&i->out, i->tag);
613 swf_ResetTag(i->tag, ST_FREECHARACTER);
614 swf_SetU16(i->tag, i->id-4);
615 i->filesize += swf_WriteTag2(&i->out, i->tag);
618 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
619 swf_SetU16(i->tag, bmid);
620 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
621 i->filesize += swf_WriteTag2(&i->out, i->tag);
623 writeShowTags(i, shapeid, bmid, i->width, i->height);
625 } else if(i->version == 5) {
626 int width2 = i->width * 4;
627 int width8 = (i->width+7)/8;
628 int height8 = (i->height+7)/8;
630 /* the idea is here to only update those jpeg 8x8 blocks
631 which actually have changed. This means that we have to keep
632 the bitmap from the last frame for the comparison. */
635 if(!i->lastbitmap || !i->keyframe) {
640 msg("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
641 i->lastbitmap = (U8*)malloc(width2*i->height);
643 memcpy(i->lastbitmap, i->buffer, width2*i->height);
645 i->keyframe = i->keyframe_interval;
649 width2 = i->width * 4;
650 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
651 swf_SetU16(i->tag, bmid);
652 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
653 i->filesize += swf_WriteTag2(&i->out, i->tag);
655 writeShowTags(i, shapeid, bmid, i->width, i->height);
658 /* The following looks so ugly because it's somewhat optimized.
659 What it does is walk through all the 8x8 blocks, find those
660 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
661 It also set's alpha to 255 in those who haven't changed, and
662 copies them to lastbitmap.
666 //int maxdiff = ((100 - i->quality)*256)/100;
667 int maxdiff = i->blockdiff*3;
668 for(y8=0;y8<height8;y8++)
669 for(x8=0;x8<width8;x8++) {
674 if(x8*8+xl > i->width)
675 xl = i->width - x8*8;
676 if(y8*8+yl > i->height)
677 yl = i->height - y8*8;
678 d1 = &i->buffer[width2*y8*8+x8*8*4];
680 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
682 yadd = width2 - (xl*4);
684 if(i->diffmode == DIFFMODE_MAX) {
685 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
687 } else if(i->diffmode == DIFFMODE_MEAN) {
688 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
690 } else if(i->diffmode == DIFFMODE_EXACT) {
691 if(blockdiff_exact(d1, d2, yadd, xl, yl))
693 } else if(i->diffmode == DIFFMODE_QMEAN) {
694 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
709 *(U32*)d2b = *(U32*)d1b;
713 d1b += yadd; d2b += yadd;
717 /* ok, done. Now a) data is zeroed out in regions which haven't changed
718 b) lastbitmap equals the bitmap we were called with
719 c) data's alpha value is set to 255 in regions which did change */
725 int shapeid = i->id++;
727 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
728 swf_SetU16(i->tag, bmid);
729 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
730 i->filesize += swf_WriteTag2(&i->out, i->tag);
732 writeShowTags(i, shapeid, bmid, i->width, i->height);
735 int quant = 1+(30-(30*i->quality)/100);
738 swf_GetPlaceObject(0, &obj);
740 obj.matrix.sx = obj.matrix.sy = i->scale;
743 if(i->stream.frame==0) {
749 obj.ratio = i->stream.frame;
752 swf_ResetTag(i->tag, ST_VIDEOFRAME);
753 swf_SetU16(i->tag, 99);
754 if(!(--i->keyframe)) {
755 msg("setting video I-frame, ratio=%d\n", i->stream.frame);
756 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
757 i->keyframe = i->keyframe_interval;
759 msg("setting video P-frame, ratio=%d\n", i->stream.frame);
760 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
762 i->filesize += swf_WriteTag2(&i->out, i->tag);
764 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
765 swf_SetPlaceObject(i->tag,&obj);
766 i->filesize += swf_WriteTag2(&i->out, i->tag);
772 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
777 msg("v2swf_init()\n");
778 memset(v2swf, 0, sizeof(v2swf_t));
779 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
780 memset(i, 0, sizeof(v2swf_internal_t));
783 ringbuffer_init(&i->r);
785 msg("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
789 i->keyframe_interval = 8;
792 i->samplerate = 11025;
795 i->diffmode = DIFFMODE_QMEAN;
798 i->framerate = video->fps;
799 i->fpsratio = 1.00000000000;
812 memset(&i->out, 0, sizeof(struct writer_t));
813 memset(&i->out2, 0, sizeof(struct writer_t));
817 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
821 msg("v2swf_read(%d)\n", len);
822 i = (v2swf_internal_t*)v2swf->internal;
824 while(!i->finished && i->r.available < len) {
825 if(!encodeoneframe(i)) {
829 msg("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
830 l = ringbuffer_read(&i->r, buffer, len);
834 void v2swf_close(v2swf_t*v2swf)
836 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
837 msg("close(): i->finished=%d\n", i->finished);
839 /* needed only if aborting: */
842 msg("freeing memory\n");
843 free(v2swf->internal);
844 memset(v2swf, 0, sizeof(v2swf_t));
845 msg("close() done\n");
848 static int mp3_bitrates[] =
849 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
851 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
855 msg("set parameters %s to %s\n", name, value);
857 if(!strcmp(name, "verbose")) {
859 msg("set parameters %s to %s\n", name, value);
863 if(!v2swf || !v2swf->internal) {
864 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
867 i = (v2swf_internal_t*)v2swf->internal;
869 if(!strcmp(name, "flash_version")) {
870 i->version = atoi(value);
871 } else if(!strcmp(name, "audiosync")) {
872 i->audio_fix = (int)(atof(value));
873 } else if(!strcmp(name, "scale")) {
874 i->scale = (int)(atof(value)*65536);
875 } else if(!strcmp(name, "scale65536")) {
876 i->scale = atoi(value);
877 } else if(!strcmp(name, "quality")) {
878 i->quality = atoi(value);
879 } else if(!strcmp(name, "motioncompensation")) {
880 i->domotion = atoi(value);
881 } else if(!strcmp(name, "prescale")) {
882 i->prescale = atoi(value);
883 } else if(!strcmp(name, "blockdiff")) {
884 i->blockdiff = atoi(value);
885 } else if(!strcmp(name, "fixheader")) {
886 i->fixheader = atoi(value);
887 } else if(!strcmp(name, "samplerate")) {
888 i->samplerate = atoi(value);
889 } else if(!strcmp(name, "framerate")) {
890 i->framerate = atof(value);
891 i->fpsratio = i->framerate / i->video->fps;
893 else if(!strcmp(name, "mp3_bitrate")) {
895 i->bitrate = o = atoi(value);
898 while(mp3_bitrates[t]) {
899 if(i->bitrate <= mp3_bitrates[t]) {
900 i->bitrate = mp3_bitrates[t];
905 msg("bitrate %d requested, setting to %d", o, i->bitrate);
907 else if(!strcmp(name, "blockdiff_mode")) {
908 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
909 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
910 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
911 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
913 printf("diffmode %s not recognized\n", value);
914 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
917 else if(!strcmp(name, "keyframe_interval")
918 || !strcmp(name, "keyframe")) {
919 int k = atoi(value);if(k<=0) k=1;
920 i->keyframe_interval = k;
923 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
927 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
931 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
932 msg("v2swf_backpatch %s\n", filename);
934 printf("call backpatch before close\n");fflush(stdout);
936 fi = fopen(filename, "rb+");
938 printf("can't open %s\n", filename);
941 fseek(fi, 4, SEEK_SET);
942 f = i->filesize ;fwrite(&f,1,1,fi);
943 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
944 f = i->filesize >> 16;fwrite(&f,1,1,fi);
945 f = i->filesize >> 24;fwrite(&f,1,1,fi);
947 /* no compression- we can backpatch the frames too */
948 fseek(fi, i->headersize-2, SEEK_SET);
949 f = i->frames ;fwrite(&f,1,1,fi);
950 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
956 msg("v2swf_backpatch %s - fix header\n", filename);
957 memset(&tmp, 0, sizeof(tmp));
958 fi = open(filename, O_RDONLY|O_BINARY);
960 if(swf_ReadSWF(fi, &tmp)>=0) {
962 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
964 swf_WriteSWC(fi, &tmp);
966 msg("v2swf_backpatch %s - fix header: success\n", filename);
973 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
975 msg("v2swf_setvideoparameter()");
976 videoreader_setparameter(v, name, value);