]> git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
Added JAM video decoder plugin, used by Blood Omnicide
authorvortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 19 Mar 2011 20:47:35 +0000 (20:47 +0000)
committervortex <vortex@d7cf8633-e32d-0410-b094-e92efae38249>
Sat, 19 Mar 2011 20:47:35 +0000 (20:47 +0000)
git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10938 d7cf8633-e32d-0410-b094-e92efae38249

cl_video.c
cl_video_jamdecode.c [new file with mode: 0644]

index 2db4756e84f94880baaf98eb6b7e17a7dc051de4..28be575a0a5d587888d9789e6e6ee4726a8c3186 100644 (file)
@@ -5,9 +5,9 @@
 #include "dpvsimpledecode.h"
 
 // VorteX: JAM video module used by Blood Omnicide
-//#define USEJAM
+#define USEJAM
 #ifdef USEJAM
-  #include "jamdecode.c"
+  #include "cl_video_jamdecode.c"
 #endif
 
 // cvars
diff --git a/cl_video_jamdecode.c b/cl_video_jamdecode.c
new file mode 100644 (file)
index 0000000..eb6f922
--- /dev/null
@@ -0,0 +1,355 @@
+// JAM format decoder, used by Blood Omnicide\r
+\r
+typedef struct jamdecodestream_s\r
+{\r
+       int error;\r
+\r
+       qfile_t *file;\r
+       double info_framerate;\r
+       unsigned int info_frames;\r
+       unsigned int info_imagewidth;\r
+       unsigned int info_imageheight;\r
+       int doubleres;\r
+       float colorscale;\r
+       unsigned char colorsub;\r
+       float stipple;\r
+\r
+       // info used durign decoding\r
+       unsigned char *videopixels;\r
+       unsigned char *compressed;\r
+       unsigned char *framedata;\r
+       unsigned char *prevframedata;\r
+       unsigned char colormap[768];\r
+       unsigned int framesize;\r
+       unsigned int framenum;\r
+\r
+       // channel the sound file is being played on\r
+       int sndchan;\r
+}\r
+jamdecodestream_t;\r
+\r
+#define JAMDECODEERROR_NONE                0\r
+#define JAMDECODEERROR_EOF                 1\r
+#define JAMDECODEERROR_READERROR           2\r
+#define JAMDECODEERROR_BAD_FRAME_HEADER    3\r
+#define JAMDECODEERROR_BAD_OUTPUT_SIZE     4\r
+#define JAMDECODEERROR_BAD_COLORMAP        5\r
+\r
+// opens a stream\r
+void jam_close(void *stream);\r
+unsigned int jam_getwidth(void *stream);\r
+unsigned int jam_getheight(void *stream);\r
+double jam_getframerate(void *stream);\r
+int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow);\r
+void *jam_open(clvideo_t *video, char *filename, const char **errorstring)\r
+{\r
+       unsigned char jamHead[16];\r
+       char *wavename;\r
+       jamdecodestream_t *s;\r
+       qfile_t *file;\r
+\r
+       s = (jamdecodestream_t *)Z_Malloc(sizeof(jamdecodestream_t));\r
+       if (s != NULL)\r
+       {\r
+               if ((file = FS_OpenVirtualFile(filename, false)))\r
+               {\r
+                       s->file = file;\r
+                       if (FS_Read(s->file, &jamHead, 16))\r
+                       {\r
+                               if (!memcmp(jamHead, "JAM", 3))\r
+                               {\r
+                                       s->info_imagewidth = LittleLong(*(jamHead + 4));\r
+                                       s->info_imageheight = LittleLong(*(jamHead + 8));\r
+                                       s->info_frames = LittleLong(*(jamHead + 12));\r
+                                       s->info_framerate = 15;\r
+                                       s->doubleres = 0;\r
+                                       s->colorscale = 0.70;\r
+                                       s->colorsub = 8;\r
+                                       s->stipple = 0.4;\r
+                                       s->framesize = s->info_imagewidth * s->info_imageheight;\r
+                                       if (s->framesize > 0)\r
+                                       {\r
+                                               s->compressed = (unsigned char *)Z_Malloc(s->framesize);\r
+                                               s->framedata = (unsigned char *)Z_Malloc(s->framesize * 2);\r
+                                               s->prevframedata = (unsigned char *)Z_Malloc(s->framesize * 2);\r
+                                               s->videopixels = (unsigned char *)Z_Malloc(s->framesize * 4); // bgra, doubleres\r
+                                               if (s->compressed != NULL && s->framedata != NULL && s->prevframedata != NULL && s->videopixels != NULL)\r
+                                               {\r
+                                                       size_t namelen;\r
+\r
+                                                       namelen = strlen(filename) + 10;\r
+                                                       wavename = (char *)Z_Malloc(namelen);\r
+                                                       if (wavename)\r
+                                                       {\r
+                                                               sfx_t* sfx;\r
+\r
+                                                               FS_StripExtension(filename, wavename, namelen);\r
+                                                               strlcat(wavename, ".wav", namelen);\r
+                                                               sfx = S_PrecacheSound(wavename, false, false);\r
+                                                               if (sfx != NULL)\r
+                                                                       s->sndchan = S_StartSound (-1, 0, sfx, vec3_origin, 1.0f, 0);\r
+                                                               else\r
+                                                                       s->sndchan = -1;\r
+                                                               Z_Free(wavename);\r
+                                                       }\r
+                                                       // all is well...\r
+                                                       // set the module functions\r
+                                                       s->framenum = 0;\r
+                                                       video->close = jam_close;\r
+                                                       video->getwidth = jam_getwidth;\r
+                                                       video->getheight = jam_getheight;\r
+                                                       video->getframerate = jam_getframerate;\r
+                                                       video->decodeframe = jam_video;\r
+                                                       return s;\r
+                                               }\r
+                                               else if (errorstring != NULL)\r
+                                                       *errorstring = "unable to allocate memory for stream info structure";\r
+                                               if (s->compressed != NULL)\r
+                                                       Z_Free(s->compressed);\r
+                                               if (s->framedata != NULL)\r
+                                                       Z_Free(s->framedata);\r
+                                               if (s->prevframedata != NULL)\r
+                                                       Z_Free(s->prevframedata);\r
+                                               if (s->videopixels != NULL)\r
+                                                       Z_Free(s->videopixels);\r
+                                       }\r
+                                       else if (errorstring != NULL)\r
+                                               *errorstring = "bad framesize";\r
+                               }\r
+                               else if (errorstring != NULL)\r
+                                       *errorstring = "not JAM videofile";\r
+                       }\r
+                       else if (errorstring != NULL)\r
+                               *errorstring = "unexpected EOF";\r
+                       FS_Close(file);\r
+               }\r
+               else if (errorstring != NULL)\r
+                       *errorstring = "unable to open videofile";\r
+               Z_Free(s);\r
+       }\r
+       else if (errorstring != NULL)\r
+               *errorstring = "unable to allocate memory for stream info structure";\r
+       return NULL;\r
+}\r
+\r
+// closes a stream\r
+void jam_close(void *stream)\r
+{\r
+       jamdecodestream_t *s = (jamdecodestream_t *)stream;\r
+       if (s == NULL)\r
+               return;\r
+       Z_Free(s->compressed);\r
+       Z_Free(s->framedata);\r
+       Z_Free(s->prevframedata);\r
+       Z_Free(s->videopixels);\r
+       if (s->sndchan != -1)\r
+               S_StopChannel(s->sndchan, true);\r
+       if (s->file)\r
+               FS_Close(s->file);\r
+       Z_Free(s);\r
+}\r
+\r
+// returns the width of the image data\r
+unsigned int jam_getwidth(void *stream)\r
+{\r
+       jamdecodestream_t *s = (jamdecodestream_t *)stream;\r
+       if (s->doubleres)\r
+               return s->info_imagewidth * 2;\r
+       return s->info_imagewidth;\r
+}\r
+\r
+// returns the height of the image data\r
+unsigned int jam_getheight(void *stream)\r
+{\r
+       jamdecodestream_t *s = (jamdecodestream_t *)stream;\r
+       if (s->doubleres)\r
+               return s->info_imageheight * 2;\r
+       return s->info_imageheight;\r
+}\r
+\r
+// returns the framerate of the stream\r
+double jam_getframerate(void *stream)\r
+{\r
+       jamdecodestream_t *s = (jamdecodestream_t *)stream;\r
+       return s->info_framerate;\r
+}\r
+\r
+\r
+// decode JAM frame\r
+void jam_decodeframe(unsigned char *inbuf, unsigned char *outbuf, unsigned char *prevbuf, int outsize, int frametype)\r
+{\r
+       unsigned char *srcptr, *destptr, *prevptr;\r
+       int bytesleft;\r
+       unsigned int mark;\r
+       unsigned short int bits;\r
+       int rep;\r
+       int backoffs;\r
+       unsigned char *back;\r
+       int i;\r
+\r
+       srcptr = inbuf;\r
+       destptr = outbuf;\r
+       prevptr = prevbuf;\r
+       bytesleft = outsize;\r
+\r
+       if (frametype == 2)\r
+       {\r
+               memcpy(outbuf, inbuf, outsize);\r
+               return;\r
+       }\r
+       while(bytesleft > 0)\r
+       {\r
+               memcpy(&mark, srcptr, 4);\r
+               srcptr += 4;\r
+               for(i=0; i<32 && bytesleft > 0; i++,mark=mark>>1)\r
+               {\r
+                       if(mark & 1)\r
+                       {\r
+                               *destptr = *srcptr;\r
+                               destptr ++;\r
+                               prevptr ++;\r
+                               srcptr ++;\r
+                               bytesleft --;\r
+                       }\r
+                       else\r
+                       {\r
+                               bits = srcptr[0] + 256*srcptr[1];\r
+                               rep = (bits >> 11) + 3;\r
+                               if(frametype == 1)\r
+                               {\r
+                                       backoffs = 0x821 - (bits & 0x7ff);\r
+                                       back = destptr - backoffs;\r
+                               }\r
+                               else\r
+                               {\r
+                                       backoffs = 0x400 - (bits & 0x7ff);\r
+                                       back = prevptr - backoffs;\r
+                               }\r
+                               srcptr += 2;\r
+                               memcpy(destptr, back, rep);\r
+                               destptr += rep;\r
+                               prevptr += rep;\r
+                               bytesleft -= rep;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+// decodes a video frame to the supplied output pixels\r
+int jam_video(void *stream, void *imagedata, unsigned int Rmask, unsigned int Gmask, unsigned int Bmask, unsigned int bytesperpixel, int imagebytesperrow)\r
+{\r
+       unsigned char frameHead[16], *b;\r
+       unsigned int compsize, outsize, i, j;\r
+       jamdecodestream_t *s = (jamdecodestream_t *)stream;\r
+\r
+       s->error = DPVSIMPLEDECODEERROR_NONE;\r
+       if (s->framenum < s->info_frames)\r
+       {\r
+readframe:\r
+               if (FS_Read(s->file, &frameHead, 16))\r
+               {\r
+                       compsize = LittleLong(*(frameHead + 8)) - 16;\r
+                       outsize = LittleLong(*(frameHead + 12));\r
+                       if (compsize < 0 || compsize > s->framesize || outsize < 0 || outsize > s->framesize)\r
+                               s->error = JAMDECODEERROR_BAD_FRAME_HEADER;\r
+                       else if (FS_Read(s->file, s->compressed, compsize))\r
+                       {\r
+                               // palette goes interleaved with special flag\r
+                               if (frameHead[0] == 2)\r
+                               {\r
+                                       if (compsize == 768)\r
+                                       {\r
+                                               memcpy(s->colormap, s->compressed, 768);\r
+                                               for(i = 0; i < 768; i++)\r
+                                                       s->colormap[i] = (unsigned char)(bound(0, (s->colormap[i] * s->colorscale) - s->colorsub, 255));\r
+                                               goto readframe;\r
+                                       }\r
+                                       //else\r
+                                       //      s->error = JAMDECODEERROR_BAD_COLORMAP;\r
+                               }\r
+                               else\r
+                               {\r
+                                       // decode frame\r
+                                       // shift buffers to provide current and previous one, decode\r
+                                       b = s->prevframedata;\r
+                                       s->prevframedata = s->framedata;\r
+                                       s->framedata = b;\r
+                                       jam_decodeframe(s->compressed, s->framedata, s->prevframedata, outsize, frameHead[4]);\r
+                                       // make 32bit imagepixels from 8bit palettized frame\r
+                                       if (s->doubleres)\r
+                                               b = s->videopixels;\r
+                                       else\r
+                                               b = (unsigned char *)imagedata;\r
+                                       for(i = 0; i < s->framesize; i++)\r
+                                       {\r
+                                               // bgra\r
+                                               *b++ = s->colormap[s->framedata[i]*3 + 2];\r
+                                               *b++ = s->colormap[s->framedata[i]*3 + 1];\r
+                                               *b++ = s->colormap[s->framedata[i]*3];\r
+                                               *b++ = 255;\r
+                                       }\r
+                                       // nearest 2x\r
+                                       if (s->doubleres)\r
+                                       {\r
+                                               for (i = 0; i < s->info_imageheight; i++)\r
+                                               {\r
+                                                       b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2);\r
+                                                       for (j = 0; j < s->info_imagewidth; j++)\r
+                                                       {\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];\r
+                                                               //\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];\r
+                                                       }\r
+                                                       b = (unsigned char *)imagedata + (s->info_imagewidth*2*4)*(i*2 + 1);\r
+                                                       for (j = 0; j < s->info_imagewidth; j++)\r
+                                                       {\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];\r
+                                                               //\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 1];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 2];\r
+                                                               *b++ = s->videopixels[i*s->info_imagewidth*4 + j*4 + 3];\r
+                                                       }\r
+                                               }\r
+                                               // do stippling\r
+                                               if (s->stipple)\r
+                                               {\r
+                                                       for (i = 0; i < s->info_imageheight; i++)\r
+                                                       {\r
+                                                               b = (unsigned char *)imagedata + (s->info_imagewidth * 4 * 2 * 2 * i);\r
+                                                               for (j = 0; j < s->info_imagewidth; j++)\r
+                                                               {\r
+                                                                       b[0] = b[0] * s->stipple;\r
+                                                                       b[1] = b[1] * s->stipple;\r
+                                                                       b[2] = b[2] * s->stipple;\r
+                                                                       b += 4;\r
+                                                                       b[0] = b[0] * s->stipple;\r
+                                                                       b[1] = b[1] * s->stipple;\r
+                                                                       b[2] = b[2] * s->stipple;\r
+                                                                       b += 4;\r
+                                                               }\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                               }\r
+                       }\r
+                       else\r
+                               s->error = JAMDECODEERROR_READERROR;\r
+               }\r
+               else\r
+                       s->error = JAMDECODEERROR_READERROR;\r
+       }\r
+       else\r
+               s->error = DPVSIMPLEDECODEERROR_EOF;\r
+       return s->error;\r
+}
\ No newline at end of file