From: kramm Date: Tue, 6 May 2003 11:39:20 +0000 (+0000) Subject: initial revision. X-Git-Tag: release-0-5-0~243 X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=commitdiff_plain;h=2426d04359ede90a92f33740c7086cafa789ff9f initial revision. --- diff --git a/avi2swf/v2swf.c b/avi2swf/v2swf.c new file mode 100644 index 0000000..5720199 --- /dev/null +++ b/avi2swf/v2swf.c @@ -0,0 +1,993 @@ +/* v2swf.c + part of swftools + + Copyright (C) 2003 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include "v2swf.h" +#include "../lib/rfxswf.h" +#include "ringbuffer.c" + +typedef struct _v2swf_internal_t +{ + TAG*tag; + + int filesize; + int headersize; + int frames; + + int myframes; + + struct writer_t out; + struct writer_t out2; + + ringbuffer_t r; + videoreader_t* video; + + int width; + int height; + + unsigned char* vrbuffer; + unsigned char* buffer; + unsigned char* lastbitmap; + + int id; + int lastid; + + int quality; + int blockdiff; + int keyframe_interval; + int diffmode; + + float framerate; + float fpsratio; + float fpspos; + + int bitrate; + + int finished; + int keyframe; + int showframe; + + float samplepos; + float framesamplepos; + int samplewritepos; + double soundframepos; + int soundstreamhead; + int seek; + + double audio_fix; + int fixheader; + int prescale; + + int scale; + + int domotion; + + int head_done; + + int version; + + VIDEOSTREAM stream; + +} v2swf_internal_t; + +static int verbose = 0; +static int filelog = 0; + +static void logf(char*format, ...) +{ + char buf[1024]; + int l; + va_list arglist; + if(!verbose) + return; + va_start(arglist, format); + vsprintf(buf, format, arglist); + va_end(arglist); + l = strlen(buf); + while(l && buf[l-1]=='\n') { + buf[l-1] = 0; + l--; + } + if(filelog) + { + FILE*fi = fopen("debug.log", "ab+"); + fprintf(fi, "(v2swf) %s\n", buf); + fflush(fi); + fclose(fi); + } + + printf("(v2swf) %s\n", buf); + fflush(stdout); +} + +static void writeShape(v2swf_internal_t*i, int id, int gfxid, int width, int height) +{ + RGBA rgb; + MATRIX m; + SHAPE*shape; + SRECT r; + int lines = 0; + int ls,fs; + swf_ResetTag(i->tag, ST_DEFINESHAPE); + swf_ShapeNew(&shape); + rgb.b = rgb.g = rgb.r = 0xff; + if(lines) + ls = swf_ShapeAddLineStyle(shape,20,&rgb); + swf_GetMatrix(NULL,&m); + m.sx = 20*65536; + m.sy = 20*65536; + + fs = swf_ShapeAddBitmapFillStyle(shape,&m,gfxid,0); + swf_SetU16(i->tag,id); // ID + r.xmin = 0; + r.ymin = 0; + r.xmax = width*20; + r.ymax = height*20; + swf_SetRect(i->tag,&r); + + swf_SetShapeStyles(i->tag,shape); + swf_ShapeCountBits(shape,NULL,NULL); + swf_SetShapeBits(i->tag,shape); + + swf_ShapeSetAll(i->tag,shape,0,0,lines?ls:0,fs,0); + + swf_ShapeSetLine(i->tag,shape,width*20,0); + swf_ShapeSetLine(i->tag,shape,0,height*20); + swf_ShapeSetLine(i->tag,shape,-width*20,0); + swf_ShapeSetLine(i->tag,shape,0,-height*20); + swf_ShapeSetEnd(i->tag); + i->filesize += swf_WriteTag2(&i->out, i->tag); + swf_ShapeFree(shape); +} + +static int getSamples(videoreader_t*video, S16*data, int len, double speedup) +{ + double pos = 0; + double ratio = video->rate * speedup / 44100.0; + int rlen = (int)(len * ratio); + int t; + S16 tmp[576*32]; + int r = /*resampled len */ rlen * + /* s16_le */ 2 * + video->channels; + if(videoreader_getsamples(video, tmp, r) < r) + return 0; + + /* convert to 1 channel */ + for(t=0;tchannels;s++) + a += tmp[t*video->channels+s]; + tmp[t] = a/video->channels; + } + + /* down/up-sample to 44khz */ + for(t=0;taudio_fix; + int num = 0; + int pos = 0; + S16 block1[576*4 * 2]; + + logf("writeAudioForOneFrame()"); + + if(i->video->channels<=0 || i->video->rate<=0) + return; /* no sound in video */ + + blocksize = 576; /* 11khz samples per mp3 block */ + blockspersecond = 11025.0/blocksize; + + /* notice: for framerates greater than about 35, audio starts getting choppy. */ + framespersecond = i->framerate; + + framesperblock = framespersecond / blockspersecond; + samplesperframe = (blocksize * blockspersecond) / framespersecond; /* 11khz-samples per frame */ + samplesperblock = samplesperframe * framesperblock; + + logf("samplesperblock: %f", samplesperblock); + + if(!i->soundstreamhead) { + /* first run - initialize */ + swf_mp3_channels = 1;//i->video->channels; + swf_mp3_bitrate = i->bitrate; + swf_ResetTag(i->tag, ST_SOUNDSTREAMHEAD); + /* samplesperframe overrides the movie framerate: */ + logf("swf_SetSoundStreamHead(): %08x %d", i->tag, samplesperframe); + swf_SetSoundStreamHead(i->tag, samplesperframe); + logf("swf_SetSoundStreamHead() done"); + i->filesize += swf_WriteTag2(&i->out, i->tag); + i->soundstreamhead = 1; + } + + /* for framerates greater than 19.14, every now and then a frame + hasn't a soundstreamblock. Determine whether this is the case. + */ + if(i->frames < i->soundframepos) { + i->samplepos += samplesperframe; + return; + } + + seek = i->seek; + + //while(i->samplewritepos + num * blocksize < i->samplepos + blocksize) { + while(i->samplewritepos < i->samplepos + blocksize) { + i->samplewritepos += blocksize; + i->soundframepos += framesperblock; + num++; + } + if(!num) { + logf("num is zero"); + printf(" num is zero\n"); + fprintf(stderr, " num is zero\n"); + } + logf("num: %d", num); + + /* write num frames, max 1 block */ + for(pos=0;posvideo, block1, 576*4, speedup)) { /* 4 = 44100/11025 */ + i->video->rate = i->video->channels = 0; //end of soundtrack + return; + } + logf("pos: %d- encode mp3", pos); + if(!pos) { + swf_ResetTag(i->tag, ST_SOUNDSTREAMBLOCK); + swf_SetSoundStreamBlock(i->tag, block1, seek, num); + } else { + swf_SetSoundStreamBlock(i->tag, block1, seek, 0); + } + } + i->filesize += swf_WriteTag2(&i->out, i->tag); + + i->seek = i->samplewritepos - (i->samplepos + blocksize); + i->samplepos += samplesperframe; + logf("writeSamplesForOneFrame(): done"); +} + +static void writeShowFrame(v2swf_internal_t* i) +{ + do { + writeAudioForOneFrame(i); + + swf_ResetTag(i->tag, ST_SHOWFRAME); + i->filesize += swf_WriteTag2(&i->out, i->tag); + + i->fpspos -= 1.0; + i->frames ++; + } + while(i->fpspos >= 1.0); + i->showframe = 0; +} + +static void writeShowTags(v2swf_internal_t* i, int shapeid, int bmid, int width, int height) +{ + writeShape(i, shapeid, bmid, width, height); + + swf_ResetTag(i->tag, ST_PLACEOBJECT2); + if(!i->prescale) { + MATRIX m; + swf_GetMatrix(0, &m); + m.sx = m.sy = i->scale; + swf_ObjectPlace(i->tag,shapeid,shapeid,&m,0,0); + } else { + swf_ObjectPlace(i->tag,shapeid,shapeid,0,0,0); + } + i->filesize += swf_WriteTag2(&i->out, i->tag); + + i->showframe = 1; +} + +static int wwrite(struct writer_t*w, void*data, int len) +{ + v2swf_internal_t* i = (v2swf_internal_t*)w->internal; + ringbuffer_put(&i->r, data, len); + return len; +} + +static void wfinish(struct writer_t*w) +{ + v2swf_internal_t* i = (v2swf_internal_t*)w->internal; +} + +static void writehead(v2swf_internal_t*i) +{ + char header[]="FWS\6\0\0\0\4"; + SWF swf; + int ret; + int id; + + header[3] = i->version; + if(i->version >= 6) { //MX + header[0] = 'C'; + + i->out2.write = wwrite; + i->out2.finish = wfinish; + i->out2.internal = i; + i->out2.type = 77; + i->out2.bitpos = 0; + i->out2.mybyte = 0; + i->out2.pos = 0; + writer_init_zlibdeflate(&i->out, &i->out2); + } else { + i->out.write = wwrite; + i->out.finish = wfinish; + i->out.internal = i; + i->out.type = 77; + i->out.bitpos = 0; + i->out.mybyte = 0; + i->out.pos = 0; + i->out2 = i->out; + } + + if(i->prescale) { + i->width = (int)(i->video->width*(i->scale/65536.0)); + i->height = (int)(i->video->height*(i->scale/65536.0)); + } else { + i->width = i->video->width; + i->height = i->video->height; + } + if(!i->width) + i->width = 1; + if(!i->height) + i->height = 1; + i->buffer = (unsigned char*)malloc(i->width*i->height*4); + i->vrbuffer = (unsigned char*)malloc(i->video->width*i->video->height*4); + + memset(&swf, 0, sizeof(SWF)); + swf.fileVersion=i->version; + swf.fileSize = 0; + swf.frameCount = 65535; + swf.movieSize.xmax=i->width*20; + swf.movieSize.ymax=i->height*20; + swf.compressed = 8; /* 8 = compression done by caller (us) */ + swf.frameRate = (int)(i->framerate*0x100);//25*0x100; + + /* write the first 8 bytes to out */ + i->out2.write(&i->out2, header, 8); + + i->filesize += swf_WriteHeader2(&i->out, &swf); + i->headersize = i->filesize; + + i->tag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR); + swf_SetU8(i->tag, 0); //black + swf_SetU8(i->tag, 0); + swf_SetU8(i->tag, 0); + i->filesize += swf_WriteTag2(&i->out, i->tag); +} + +static void finish(v2swf_internal_t*i) +{ + logf("finish(): i->finished=%d\n", i->finished); + if(!i->finished) { + logf("write endtag\n", i->finished); + + swf_ResetTag(i->tag, ST_END); + i->filesize += swf_WriteTag2(&i->out, i->tag); + i->out.finish(&i->out); + + if(i->version>=6) { + swf_VideoStreamClear(&i->stream); + } + if(i->buffer) { + free(i->buffer);i->buffer = 0; + } + if(i->vrbuffer) { + free(i->vrbuffer);i->vrbuffer = 0; + } + if(i->lastbitmap) { + free(i->lastbitmap);i->lastbitmap = 0; + } + + /* FIXME: we shouldn't be doing this. the caller should */ + logf("call videoreader_close(%08x)\n", i->video); + videoreader_close(i->video); + + i->finished = 1; + } + logf("finishing done\n"); +} +static void cleanup(v2swf_internal_t*i) +{ + int t; + for(t=i->lastid;tid;t++) { + if(!(t&1)) { + swf_ResetTag(i->tag, ST_REMOVEOBJECT2); + swf_SetU16(i->tag, t); + i->filesize += swf_WriteTag2(&i->out, i->tag); + } + swf_ResetTag(i->tag, ST_FREECHARACTER); + swf_SetU16(i->tag, t); + i->filesize += swf_WriteTag2(&i->out, i->tag); + } + i->lastid = i->id; +} + +#define DIFFMODE_MAX 1 +#define DIFFMODE_MEAN 2 +#define DIFFMODE_EXACT 3 +#define DIFFMODE_QMEAN 4 + +static int blockdiff_max(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl) +{ + int x,y; + for(y=0;ymaxdiff) + return 1; + + d1+=4; d2+=4; + } + d1 += yadd; d2 += yadd; + } + return 0; +} + +static int blockdiff_mean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl) +{ + int mean = 0; + int x,y; + for(y=0;y maxdiff) + return 1; + return 0; +} + +static int blockdiff_qmean(U8*d1,U8*d2,int yadd, int maxdiff, int xl, int yl) +{ + int mean = 0; + int x,y; + for(y=0;y maxdiff*maxdiff) + return 1; + return 0; +} + +static int blockdiff_exact(U8*d1,U8*d2,int yadd, int xl, int yl) +{ + int x,y; + for(y=0;yhead_done) { + writehead(i); + if(i->version>=6) { + swf_ResetTag(i->tag, ST_DEFINEVIDEOSTREAM); + swf_SetU16(i->tag, 99); + swf_SetVideoStreamDefine(i->tag, &i->stream, 65535, i->width, i->height); + i->filesize += swf_WriteTag2(&i->out, i->tag); + if(i->domotion) { + i->stream.do_motion = 1; + } + } + i->head_done = 1; + } +} + +static void scaleimage(v2swf_internal_t*i) +{ + int x,y; + int xv,yv; + int xm = (i->video->width*65536)/i->width; + int ym = (i->video->height*65536)/i->height; + memset(i->buffer, 255, i->width*i->height*4); + for(y=0,yv=0;yheight;y++,yv+=ym) { + int*src = &((int*)i->vrbuffer)[(yv>>16)*i->video->width]; + int*dest = &((int*)i->buffer)[y*i->width]; + for(x=0,xv=0;xwidth;x++,xv+=xm) { + dest[x] = src[xv>>16]; + } + } + //memcpy(i->buffer, i->vrbuffer, i->width*i->height*4); +} + +static int encodeoneframe(v2swf_internal_t*i) +{ + videoreader_t*video = i->video; + int ret; + + checkInit(i); + + if(videoreader_eof(i->video) || !videoreader_getimage(i->video, i->vrbuffer)) + { + logf("videoreader returned eof\n"); + finish(i); + return 0; + } + + i->fpspos += i->fpsratio; + + /* skip frames */ + if(i->fpspos<1.0) { + return 0; + } + + logf("encoding image for frame %d\n", i->frames); + + if(i->showframe) + writeShowFrame(i); + + logf("scaling\n"); + + scaleimage(i); + + logf("version is %d\n", i->version); + + if(i->version <= 4) { + + int bmid = i->id++; + int shapeid = i->id++; + int width2 = i->width * 4; + + if(i->id>=4) { + swf_ResetTag(i->tag, ST_REMOVEOBJECT2); + swf_SetU16(i->tag, i->id-3); + i->filesize += swf_WriteTag2(&i->out, i->tag); + swf_ResetTag(i->tag, ST_FREECHARACTER); + swf_SetU16(i->tag, i->id-4); + i->filesize += swf_WriteTag2(&i->out, i->tag); + } + + swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2); + swf_SetU16(i->tag, bmid); + swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality); + i->filesize += swf_WriteTag2(&i->out, i->tag); + + writeShowTags(i, shapeid, bmid, i->width, i->height); + + } else if(i->version == 5) { + int width2 = i->width * 4; + int width8 = (i->width+7)/8; + int height8 = (i->height+7)/8; + + /* the idea is here to only update those jpeg 8x8 blocks + which actually have changed. This means that we have to keep + the bitmap from the last frame for the comparison. */ + + (i->keyframe)--; + if(!i->lastbitmap || !i->keyframe) { + int t, bmid,shapeid; + cleanup(i); + + if(!i->lastbitmap) { + logf("Creating bitmap buffer for %dx%d (%dx%d), (%dx%d)\n", i->width, i->height, width2, i->height, width8, height8); + i->lastbitmap = (U8*)malloc(width2*i->height); + } + memcpy(i->lastbitmap, i->buffer, width2*i->height); + + i->keyframe = i->keyframe_interval; + + bmid = i->id++; + shapeid = i->id++; + width2 = i->width * 4; + swf_ResetTag(i->tag, ST_DEFINEBITSJPEG2); + swf_SetU16(i->tag, bmid); + swf_SetJPEGBits2(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality); + i->filesize += swf_WriteTag2(&i->out, i->tag); + + writeShowTags(i, shapeid, bmid, i->width, i->height); + return 1; + } else { + /* The following looks so ugly because it's somewhat optimized. + What it does is walk through all the 8x8 blocks, find those + which have changed too much and set all others to (R,G,B,A)=(0,0,0,0). + It also set's alpha to 255 in those who haven't changed, and + copies them to lastbitmap. + */ + + int x8, y8; + //int maxdiff = ((100 - i->quality)*256)/100; + int maxdiff = i->blockdiff*3; + for(y8=0;y8 i->width) + xl = i->width - x8*8; + if(y8*8+yl > i->height) + yl = i->height - y8*8; + d1 = &i->buffer[width2*y8*8+x8*8*4]; + d1b = d1; + d2 = &i->lastbitmap[width2*y8*8+x8*8*4]; + d2b = d2; + yadd = width2 - (xl*4); + + if(i->diffmode == DIFFMODE_MAX) { + if(blockdiff_max(d1, d2, yadd, maxdiff, xl, yl)) + goto differ; + } else if(i->diffmode == DIFFMODE_MEAN) { + if(blockdiff_mean(d1, d2, yadd, maxdiff, xl, yl)) + goto differ; + } else if(i->diffmode == DIFFMODE_EXACT) { + if(blockdiff_exact(d1, d2, yadd, xl, yl)) + goto differ; + } else if(i->diffmode == DIFFMODE_QMEAN) { + if(blockdiff_qmean(d1, d2, yadd, maxdiff, xl, yl)) + goto differ; + } + + for(y=0;yid++; + int shapeid = i->id++; + + swf_ResetTag(i->tag, ST_DEFINEBITSJPEG3); + swf_SetU16(i->tag, bmid); + swf_SetJPEGBits3(i->tag, i->width, i->height, (RGBA*)i->buffer, i->quality); + i->filesize += swf_WriteTag2(&i->out, i->tag); + + writeShowTags(i, shapeid, bmid, i->width, i->height); + } + } else { + int quant = 1+(30-(30*i->quality)/100); + SWFPLACEOBJECT obj; + + swf_GetPlaceObject(0, &obj); + if(!i->prescale) { + obj.matrix.sx = obj.matrix.sy = i->scale; + } + + if(i->stream.frame==0) { + obj.depth = 1; + obj.id = 99; + } else { + obj.move = 1; + obj.depth = 1; + obj.ratio = i->stream.frame; + } + + swf_ResetTag(i->tag, ST_VIDEOFRAME); + swf_SetU16(i->tag, 99); + if(!(--i->keyframe)) { + logf("setting video I-frame, ratio=%d\n", i->stream.frame); + swf_SetVideoStreamIFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant); + i->keyframe = i->keyframe_interval; + } else { + logf("setting video P-frame, ratio=%d\n", i->stream.frame); + swf_SetVideoStreamPFrame(i->tag, &i->stream, (RGBA*)i->buffer, quant); + } + i->filesize += swf_WriteTag2(&i->out, i->tag); + + swf_ResetTag(i->tag, ST_PLACEOBJECT2); + swf_SetPlaceObject(i->tag,&obj); + i->filesize += swf_WriteTag2(&i->out, i->tag); + i->showframe = 1; + } + return 1; +} + +int v2swf_init(v2swf_t*v2swf, videoreader_t * video) +{ + int ret = 0; + int t=0; + v2swf_internal_t* i; + logf("v2swf_init()\n"); + memset(v2swf, 0, sizeof(v2swf_t)); + i = (v2swf_internal_t*)malloc(sizeof(v2swf_internal_t)); + memset(i, 0, sizeof(v2swf_internal_t)); + v2swf->internal = i; + + ringbuffer_init(&i->r); + + logf("video: %dx%d, fps %f\n", video->width, video->height, video->fps); + + i->video = video; + i->blockdiff = 64; + i->keyframe_interval = 8; + i->quality = 20; + i->scale = 65536; + i->prescale = 0; + i->head_done = 0; + i->diffmode = DIFFMODE_QMEAN; + i->audio_fix = 1.0; + i->fixheader = 0; + i->framerate = video->fps; + i->fpsratio = 1.00000000; + i->fpspos = 0.0; + i->bitrate = 32; + i->version = 6; + i->buffer = 0; + i->lastbitmap = 0; + i->filesize = 8; + i->frames = 0; + i->id = 1; + i->lastid = 1; + i->keyframe = 1; + i->showframe = 0; + + memset(&i->out, 0, sizeof(struct writer_t)); + memset(&i->out2, 0, sizeof(struct writer_t)); + + return 0; +} +int v2swf_read(v2swf_t*v2swf, void*buffer, int len) +{ + v2swf_internal_t* i; + int l; + logf("v2swf_read(%d)\n", len); + i = (v2swf_internal_t*)v2swf->internal; + + while(!i->finished && i->r.available < len) { + if(!encodeoneframe(i)) { + break; + } + } + logf("v2swf_read() done: %d bytes available in ringbuffer\n", i->r.available); + l = ringbuffer_read(&i->r, buffer, len); + + return l; +} +void v2swf_close(v2swf_t*v2swf) +{ + v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal; + logf("close(): i->finished=%d\n", i->finished); + + /* needed only if aborting: */ + finish(i); + + logf("freeing memory\n"); + free(v2swf->internal); + memset(v2swf, 0, sizeof(v2swf_t)); + logf("close() done\n"); +} + +static int mp3_bitrates[] = +{ 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}; + +void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value) +{ + v2swf_internal_t* i; + + logf("set parameters %s to %s\n", name, value); + + if(!strcmp(name, "verbose")) { + verbose = 1; + logf("set parameters %s to %s\n", name, value); + return; + } + + if(!v2swf || !v2swf->internal) { + printf("error- couldn't set parameter %s: not initialized yet\n", name);fflush(stdout); + return; + } + i = (v2swf_internal_t*)v2swf->internal; + + if(!strcmp(name, "flash_version")) { + i->version = atoi(value); + } else if(!strcmp(name, "audiosync")) { + i->audio_fix = (int)(atof(value)); + } else if(!strcmp(name, "scale")) { + i->scale = (int)(atof(value)*65536); + } else if(!strcmp(name, "scale65536")) { + i->scale = atoi(value); + } else if(!strcmp(name, "quality")) { + i->quality = atoi(value); + } else if(!strcmp(name, "motioncompensation")) { + i->domotion = atoi(value); + } else if(!strcmp(name, "prescale")) { + i->prescale = atoi(value); + } else if(!strcmp(name, "blockdiff")) { + i->blockdiff = atoi(value); + } else if(!strcmp(name, "fixheader")) { + i->fixheader = atoi(value); + } else if(!strcmp(name, "framerate")) { + i->framerate = atof(value); + i->fpsratio = i->framerate / i->video->fps; + } + else if(!strcmp(name, "mp3_bitrate")) { + int t=0,o; + i->bitrate = o = atoi(value); + if(i->bitrate>160) + i->bitrate = 160; + while(mp3_bitrates[t]) { + if(i->bitrate <= mp3_bitrates[t]) { + i->bitrate = mp3_bitrates[t]; + break; + } + t++; + } + logf("bitrate %d requested, setting to %d", o, i->bitrate); + } + else if(!strcmp(name, "blockdiff_mode")) { + if(!strcmp(value, "max")) i->diffmode = DIFFMODE_MAX; + else if(!strcmp(value, "mean")) i->diffmode = DIFFMODE_MEAN; + else if(!strcmp(value, "qmean")) i->diffmode = DIFFMODE_QMEAN; + else if(!strcmp(value, "exact")) i->diffmode = DIFFMODE_EXACT; + else { + printf("diffmode %s not recognized\n", value); + printf("valid diffmodes are: %s\n", "max, mean, qmean, exact"); + } + } + else if(!strcmp(name, "keyframe_interval") + || !strcmp(name, "keyframe")) { + int k = atoi(value);if(k<=0) k=1; + i->keyframe_interval = k; + } + else { + printf("Setting encoder.%s not recognized!\n", name);fflush(stdout); + return; + } +} +void v2swf_backpatch(v2swf_t*v2swf, char*filename) +{ + FILE* fi; + unsigned char f; + v2swf_internal_t* i = (v2swf_internal_t*)v2swf->internal; + logf("v2swf_backpatch %s\n", filename); + if(!i) { + printf("call backpatch before close\n");fflush(stdout); + } + fi = fopen(filename, "rb+"); + if(!fi) { + printf("can't open %s\n", filename); + exit(1); + } + fseek(fi, 4, SEEK_SET); + f = i->filesize ;fwrite(&f,1,1,fi); + f = i->filesize >> 8 ;fwrite(&f,1,1,fi); + f = i->filesize >> 16;fwrite(&f,1,1,fi); + f = i->filesize >> 24;fwrite(&f,1,1,fi); + if(i->version<6) { + /* no compression- we can backpatch the frames too */ + fseek(fi, i->headersize-2, SEEK_SET); + f = i->frames ;fwrite(&f,1,1,fi); + f = i->frames >> 8 ;fwrite(&f,1,1,fi); + } + fclose(fi); + if(i->fixheader) { + SWF tmp; + int fi; + logf("v2swf_backpatch %s - fix header\n", filename); + memset(&tmp, 0, sizeof(tmp)); + fi = open(filename, O_RDONLY|O_BINARY); + if(fi>=0) { + if(swf_ReadSWF(fi, &tmp)>=0) { + close(fi); + fi = open(filename, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666); + if(fi>=0) { + swf_WriteSWC(fi, &tmp); + close(fi); + logf("v2swf_backpatch %s - fix header: success\n", filename); + } + } + } + } +} + +float v2swf_getprogress(v2swf_t*v2swf) +{ + float* p; + v2swf_internal_t* i; + logf("v2swf_getprogress()"); + if(!v2swf || !v2swf->internal) { + return 0.0; + } + i = (v2swf_internal_t*)v2swf->internal; + + p = (float*)videoreader_getinfo(i->video, "position"); + + if(p) { + return *p; + } else { + float f = i->frames/1500.0; /*fake*/ + if(f>1.0) + return 1.0; + else + return f; + } +} + +void v2swf_setvideoparameter(videoreader_t*v, char*name, char*value) +{ + logf("v2swf_setvideoparameter()"); + videoreader_setparameter(v, name, value); +} diff --git a/avi2swf/v2swf.h b/avi2swf/v2swf.h new file mode 100644 index 0000000..94a9526 --- /dev/null +++ b/avi2swf/v2swf.h @@ -0,0 +1,73 @@ +/* v2swf.c + header file for v2swf.h - part of SWFTools + + Copyright (C) 2003 Matthias Kramm + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef __video_h__ +#define __video_h__ + +#ifdef __cplusplus +extern "C" { +#else +typedef unsigned char bool; +#endif + +typedef struct _videoreader_t +{ + void*internal; + + /* video */ + int width; + int height; + double fps; + + /* audio */ + int channels; + int rate; + + int (*getsamples) (struct _videoreader_t*, void*buffer, int num); + /* buffer must be big enough to hold width*height*4 bytes: */ + int (*getimage) (struct _videoreader_t*, void*buffer); + bool (*eof) (struct _videoreader_t*); + /* multi purpose functions */ + void (*setparameter) (struct _videoreader_t*, char*name, char*value); + void* (*getinfo) (struct _videoreader_t*, char*name); + void (*close) (struct _videoreader_t*); +} videoreader_t; + +#define videoreader_getsamples(v, buffer, num) ((v)->getsamples((v),(buffer),(num))) +#define videoreader_getimage(v, buffer) ((v)->getimage((v),(buffer))) +#define videoreader_eof(v) ((v)->eof(v)) +#define videoreader_setparameter(v,name,value) ((v)->setparameter((v),(name),(value))) +#define videoreader_getinfo(v,name) ((v)->getinfo((v),(name))) +#define videoreader_close(v) ((v)->close(v)) + +typedef struct _v2swf_t +{ + void*internal; +} v2swf_t; + +int v2swf_init(v2swf_t*v2swf, videoreader_t * video); +int v2swf_read(v2swf_t*v2swf, void*buffer, int len); +void v2swf_setparameter(v2swf_t*v2swf, char*name, char*value); +void v2swf_close(v2swf_t*v2swf); +void v2swf_backpatch(v2swf_t*v2swf, char*filename); + +#ifdef __cplusplus +} +#endif + +#endif