fixed drawlink() ruby callback
[swftools.git] / avi2swf / videoreader_vfw.cc
index d605cf7..ca8a6b7 100644 (file)
@@ -37,6 +37,9 @@ typedef struct _videoreader_vfw_internal {
     BITMAPINFOHEADER bitmap;
     WAVEFORMATEX waveformat;
 
+    int audio_eof;
+    int video_eof;
+
     int video_pos;
     int video_end;
 
@@ -49,19 +52,15 @@ typedef struct _videoreader_vfw_internal {
     int samplerate;
     int channels;
 
+    int flip;
 } videoreader_vfw_internal_t;
 
 static int avifile_initialized = 0;
+static int verbose;
 
-#define _TRACE_ {printf("%s: %d (%s)\n",__FILE__,__LINE__,__func__);fflush(stdout);}
-
-bool videoreader_vfw_eof(videoreader_t* vr)
-{
-    videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
-    return (i->video_pos >= i->video_end);
-}
+#define _TRACE_ {printf("vfw: %s: %d (%s)\n",__FILE__,__LINE__,__func__);fflush(stdout);}
 
-static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width, const int dest_height)
+static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width, const int dest_height, int flip)
 {
     UCHAR*data = (UCHAR*)(bi+1); // actual bitmap data starts after the header
 
@@ -74,8 +73,8 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
     
     ULONG*dest = (ULONG*)buffer;
 
-    int width = bi->biWidth;
-    int height = bi->biHeight;
+    int width = abs(bi->biWidth);
+    int height = abs(bi->biHeight);
     if(dest_width != width || dest_height != height) {
        /* TODO: size conversion */
        fprintf(stderr, "size mismatch: %dx%d != %dx%d\n", width, height, dest_width, dest_height);
@@ -87,10 +86,19 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
     int bytesperpixel = ((bi->biWidth*bi->biBitCount)+7)&~7;
     int linex = ((bytesperpixel/8)+3)&~3;
     memset(dest, 255, dest_width*dest_height*4);//pre-fill alpha channel
+
+    const int starty = flip? 0 : dest_height-1;
+    const int endy   = flip? dest_height : -1;
+    const int yinc   = flip? 1 : -1;
+
+    if(verbose) {
+       printf("vfw: Convering scanlines %d to %d from bpp %d, %d stepping, flip=%d\n", starty, endy, bi->biBitCount, yinc, flip);
+    }
+
     if(bi->biBitCount==1) {
-       int y;
        UCHAR*img = data;
-       for(y=0;y<dest_height;y++) {
+       int y;
+       for(y=starty;y!=endy;y+=yinc) {
            UCHAR*line = &img[linex*y];
            int x;
            for(x=0;x<dest_width;x++) {
@@ -98,10 +106,10 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
            }
        }
     } else if(bi->biBitCount==4) {
-       int y;
        UCHAR*img = &data[bi->biClrUsed*4];
        UCHAR*pal = data;
-       for(y=0;y<dest_height;y++) {
+       int y;
+       for(y=starty;y!=endy;y+=yinc) {
            UCHAR*line = &img[linex*y];
            int x;
            for(x=0;x<dest_width/2;x++) {
@@ -111,10 +119,10 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
            }
        }
     } else if(bi->biBitCount==8) {
-       int y;
        UCHAR*img = &data[bi->biClrUsed*4];
        UCHAR*pal = data;
-       for(y=0;y<dest_height;y++) {
+       int y;
+       for(y=starty;y!=endy;y+=yinc) {
            UCHAR*line = &img[linex*y];
            int x;
            for(x=0;x<dest_width;x++) {
@@ -122,10 +130,22 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
                line++;
            }
        }
+    } else if(bi->biBitCount==16) {
+       UCHAR*img = data;
+       int y;
+       for(y=starty;y!=endy;y+=yinc) {
+           UCHAR*line = &img[linex*y];
+           int x;
+           for(x=0;x<dest_width;x++) {
+               USHORT c = line[0]|line[1]<<8;
+               *dest++ = 255|(c&0x1f)<<(24+3)|(c>>5&0x1f)<<(16+3)|(c>>10&0x1f)<<(8+3);
+               line+=2;
+           }
+       }
     } else if(bi->biBitCount==24) {
        UCHAR*img = data;
        int y;
-       for(y=0;y<dest_height;y++) {
+       for(y=starty;y!=endy;y+=yinc) {
            UCHAR*line = &img[linex*y];
            int x;
            for(x=0;x<dest_width;x++) {
@@ -136,7 +156,7 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
     } else if(bi->biBitCount==32) {
        UCHAR*img = data;
        int y;
-       for(y=0;y<dest_height;y++) {
+       for(y=starty;y!=endy;y+=yinc) {
            UCHAR*line = &img[linex*y];
            int x;
            for(x=0;x<dest_width;x++) {
@@ -151,11 +171,14 @@ static int bitmap_to_rgba(BITMAPINFOHEADER*bi, void*buffer, const int dest_width
     return 1;
 }
 
-int videoreader_vfw_getimage(videoreader_t* vr, void*buffer)
+static int videoreader_vfw_getimage(videoreader_t* vr, void*buffer)
 {
     videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
 
-    if(videoreader_vfw_eof(vr))
+    if (i->video_pos >= i->video_end)
+       i->video_eof = 1;
+
+    if(i->video_eof)
        return 0;
 
     LPBITMAPINFOHEADER bi;
@@ -169,7 +192,7 @@ int videoreader_vfw_getimage(videoreader_t* vr, void*buffer)
        return 0;
     }
     
-    if(!bitmap_to_rgba(bi, buffer, i->width, i->height)) {
+    if(!bitmap_to_rgba(bi, buffer, i->width, i->height, i->flip)) {
        fprintf(stderr, "couldn't convert bitmap to RGBA.\n");
        return 0;
     }
@@ -185,9 +208,12 @@ static int readAudioBlock(videoreader_vfw_internal_t* i, void*buf, int len)
     return bytes;
 }
 
-int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
+static int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
 {
     videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
+
+    if(i->audio_eof)
+       return 0;
    
     switch(i->waveformat.wBitsPerSample) {
        case 1: {
@@ -196,6 +222,7 @@ int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
            do {
                ((SHORT*)buf)[t] = ((((BYTE*)buf)[t>>3])>>(t&7))<<15;
            } while(--t>=0);
+           if(!len) i->audio_eof = 1;
            return len*8;
        }
        case 8: {
@@ -204,10 +231,13 @@ int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
            do {
                ((SHORT*)buf)[t] = (((BYTE*)buf)[t]<<8)^0x8000;
            } while(--t>=0);
+           if(!len) i->audio_eof = 1;
            return len*2;
        }
        case 16: {
-           return readAudioBlock(i, buf, num);
+           int len = readAudioBlock(i, buf, num);
+           if(!len) i->audio_eof = 1;
+           return len;
        }
        default: {
            return 0;
@@ -215,7 +245,7 @@ int videoreader_vfw_getsamples(videoreader_t* vr, void*buf, int num)
     }
 }
 
-void videoreader_vfw_close(videoreader_t* vr)
+static void videoreader_vfw_close(videoreader_t* vr)
 {
     videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
 
@@ -233,7 +263,15 @@ void videoreader_vfw_close(videoreader_t* vr)
     free(vr->internal); vr->internal = 0;
 }
 
-void videoreader_vfw_setparameter(videoreader_t* vr, char*name, char*value) {}
+static void videoreader_vfw_setparameter(videoreader_t*vr, char*name, char*value)
+{
+    videoreader_vfw_internal_t* i = (videoreader_vfw_internal_t*)vr->internal;
+    if(!strcmp(name, "flip")) {
+       i->flip = atoi(value);
+    } else if(!strcmp(name, "verbose")) {
+       verbose = atoi(value);
+    }
+}
 
 int videoreader_vfw_open(videoreader_t* vr, char* filename)
 {
@@ -247,7 +285,6 @@ int videoreader_vfw_open(videoreader_t* vr, char* filename)
     memset(i, 0, sizeof(videoreader_vfw_internal_t));
 
     vr->internal = i;
-    vr->eof = videoreader_vfw_eof;
     vr->getimage = videoreader_vfw_getimage;
     vr->getsamples = videoreader_vfw_getsamples;
     vr->close = videoreader_vfw_close;
@@ -266,6 +303,10 @@ int videoreader_vfw_open(videoreader_t* vr, char* filename)
     /* calculate framerate */
     i->fps = (double)info.dwRate/(double)info.dwScale;
 
+    if(verbose) {
+       printf("vfw: file %s has %f fps, and %d streams\n", i->fps, info.dwStreams);
+    }
+
     unsigned int t=0;
     while(t<info.dwStreams) {
        PAVISTREAM stream;
@@ -285,11 +326,11 @@ int videoreader_vfw_open(videoreader_t* vr, char* filename)
            if(1) {
                i->bitmap = bitmap;
                i->vs = stream;
-               i->width = bitmap.biWidth;
-               i->height = bitmap.biHeight;
+               i->width = abs(bitmap.biWidth);
+               i->height = abs(bitmap.biHeight);
            } else {
                fprintf(stderr, "Ignoring video stream: %dx%d compression=%d planes=%d\n", 
-                       bitmap.biWidth, bitmap.biHeight,
+                       abs(bitmap.biWidth), abs(bitmap.biHeight),
                        bitmap.biCompression,bitmap.biPlanes);
            }
         }
@@ -316,6 +357,9 @@ int videoreader_vfw_open(videoreader_t* vr, char* filename)
     }
 
     if(i->vs) {
+       if(verbose) {
+           printf("vfw: video stream: %dx%d, %.2f\n", i->width, i->height, i->fps);
+       }
        vr->width = i->width;
        vr->height = i->height;
        vr->fps = i->fps;
@@ -323,6 +367,9 @@ int videoreader_vfw_open(videoreader_t* vr, char* filename)
        fprintf(stderr, "AVIReader: Warning: No video stream\n");
     }
     if(i->as) {
+       if(verbose) {
+           printf("vfw: audio stream: %d channels, %d samples/sec", i->channels, i->samplerate);
+       }
        vr->channels = i->channels;
        vr->samplerate = i->samplerate;
     } else {