/* XMPS - X MPEG Player System * Copyright (C) 1999 Damien Chavarria * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public Licensse 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. */ /** * * flx_codec.c * * FLI/FLC Codec. * @Author Chavarria Damien. * Jasper Berlijn * Copyright 1999-2000 */ #include "flx_codec.h" /* * variables * */ typedef struct _flx_decoder_t { xmps_system_plugin_t *our_system; xmps_video_info_t *video_info; xmps_video_format_t format; unsigned int our_stream_id; flc_data_t flc; } flx_decoder_t; /* * get_video_decoder_info : MANDATORY * * used by scanplugins to get * a pointer to the decoder. * */ xmps_video_decoder_plugin_t *get_video_decoder_info() { xmps_video_decoder_plugin_t *video_decoder; video_decoder = (xmps_video_decoder_plugin_t *) malloc(sizeof(xmps_video_decoder_plugin_t)); video_decoder->name = "FLI/FLC"; video_decoder->data = (void *) malloc(sizeof(flx_decoder_t)); video_decoder->open = flx_open; video_decoder->get = flx_get; video_decoder->set = flx_set; video_decoder->decompress = flx_decompress; video_decoder->close = flx_close; ((flx_decoder_t *) video_decoder->data)->our_system = NULL; ((flx_decoder_t *) video_decoder->data)->our_stream_id = 0; ((flx_decoder_t *) video_decoder->data)->flc.pMembuf = NULL; ((flx_decoder_t *) video_decoder->data)->flc.membufSize = 0; ((flx_decoder_t *) video_decoder->data)->video_info = (xmps_video_info_t *) malloc(sizeof(xmps_video_info_t)); return video_decoder; } /* * Codec functions. * */ unsigned int FlcReadFile(xmps_video_decoder_plugin_t *video_decoder, Uint32 size) { if(video_decoder == NULL) { XMPS_DEBUG("read failed: %d", size); return 0; } if( ((flx_decoder_t *) video_decoder->data)->our_system == NULL ) { return 0; } if(size > ((flx_decoder_t *) video_decoder->data)->flc.membufSize) { if(!(((flx_decoder_t *) video_decoder->data)->flc.pMembuf = realloc(((flx_decoder_t *) video_decoder->data)->flc.pMembuf, size+1))) { XMPS_DEBUG("realloc failed: %d", size); return 0; } } if( ((flx_decoder_t *) video_decoder->data)->our_system->read(((flx_decoder_t *) video_decoder->data)->our_system, ((flx_decoder_t *) video_decoder->data)->our_stream_id, (void *) ((flx_decoder_t *) video_decoder->data)->flc.pMembuf, size) != size ) { return 0; } return 1; } int FlcCheckHeader(xmps_video_decoder_plugin_t *video_decoder) { if(video_decoder == NULL) { XMPS_DEBUG("wrong parameters!"); return 0; } if(((flx_decoder_t *) video_decoder->data)->our_system == NULL) { XMPS_DEBUG("wrong parameters!"); return 0; } FlcReadFile(video_decoder, 128); ReadU32(&((flx_decoder_t *) video_decoder->data)->flc.HeaderSize, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.HeaderCheck, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + 4); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.HeaderFrames, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + 6); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.HeaderWidth, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + 8); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.HeaderHeight, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + 10); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.HeaderDepth, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + 12); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.HeaderSpeed, ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + 16); if((((flx_decoder_t *) video_decoder->data)->flc.HeaderCheck == 0x0AF12) || (((flx_decoder_t *) video_decoder->data)->flc.HeaderCheck == 0x0AF11)) { XMPS_DEBUG("header seems ok!"); ((flx_decoder_t *) video_decoder->data)->flc.screen_w=((flx_decoder_t *) video_decoder->data)->flc.HeaderWidth; ((flx_decoder_t *) video_decoder->data)->flc.screen_h=((flx_decoder_t *) video_decoder->data)->flc.HeaderHeight; ((flx_decoder_t *) video_decoder->data)->flc.screen_depth=8; if(((flx_decoder_t *) video_decoder->data)->flc.HeaderCheck==0x0AF11) { ((flx_decoder_t *) video_decoder->data)->flc.HeaderSpeed*=1000/70; } return(1); } else { XMPS_DEBUG("header seems wrong %x!", ((flx_decoder_t *) video_decoder->data)->flc.HeaderSize); } return(0); } int FlcCheckFrame(xmps_video_decoder_plugin_t *video_decoder) { ((flx_decoder_t *) video_decoder->data)->flc.pFrame = ((flx_decoder_t *) video_decoder->data)->flc.pMembuf + ((flx_decoder_t *) video_decoder->data)->flc.FrameSize - 16; ReadU32(&((flx_decoder_t *) video_decoder->data)->flc.FrameSize, ((flx_decoder_t *) video_decoder->data)->flc.pFrame+0); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.FrameCheck, ((flx_decoder_t *) video_decoder->data)->flc.pFrame+4); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.FrameChunks, ((flx_decoder_t *) video_decoder->data)->flc.pFrame+6); ((flx_decoder_t *) video_decoder->data)->flc.pFrame += 16; if(((flx_decoder_t *) video_decoder->data)->flc.FrameCheck == 0x0f1fa) return(0); if(((flx_decoder_t *) video_decoder->data)->flc.FrameCheck==0x0f100) { return(0); } return(1); } void COLORS256(xmps_video_decoder_plugin_t *video_decoder) { Uint8 *pSrc; Uint16 NumColorPackets; Uint16 NumColors; Uint8 NumColorsSkip; int i; pSrc = ((flx_decoder_t *) video_decoder->data)->flc.pChunk + 6; ReadU16(&NumColorPackets, pSrc); pSrc += 2; while(NumColorPackets--) { NumColorsSkip=*(pSrc++); if(!(NumColors=*(pSrc++))) { NumColors=256; } i=0; while(NumColors--) { ((flx_decoder_t *) video_decoder->data)->flc.colors[i].r = *(pSrc++); ((flx_decoder_t *) video_decoder->data)->flc.colors[i].g = *(pSrc++); ((flx_decoder_t *) video_decoder->data)->flc.colors[i].b = *(pSrc++); i++; } } } void SS2(xmps_video_decoder_plugin_t *video_decoder, void *pixels) { Uint8 *pSrc, *pDst, *pTmpDst; Sint8 CountData; Uint8 ColumSkip, Fill1, Fill2; Uint16 Lines, Count; pSrc=((flx_decoder_t *) video_decoder->data)->flc.pChunk+6; pDst= (Uint8 *) pixels; ReadU16(&Lines, pSrc); pSrc+=2; while(Lines--) { ReadU16(&Count, pSrc); pSrc+=2; while(Count & 0xc000) { if((Count & 0xc000)==0xc000) { pDst+=(0x10000-Count)*((flx_decoder_t *) video_decoder->data)->flc.HeaderWidth; } ReadU16(&Count, pSrc); pSrc+=2; } if((Count & 0xc000)==0x0000) { pTmpDst=pDst; while(Count--) { ColumSkip=*(pSrc++); pTmpDst+=ColumSkip; CountData=*(pSrc++); if(CountData>0) { while(CountData--) { *(pTmpDst++)=*(pSrc++); *(pTmpDst++)=*(pSrc++); } } else { if(CountData<0) { CountData=(0x100-CountData); Fill1=*(pSrc++); Fill2=*(pSrc++); while(CountData--) { *(pTmpDst++)=Fill1; *(pTmpDst++)=Fill2; } } } } pDst+=((flx_decoder_t *) video_decoder->data)->flc.HeaderWidth; } } } void DECODE_BRUN(xmps_video_decoder_plugin_t *video_decoder, void *pixels) { Uint8 *pSrc, *pDst, Fill; Sint8 CountData; int HeightCount, PacketsCount; HeightCount=((flx_decoder_t *) video_decoder->data)->flc.HeaderHeight; pSrc=((flx_decoder_t *) video_decoder->data)->flc.pChunk+6; pDst= (Uint8 *) pixels; while(HeightCount--) { PacketsCount=*(pSrc++); while(PacketsCount--) { CountData=*(pSrc++); if(CountData>0) { Fill=*(pSrc++); while(CountData--) { *(pDst++)=Fill; } } else { if(CountData<0) { CountData=(0x100-CountData); while(CountData--) { *(pDst++)=*(pSrc++); } } } } } } void DECODE_LC(xmps_video_decoder_plugin_t *video_decoder, void * pixels) { Uint8 *pSrc, *pDst, *pTmpDst; Sint8 CountData; Uint8 CountSkip; Uint8 Fill; Uint16 Lines, tmp; int PacketsCount; pSrc=((flx_decoder_t *) video_decoder->data)->flc.pChunk + 6; pDst= (Uint8 *) pixels; ReadU16(&tmp, pSrc); pSrc+=2; pDst+=tmp*((flx_decoder_t *) video_decoder->data)->flc.HeaderWidth; ReadU16(&Lines, pSrc); pSrc+=2; while(Lines--) { pTmpDst=pDst; PacketsCount=*(pSrc++); while(PacketsCount--) { CountSkip=*(pSrc++); pTmpDst+=CountSkip; CountData=*(pSrc++); if(CountData>0) { while(CountData--) { *(pTmpDst++)=*(pSrc++); } } else { if(CountData<0) { CountData=(0x100-CountData); Fill=*(pSrc++); while(CountData--) { *(pTmpDst++)=Fill; } } } } pDst+=((flx_decoder_t *) video_decoder->data)->flc.screen_w; } } void DECODE_COLOR(xmps_video_decoder_plugin_t *video_decoder) { Uint8 *pSrc; Uint16 NumColors, NumColorPackets; Uint8 NumColorsSkip; int i; pSrc = ((flx_decoder_t *) video_decoder->data)->flc.pChunk + 6; ReadU16(&NumColorPackets, pSrc); pSrc += 2; while(NumColorPackets--) { NumColorsSkip=*(pSrc++); if(!(NumColors = *(pSrc++))) { NumColors = 256; } i = 0; while(NumColors--) { ((flx_decoder_t *) video_decoder->data)->flc.colors[i].r = *(pSrc++) << 2; ((flx_decoder_t *) video_decoder->data)->flc.colors[i].g = *(pSrc++) << 2; ((flx_decoder_t *) video_decoder->data)->flc.colors[i].b = *(pSrc++) << 2; i++; } } } void DECODE_COPY(xmps_video_decoder_plugin_t *video_decoder, void *pixels) { Uint8 *pSrc, *pDst; pSrc=((flx_decoder_t *) video_decoder->data)->flc.pChunk+6; pDst= (Uint8 *) pixels; memcpy(pDst, pSrc, ((flx_decoder_t *) video_decoder->data)->flc.screen_w*((flx_decoder_t *) video_decoder->data)->flc.screen_h); } void BLACK(xmps_video_decoder_plugin_t *video_decoder, void *pixels) { Uint8 *pDst; pDst= (Uint8 *) pixels; memset(pDst, 0, ((flx_decoder_t *) video_decoder->data)->flc.screen_w*((flx_decoder_t *) video_decoder->data)->flc.screen_h); } void FlcDoOneFrame(xmps_video_decoder_plugin_t *video_decoder, void *pixels) { int ChunkCount; if(video_decoder == NULL) { return; } if(((flx_decoder_t *) video_decoder->data)->our_system == NULL) { return; } ChunkCount = ((flx_decoder_t *) video_decoder->data)->flc.FrameChunks; ((flx_decoder_t *) video_decoder->data)->flc.pChunk = ((flx_decoder_t *) video_decoder->data)->flc.pMembuf; while(ChunkCount--) { ReadU32(&((flx_decoder_t *) video_decoder->data)->flc.ChunkSize, ((flx_decoder_t *) video_decoder->data)->flc.pChunk+0); ReadU16(&((flx_decoder_t *) video_decoder->data)->flc.ChunkType, ((flx_decoder_t *) video_decoder->data)->flc.pChunk+4); switch(((flx_decoder_t *) video_decoder->data)->flc.ChunkType) { case 4: COLORS256(video_decoder); break; case 7: SS2(video_decoder, pixels); break; case 11: DECODE_COLOR(video_decoder); break; case 12: DECODE_LC(video_decoder, pixels); break; case 13: BLACK(video_decoder, pixels); break; case 15: DECODE_BRUN(video_decoder, pixels); break; case 16: DECODE_COPY(video_decoder, pixels); break; case 18: break; default: XMPS_DEBUG("Ieek an non implemented chunk type: %d", ((flx_decoder_t *) video_decoder->data)->flc.ChunkType); } ((flx_decoder_t *) video_decoder->data)->flc.pChunk += ((flx_decoder_t *) video_decoder->data)->flc.ChunkSize; } } void FlcInitFirstFrame(xmps_video_decoder_plugin_t *video_decoder) { if(video_decoder == NULL) { return; } if(((flx_decoder_t *) video_decoder->data)->our_system == NULL) { return; } ((flx_decoder_t *) video_decoder->data)->flc.FrameSize=16; ((flx_decoder_t *) video_decoder->data)->flc.FrameCount=0; if(((flx_decoder_t *) video_decoder->data)->our_system->seek(((flx_decoder_t *) video_decoder->data)->our_system, ((flx_decoder_t *) video_decoder->data)->our_stream_id, 128, XMPS_SEEK_SET) != 128) { XMPS_DEBUG("seek system failed"); return; }; FlcReadFile(video_decoder, ((flx_decoder_t *) video_decoder->data)->flc.FrameSize); } /********** Standard functions ************/ unsigned int flx_open(xmps_video_decoder_plugin_t *video_decoder) { if(((flx_decoder_t *) video_decoder->data)->our_system != NULL) return 0; XMPS_DEBUG("flx codec init"); return 1; } void* flx_get(xmps_video_decoder_plugin_t *video_decoder, unsigned int flags, void *data) { if(video_decoder == NULL) return NULL; switch(flags) { case XMPS_FLAG_VIDEO_FORMAT_LIST: { GList *list = NULL; flx_decoder_t *flx_data; flx_data = (flx_decoder_t *) video_decoder->data; if(flx_data == NULL) { return NULL; } flx_data->format.type = XMPS_VIDEO_FORMAT_RGB8; flx_data->format.bpp = 8; list = g_list_prepend(list, (void *) &flx_data->format); return list; } break; case XMPS_FLAG_VIDEO_INFO: { flx_decoder_t *flx_data; flx_data = (flx_decoder_t *) video_decoder->data; XMPS_DEBUG("giving video info!") if(flx_data == NULL) { XMPS_DEBUG("problem!"); return NULL; } flx_data->video_info->width = flx_data->flc.screen_w; flx_data->video_info->height = flx_data->flc.screen_h; flx_data->video_info->format.type = XMPS_VIDEO_FORMAT_RGB8; flx_data->video_info->format.bpp = 8; flx_data->video_info->palette = flx_data->flc.colors; if(flx_data->video_info == NULL) { XMPS_DEBUG("big problem!"); return NULL; } return (void *) ((flx_decoder_t *) video_decoder->data)->video_info; } break; default: return NULL; break; } } unsigned int flx_set(xmps_video_decoder_plugin_t *video_decoder, unsigned int flag, void *data) { switch(flag) { case XMPS_FLAG_INPUT: { xmps_data_t *data_stream; data_stream = (xmps_data_t *) data; if(data_stream == NULL) { return 0; } XMPS_DEBUG("trying to open data stream!"); if(data_stream->type == XMPS_DATA_VIDEO_COMP) { /* * TODO : check vcomp * */ return 0; } if(data_stream->type == XMPS_DATA_RAW) { unsigned int can_play = 0; /* * we need to test for data * consistency * */ ((flx_decoder_t *) video_decoder->data)->our_system = (xmps_system_plugin_t *) data_stream->plugin; ((flx_decoder_t *) video_decoder->data)->our_stream_id = data_stream->id; ((flx_decoder_t *) video_decoder->data)->our_system->seek(((flx_decoder_t *) video_decoder->data)->our_system, ((flx_decoder_t *) video_decoder->data)->our_stream_id, 0, XMPS_SEEK_SET); XMPS_DEBUG("checking header!"); can_play = FlcCheckHeader(video_decoder); if(can_play == 1) { XMPS_DEBUG("we accept the data!"); FlcInitFirstFrame(video_decoder); return 1; } } return 0; } default: return 0; break; } } unsigned int flx_decompress(xmps_video_decoder_plugin_t *video_decoder, void *in_buffer, void *out_buffer, unsigned int size) { /* * security check * */ flx_decoder_t *flx_data; if(video_decoder == NULL) { return 0; } flx_data = (flx_decoder_t *) video_decoder->data; if(flx_data == NULL) { return 0; } /* * see if we are at the begining * */ if(flx_data->our_system->seek(flx_data->our_system, flx_data->our_stream_id, 0, XMPS_SEEK_CUR) == 0) { FlcInitFirstFrame(video_decoder); } /* * do one frame * */ flx_data->flc.FrameCount++; if(FlcCheckFrame(video_decoder)) { if (flx_data->flc.FrameCount <= flx_data->flc.HeaderFrames) { XMPS_DEBUG("Frame failure -- corrupt file?"); return 0; } } if(!FlcReadFile(video_decoder, flx_data->flc.FrameSize)) { return 0; } if(flx_data->flc.FrameCheck != 0x0f100) { FlcDoOneFrame(video_decoder, out_buffer); } return 1; } unsigned int flx_close(xmps_video_decoder_plugin_t *video_decoder) { XMPS_DEBUG("close"); ((flx_decoder_t *) video_decoder->data)->our_system = NULL; return 1; }