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;
91 static int verbose = 0;
92 static int filelog = 0;
94 static void logf(char*format, ...)
101 va_start(arglist, format);
102 vsprintf(buf, format, arglist);
105 while(l && buf[l-1]=='\n') {
111 FILE*fi = fopen("debug.log", "ab+");
112 fprintf(fi, "(v2swf) %s\n", buf);
117 printf("(v2swf) %s\n", buf);
121 static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height)
129 swf_ResetTag(i->tag, ST_DEFINESHAPE);
130 swf_ShapeNew(&shape);
131 rgb.b = rgb.g = rgb.r = 0xff;
133 ls = swf_ShapeAddLineStyle(shape,20,&rgb);
134 swf_GetMatrix(NULL,&m);
138 fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0);
139 swf_SetU16(i->tag,id); // ID
144 swf_SetRect(i->tag,&r);
146 swf_SetShapeStyles(i->tag,shape);
147 swf_ShapeCountBits(shape,NULL,NULL);
148 swf_SetShapeBits(i->tag,shape);
150 swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0);
152 swf_ShapeSetLine(i->tag,shape,width*20,0);
153 swf_ShapeSetLine(i->tag,shape,0,height*20);
154 swf_ShapeSetLine(i->tag,shape,-width*20,0);
155 swf_ShapeSetLine(i->tag,shape,0,-height*20);
156 swf_ShapeSetEnd(i->tag);
157 i->filesize += swf_WriteTag2(&i->out, i->tag);
158 swf_ShapeFree(shape);
161 static int getSamples(videoreader_t*video, S16*data, int len, double speedup)
164 double ratio = video->rate * speedup / 44100.0;
165 int rlen = (int)(len * ratio);
168 int r = /*resampled len */ rlen *
171 if(videoreader_getsamples(video, tmp, r) < r)
174 /* convert to 1 channel */
175 for(t=0;t<rlen;t++) {
178 for(s=0;s<video->channels;s++)
179 a += tmp[t*video->channels+s];
180 tmp[t] = a/video->channels;
183 /* down/up-sample to 44khz */
185 data[t] = tmp[(int)pos];
191 extern int swf_mp3_channels;
192 extern int swf_mp3_bitrate;
193 extern int swf_mp3_samplerate;
194 static void writeAudioForOneFrame(v2swf_internal_t* i)
197 double blockspersecond;
198 double framespersecond, framesperblock, samplesperframe, samplesperblock;
201 double speedup = i->audio_fix;
204 S16 block1[576*4 * 2];
206 logf("writeAudioForOneFrame()");
208 if(i->video->channels<=0 || i->video->rate<=0)
209 return; /* no sound in video */
211 blocksize = 576; /* 11khz samples per mp3 block */
212 blockspersecond = 11025.0/blocksize;
214 /* notice: for framerates greater than about 35, audio starts getting choppy. */
215 framespersecond = i->framerate;
217 framesperblock = framespersecond / blockspersecond;
218 samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */
219 samplesperblock = samplesperframe * framesperblock;
221 logf("samplesperblock: %f", samplesperblock);
223 if(!i->soundstreamhead) {
224 /* first run - initialize */
225 swf_mp3_channels = 1;//i->video->channels;
226 swf_mp3_bitrate = i->bitrate;
227 swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD);
228 /* samplesperframe overrides the movie framerate: */
229 logf("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe);
230 swf_SetSoundStreamHead(i->tag, samplesperframe);
231 logf("swf_SetSoundStreamHead() done");
232 i->filesize += swf_WriteTag2(&i->out, i->tag);
233 i->soundstreamhead = 1;
236 /* for framerates greater than 19.14, every now and then a frame
237 hasn't a soundstreamblock. Determine whether this is the case.
239 if(i->frames < i->soundframepos) {
240 i->samplepos += samplesperframe;
246 //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) {
247 while(i->samplewritepos < i->samplepos + blocksize) {
248 i->samplewritepos += blocksize;
249 i->soundframepos += framesperblock;
254 printf(" num is zero\n");
255 fprintf(stderr, " num is zero\n");
257 logf("num: %d", num);
259 /* write num frames, max 1 block */
260 for(pos=0;pos<num;pos++) {
261 logf("pos: %d- getsamples", pos);
262 if(!getSamples(i->video, block1, 576*4, speedup)) { /* 4 = 44100/11025 */
263 i->video->rate = i->video->channels = 0; //end of soundtrack
266 logf("pos: %d- encode mp3", pos);
268 swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK);
269 swf_SetSoundStreamBlock(i->tag, block1, seek, num);
271 swf_SetSoundStreamBlock(i->tag, block1, seek, 0);
274 i->filesize += swf_WriteTag2(&i->out, i->tag);
276 i->seek = i->samplewritepos - (i->samplepos + blocksize);
277 i->samplepos += samplesperframe;
278 logf("writeSamplesForOneFrame(): done");
281 static void writeShowFrame(v2swf_internal_t* i)
284 writeAudioForOneFrame(i);
286 swf_ResetTag(i->tag, ST_SHOWFRAME);
287 i->filesize += swf_WriteTag2(&i->out, i->tag);
292 while(i->fpspos >= 1.0);
296 static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height)
298 writeShape(i, shapeid, bmid, width, height);
300 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
303 swf_GetMatrix(0, &m);
304 m.sx = m.sy = i->scale;
305 swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0);
307 swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0);
309 i->filesize += swf_WriteTag2(&i->out, i->tag);
314 static int wwrite(struct writer_t*w, void*data, int len)
316 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
317 ringbuffer_put(&i->r, data, len);
321 static void wfinish(struct writer_t*w)
323 v2swf_internal_t* i = (v2swf_internal_t*)w->internal;
326 static void writehead(v2swf_internal_t*i)
328 char header[]="FWS\6\0\0\0\4";
333 header[3] = i->version;
334 if(i->version >= 6) { //MX
337 i->out2.write = wwrite;
338 i->out2.finish = wfinish;
339 i->out2.internal = i;
344 writer_init_zlibdeflate(&i->out, &i->out2);
346 i->out.write = wwrite;
347 i->out.finish = wfinish;
357 i->width = (int)(i->video->width*(i->scale/65536.0));
358 i->height = (int)(i->video->height*(i->scale/65536.0));
360 i->width = i->video->width;
361 i->height = i->video->height;
367 i->buffer = (unsigned char*)malloc(i->width*i->height*4);
368 i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4);
370 memset(&swf, 0, sizeof(SWF));
371 swf.fileVersion=i->version;
373 swf.frameCount = 65535;
374 swf.movieSize.xmax=i->width*20;
375 swf.movieSize.ymax=i->height*20;
376 swf.compressed = 8; /* 8 = compression done by caller (us) */
377 swf.frameRate = (int)(i->framerate*0x100);//25*0x100;
379 /* write the first 8 bytes to out */
380 i->out2.write(&i->out2, header, 8);
382 i->filesize += swf_WriteHeader2(&i->out, &swf);
383 i->headersize = i->filesize;
385 i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
386 swf_SetU8(i->tag, 0); //black
387 swf_SetU8(i->tag, 0);
388 swf_SetU8(i->tag, 0);
389 i->filesize += swf_WriteTag2(&i->out, i->tag);
392 static void finish(v2swf_internal_t*i)
394 logf("finish(): i->finished=%d\n", i->finished);
396 logf("write endtag\n", i->finished);
398 swf_ResetTag(i->tag, ST_END);
399 i->filesize += swf_WriteTag2(&i->out, i->tag);
400 i->out.finish(&i->out);
403 swf_VideoStreamClear(&i->stream);
406 free(i->buffer);i->buffer = 0;
409 free(i->vrbuffer);i->vrbuffer = 0;
412 free(i->lastbitmap);i->lastbitmap = 0;
415 /* FIXME: we shouldn't be doing this. the caller should */
416 logf("call videoreader_close(%08x)\n", i->video);
417 videoreader_close(i->video);
421 logf("finishing done\n");
423 static void cleanup(v2swf_internal_t*i)
426 for(t=i->lastid;t<i->id;t++) {
428 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
429 swf_SetU16(i->tag, t);
430 i->filesize += swf_WriteTag2(&i->out, i->tag);
432 swf_ResetTag(i->tag, ST_FREECHARACTER);
433 swf_SetU16(i->tag, t);
434 i->filesize += swf_WriteTag2(&i->out, i->tag);
439 #define DIFFMODE_MAX 1
440 #define DIFFMODE_MEAN 2
441 #define DIFFMODE_EXACT 3
442 #define DIFFMODE_QMEAN 4
444 static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
449 int rd = d1[1] - d2[1];
450 int gd = d1[2] - d2[2];
451 int bd = d1[3] - d2[3];
460 d1 += yadd; d2 += yadd;
465 static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
471 int rd = d1[1] - d2[1];
472 int gd = d1[2] - d2[2];
473 int bd = d1[3] - d2[3];
481 d1 += yadd; d2 += yadd;
483 if(mean/(xl*yl) > maxdiff)
488 static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl)
494 int rd = d1[1] - d2[1];
495 int gd = d1[2] - d2[2];
496 int bd = d1[3] - d2[3];
506 d1 += yadd; d2 += yadd;
508 if(mean/(xl*yl) > maxdiff*maxdiff)
513 static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl)
518 if((*(U32*)d1^*(U32*)d2)&0xffffff00) { //bits [RGB_] of [RGBA] differ
523 d1 += yadd; d2 += yadd;
528 /*U32 r = (*(U32*)d1^-(U32*)d2)&0xffffff00;
529 U32 g = ((r << 3) ^ r)&0x80808080;
533 static void checkInit(v2swf_internal_t*i)
538 swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM);
539 swf_SetU16(i->tag, 99);
540 swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height);
541 i->filesize += swf_WriteTag2(&i->out, i->tag);
543 i->stream.do_motion = 1;
550 static void scaleimage(v2swf_internal_t*i)
554 int xm = (i->video->width*65536)/i->width;
555 int ym = (i->video->height*65536)/i->height;
556 memset(i->buffer, 255, i->width*i->height*4);
557 for(y=0,yv=0;y<i->height;y++,yv+=ym) {
558 int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width];
559 int*dest = &((int*)i->buffer)[y*i->width];
560 for(x=0,xv=0;x<i->width;x++,xv+=xm) {
561 dest[x] = src[xv>>16];
564 //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4);
567 static int encodeoneframe(v2swf_internal_t*i)
569 videoreader_t*video = i->video;
574 if(videoreader_eof(i->video) || !videoreader_getimage(i->video, i->vrbuffer))
576 logf("videoreader returned eof\n");
581 i->fpspos += i->fpsratio;
588 logf("encoding image for frame %d\n", i->frames);
597 logf("version is %d\n", i->version);
599 if(i->version <= 4) {
602 int shapeid = i->id++;
603 int width2 = i->width * 4;
606 swf_ResetTag(i->tag, ST_REMOVEOBJECT2);
607 swf_SetU16(i->tag, i->id-3);
608 i->filesize += swf_WriteTag2(&i->out, i->tag);
609 swf_ResetTag(i->tag, ST_FREECHARACTER);
610 swf_SetU16(i->tag, i->id-4);
611 i->filesize += swf_WriteTag2(&i->out, i->tag);
614 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
615 swf_SetU16(i->tag, bmid);
616 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
617 i->filesize += swf_WriteTag2(&i->out, i->tag);
619 writeShowTags(i, shapeid, bmid, i->width, i->height);
621 } else if(i->version == 5) {
622 int width2 = i->width * 4;
623 int width8 = (i->width+7)/8;
624 int height8 = (i->height+7)/8;
626 /* the idea is here to only update those jpeg 8x8 blocks
627 which actually have changed. This means that we have to keep
628 the bitmap from the last frame for the comparison. */
631 if(!i->lastbitmap || !i->keyframe) {
636 logf("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8);
637 i->lastbitmap = (U8*)malloc(width2*i->height);
639 memcpy(i->lastbitmap, i->buffer, width2*i->height);
641 i->keyframe = i->keyframe_interval;
645 width2 = i->width * 4;
646 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2);
647 swf_SetU16(i->tag, bmid);
648 swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
649 i->filesize += swf_WriteTag2(&i->out, i->tag);
651 writeShowTags(i, shapeid, bmid, i->width, i->height);
654 /* The following looks so ugly because it's somewhat optimized.
655 What it does is walk through all the 8x8 blocks, find those
656 which have changed too much and set all others to (R,G,B,A)=(0,0,0,0).
657 It also set's alpha to 255 in those who haven't changed, and
658 copies them to lastbitmap.
662 //int maxdiff = ((100 - i->quality)*256)/100;
663 int maxdiff = i->blockdiff*3;
664 for(y8=0;y8<height8;y8++)
665 for(x8=0;x8<width8;x8++) {
670 if(x8*8+xl > i->width)
671 xl = i->width - x8*8;
672 if(y8*8+yl > i->height)
673 yl = i->height - y8*8;
674 d1 = &i->buffer[width2*y8*8+x8*8*4];
676 d2 = &i->lastbitmap[width2*y8*8+x8*8*4];
678 yadd = width2 - (xl*4);
680 if(i->diffmode == DIFFMODE_MAX) {
681 if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl))
683 } else if(i->diffmode == DIFFMODE_MEAN) {
684 if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl))
686 } else if(i->diffmode == DIFFMODE_EXACT) {
687 if(blockdiff_exact(d1, d2, yadd, xl, yl))
689 } else if(i->diffmode == DIFFMODE_QMEAN) {
690 if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl))
705 *(U32*)d2b = *(U32*)d1b;
709 d1b += yadd; d2b += yadd;
713 /* ok, done. Now a) data is zeroed out in regions which haven't changed
714 b) lastbitmap equals the bitmap we were called with
715 c) data's alpha value is set to 255 in regions which did change */
721 int shapeid = i->id++;
723 swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3);
724 swf_SetU16(i->tag, bmid);
725 swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality);
726 i->filesize += swf_WriteTag2(&i->out, i->tag);
728 writeShowTags(i, shapeid, bmid, i->width, i->height);
731 int quant = 1+(30-(30*i->quality)/100);
734 swf_GetPlaceObject(0, &obj);
736 obj.matrix.sx = obj.matrix.sy = i->scale;
739 if(i->stream.frame==0) {
745 obj.ratio = i->stream.frame;
748 swf_ResetTag(i->tag, ST_VIDEOFRAME);
749 swf_SetU16(i->tag, 99);
750 if(!(--i->keyframe)) {
751 logf("setting video I-frame, ratio=%d\n", i->stream.frame);
752 swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
753 i->keyframe = i->keyframe_interval;
755 logf("setting video P-frame, ratio=%d\n", i->stream.frame);
756 swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant);
758 i->filesize += swf_WriteTag2(&i->out, i->tag);
760 swf_ResetTag(i->tag, ST_PLACEOBJECT2);
761 swf_SetPlaceObject(i->tag,&obj);
762 i->filesize += swf_WriteTag2(&i->out, i->tag);
768 int v2swf_init(v2swf_t*v2swf, videoreader_t * video)
773 logf("v2swf_init()\n");
774 memset(v2swf, 0, sizeof(v2swf_t));
775 i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t));
776 memset(i, 0, sizeof(v2swf_internal_t));
779 ringbuffer_init(&i->r);
781 logf("video: %dx%d, fps %f\n", video->width, video->height, video->fps);
785 i->keyframe_interval = 8;
790 i->diffmode = DIFFMODE_QMEAN;
793 i->framerate = video->fps;
794 i->fpsratio = 1.00000000;
807 memset(&i->out, 0, sizeof(struct writer_t));
808 memset(&i->out2, 0, sizeof(struct writer_t));
812 int v2swf_read(v2swf_t*v2swf, void*buffer, int len)
816 logf("v2swf_read(%d)\n", len);
817 i = (v2swf_internal_t*)v2swf->internal;
819 while(!i->finished && i->r.available < len) {
820 if(!encodeoneframe(i)) {
824 logf("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available);
825 l = ringbuffer_read(&i->r, buffer, len);
829 void v2swf_close(v2swf_t*v2swf)
831 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
832 logf("close(): i->finished=%d\n", i->finished);
834 /* needed only if aborting: */
837 logf("freeing memory\n");
838 free(v2swf->internal);
839 memset(v2swf, 0, sizeof(v2swf_t));
840 logf("close() done\n");
843 static int mp3_bitrates[] =
844 { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0};
846 void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value)
850 logf("set parameters %s to %s\n", name, value);
852 if(!strcmp(name, "verbose")) {
854 logf("set parameters %s to %s\n", name, value);
858 if(!v2swf || !v2swf->internal) {
859 printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout);
862 i = (v2swf_internal_t*)v2swf->internal;
864 if(!strcmp(name, "flash_version")) {
865 i->version = atoi(value);
866 } else if(!strcmp(name, "audiosync")) {
867 i->audio_fix = (int)(atof(value));
868 } else if(!strcmp(name, "scale")) {
869 i->scale = (int)(atof(value)*65536);
870 } else if(!strcmp(name, "scale65536")) {
871 i->scale = atoi(value);
872 } else if(!strcmp(name, "quality")) {
873 i->quality = atoi(value);
874 } else if(!strcmp(name, "motioncompensation")) {
875 i->domotion = atoi(value);
876 } else if(!strcmp(name, "prescale")) {
877 i->prescale = atoi(value);
878 } else if(!strcmp(name, "blockdiff")) {
879 i->blockdiff = atoi(value);
880 } else if(!strcmp(name, "fixheader")) {
881 i->fixheader = atoi(value);
882 } else if(!strcmp(name, "framerate")) {
883 i->framerate = atof(value);
884 i->fpsratio = i->framerate / i->video->fps;
886 else if(!strcmp(name, "mp3_bitrate")) {
888 i->bitrate = o = atoi(value);
891 while(mp3_bitrates[t]) {
892 if(i->bitrate <= mp3_bitrates[t]) {
893 i->bitrate = mp3_bitrates[t];
898 logf("bitrate %d requested, setting to %d", o, i->bitrate);
900 else if(!strcmp(name, "blockdiff_mode")) {
901 if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX;
902 else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN;
903 else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN;
904 else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT;
906 printf("diffmode %s not recognized\n", value);
907 printf("valid diffmodes are: %s\n", "max, mean, qmean, exact");
910 else if(!strcmp(name, "keyframe_interval")
911 || !strcmp(name, "keyframe")) {
912 int k = atoi(value);if(k<=0) k=1;
913 i->keyframe_interval = k;
916 printf("Setting encoder.%s not recognized!\n", name);fflush(stdout);
920 void v2swf_backpatch(v2swf_t*v2swf, char*filename)
924 v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal;
925 logf("v2swf_backpatch %s\n", filename);
927 printf("call backpatch before close\n");fflush(stdout);
929 fi = fopen(filename, "rb+");
931 printf("can't open %s\n", filename);
934 fseek(fi, 4, SEEK_SET);
935 f = i->filesize ;fwrite(&f,1,1,fi);
936 f = i->filesize >> 8 ;fwrite(&f,1,1,fi);
937 f = i->filesize >> 16;fwrite(&f,1,1,fi);
938 f = i->filesize >> 24;fwrite(&f,1,1,fi);
940 /* no compression- we can backpatch the frames too */
941 fseek(fi, i->headersize-2, SEEK_SET);
942 f = i->frames ;fwrite(&f,1,1,fi);
943 f = i->frames >> 8 ;fwrite(&f,1,1,fi);
949 logf("v2swf_backpatch %s - fix header\n", filename);
950 memset(&tmp, 0, sizeof(tmp));
951 fi = open(filename, O_RDONLY|O_BINARY);
953 if(swf_ReadSWF(fi, &tmp)>=0) {
955 fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666);
957 swf_WriteSWC(fi, &tmp);
959 logf("v2swf_backpatch %s - fix header: success\n", filename);
966 float v2swf_getprogress(v2swf_t*v2swf)
970 logf("v2swf_getprogress()");
971 if(!v2swf || !v2swf->internal) {
974 i = (v2swf_internal_t*)v2swf->internal;
976 p = (float*)videoreader_getinfo(i->video, "position");
981 float f = i->frames/1500.0; /*fake*/
989 void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value)
991 logf("v2swf_setvideoparameter()");
992 videoreader_setparameter(v, name, value);