BlinkenArea - GitList
Repositories
Blog
Wiki
BlinkenLib
Code
Commits
Branches
Tags
Search
Tree:
a62ca13
Branches
Tags
master
v0.1
v0.2
v0.3
v0.3.1
v0.4
v0.4.1
v0.5
v0.5.1
v0.5.2
v0.5.3
v0.5.4
v0.5.5
v0.6.0
v0.6.1
v0.6.2
v0.6.3
v0.6.4
v0.6.5
v0.6.6
v0.6.7
v0.6.8
v0.6.9
v0.7.0
v0.7.1
v0.7.10
v0.7.2
v0.7.3
v0.7.4
v0.7.5
v0.7.6
v0.7.7
v0.7.8
v0.7.9
v0.8.0
v0.8.1
BlinkenLib
BlinkenMovie.c
BlinkenLib v.0.4.1 (2005-12-05)
Christian Heimke
commited
a62ca13
at 2011-07-15 09:03:25
BlinkenMovie.c
Blame
History
Raw
/* BlinkenLib * version 0.4.1 date 2005-12-05 * Copyright 2004-2005 Stefan Schuermans <1stein@schuermans.info> * Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html * a blinkenarea.org project * powered by eventphone.de */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/select.h> #include "BlinkenConstants.h" #include "BlinkenFrame.h" #include "BlinkenMovie.h" #include "Tools.h" struct sBlinkenMovie { int height; int width; int channels; int maxval; int infoCnt; char * * * pppInfos; int frameCnt; stBlinkenFrame * * ppFrames; }; stBlinkenMovie * BlinkenMovieNew( int height, int width, int channels, int maxval ) { stBlinkenMovie * pMovie; if( height < BlinkenHeightMin ) height = BlinkenHeightMin; if( height > BlinkenHeightMax ) height = BlinkenHeightMax; if( width < BlinkenWidthMin ) width = BlinkenWidthMin; if( width > BlinkenWidthMax ) width = BlinkenWidthMax; if( channels < BlinkenChannelsMin ) channels = BlinkenChannelsMin; if( channels > BlinkenChannelsMax ) channels = BlinkenMaxvalMax; if( maxval < BlinkenMaxvalMin ) maxval = BlinkenMaxvalMin; if( maxval > BlinkenMaxvalMax ) maxval = BlinkenMaxvalMax; pMovie = (stBlinkenMovie *)malloc( sizeof( stBlinkenMovie ) ); if( pMovie == NULL ) return NULL; pMovie->height = height; pMovie->width = width; pMovie->channels = channels; pMovie->maxval = maxval; pMovie->infoCnt = 0; pMovie->pppInfos = (char * * *)malloc2D( 0, 2, sizeof( char * ) ); if( pMovie->pppInfos == NULL ) { free( pMovie ); return NULL; } pMovie->frameCnt = 0; pMovie->ppFrames = (stBlinkenFrame * *)malloc1D( 0, sizeof( stBlinkenFrame * ) ); if( pMovie->ppFrames == NULL ) { free( pMovie->pppInfos ); free( pMovie ); return NULL; } return pMovie; } stBlinkenMovie * BlinkenMovieClone( stBlinkenMovie * pSrcMovie ) { stBlinkenMovie * pMovie; stBlinkenFrame * pFrame; int i; pMovie = BlinkenMovieNew( pSrcMovie->height, pSrcMovie->width, pSrcMovie->channels, pSrcMovie->maxval ); if( pMovie == NULL ) return NULL; for( i = 0; i < pSrcMovie->infoCnt; i++ ) BlinkenMovieAppendInfo( pMovie, pSrcMovie->pppInfos[i][0], pSrcMovie->pppInfos[i][1] ); for( i = 0; i < pSrcMovie->frameCnt; i++ ) { pFrame = BlinkenFrameClone( pSrcMovie->ppFrames[i] ); if( BlinkenMovieAppendFrame( pMovie, pFrame ) != 0 ) BlinkenFrameFree( pFrame ); } return pMovie; } void BlinkenMovieFree( stBlinkenMovie * pMovie ) { int i; if( pMovie == NULL ) return; for( i = 0; i < pMovie->infoCnt; i++ ) { free( pMovie->pppInfos[i][0] ); free( pMovie->pppInfos[i][1] ); } free( pMovie->pppInfos ); for( i = 0; i < pMovie->frameCnt; i++ ) BlinkenFrameFree( pMovie->ppFrames[i] ); free( pMovie->ppFrames ); free( pMovie ); } int BlinkenMovieGetHeight( stBlinkenMovie * pMovie ) { if( pMovie == NULL ) return 0; return pMovie->height; } int BlinkenMovieGetWidth( stBlinkenMovie * pMovie ) { if( pMovie == NULL ) return 0; return pMovie->width; } int BlinkenMovieGetChannels( stBlinkenMovie * pMovie ) { if( pMovie == NULL ) return 0; return pMovie->channels; } int BlinkenMovieGetMaxval( stBlinkenMovie * pMovie ) { if( pMovie == NULL ) return 0; return pMovie->maxval; } int BlinkenMovieGetDuration( stBlinkenMovie * pMovie ) { int i, duration; if( pMovie == NULL ) return 0; duration = 0; for( i = 0; i < pMovie->frameCnt; i++ ) duration += BlinkenFrameGetDuration( pMovie->ppFrames[i] ); return duration; } int BlinkenMovieGetInfoCnt( stBlinkenMovie * pMovie ) { if( pMovie == NULL ) return 0; return pMovie->infoCnt; } char * BlinkenMovieGetInfoType( stBlinkenMovie * pMovie, int infoNo ) { if( pMovie == NULL || pMovie->infoCnt < 1 ) return ""; if( infoNo < 0 ) infoNo = 0; if( infoNo >= pMovie->infoCnt ) infoNo = pMovie->infoCnt - 1; return pMovie->pppInfos[infoNo][0]; } char * BlinkenMovieGetInfoData( stBlinkenMovie * pMovie, int infoNo ) { if( pMovie == NULL || pMovie->infoCnt < 1 ) return ""; if( infoNo < 0 ) infoNo = 0; if( infoNo >= pMovie->infoCnt ) infoNo = pMovie->infoCnt - 1; return pMovie->pppInfos[infoNo][1]; } void BlinkenMovieSetInfo( stBlinkenMovie * pMovie, int infoNo, char * pInfoType, char * pInfoData ) { char * pType, * pData; if( pMovie == NULL || infoNo < 0 || infoNo >= pMovie->infoCnt ) return; pType = strdup( pInfoType ); if( pType == NULL ) return; pData = strdup( pInfoData ); if( pData == NULL ) { free( pType ); return; } free( pMovie->pppInfos[infoNo][0] ); pMovie->pppInfos[infoNo][0] = pType; free( pMovie->pppInfos[infoNo][1] ); pMovie->pppInfos[infoNo][1] = pData; } void BlinkenMovieInsertInfo( stBlinkenMovie * pMovie, int infoNo, char * pInfoType, char * pInfoData ) { char * * * pppNewInfos, * pType, * pData; int i; if( pMovie == NULL || infoNo < 0 || infoNo > pMovie->infoCnt ) return; pppNewInfos = (char * * *)malloc2D( pMovie->infoCnt + 1, 2, sizeof( char * ) ); if( pppNewInfos == NULL ) return; pType = strdup( pInfoType ); if( pType == NULL ) { free( pppNewInfos ); return; } pData = strdup( pInfoData ); if( pData == NULL ) { free( pppNewInfos ); free( pType ); return; } for( i = 0; i < infoNo; i++ ) { pppNewInfos[i][0] = pMovie->pppInfos[i][0]; pppNewInfos[i][1] = pMovie->pppInfos[i][1]; } pppNewInfos[infoNo][0] = pType; pppNewInfos[infoNo][1] = pData; for( i = infoNo; i < pMovie->infoCnt; i++ ) { pppNewInfos[i+1][0] = pMovie->pppInfos[i][0]; pppNewInfos[i+1][1] = pMovie->pppInfos[i][1]; } free( pMovie->pppInfos ); pMovie->pppInfos = pppNewInfos; pMovie->infoCnt++; } void BlinkenMovieAppendInfo( stBlinkenMovie * pMovie, char * pInfoType, char * pInfoData ) { if( pMovie == NULL ) return; BlinkenMovieInsertInfo( pMovie, pMovie->infoCnt, pInfoType, pInfoData ); } void BlinkenMovieDeleteInfo( stBlinkenMovie * pMovie, int infoNo ) { char * * * pppNewInfos; int i; if( pMovie == NULL || infoNo < 0 || infoNo >= pMovie->infoCnt ) return; pppNewInfos = (char * * *)malloc2D( pMovie->infoCnt - 1, 2, sizeof( char * ) ); if( pppNewInfos == NULL ) return; for( i = 0; i < infoNo; i++ ) { pppNewInfos[i][0] = pMovie->pppInfos[i][0]; pppNewInfos[i][1] = pMovie->pppInfos[i][1]; } free( pMovie->pppInfos[infoNo][0] ); free( pMovie->pppInfos[infoNo][1] ); for( i = infoNo; i < pMovie->infoCnt - 1; i++ ) { pppNewInfos[i][0] = pMovie->pppInfos[i+1][0]; pppNewInfos[i][1] = pMovie->pppInfos[i+1][1]; } free( pMovie->pppInfos ); pMovie->pppInfos = pppNewInfos; pMovie->infoCnt--; } void BlinkenMovieDeleteInfos( stBlinkenMovie * pMovie ) { char * * * pppNewInfos; int i; if( pMovie == NULL ) return; pppNewInfos = (char * * *)malloc2D( 0, 2, sizeof( char * ) ); if( pppNewInfos == NULL ) return; for( i = 0; i < pMovie->infoCnt; i++ ) { free( pMovie->pppInfos[i][0] ); free( pMovie->pppInfos[i][1] ); } free( pMovie->pppInfos ); pMovie->pppInfos = pppNewInfos; pMovie->infoCnt = 0; } int BlinkenMovieGetFrameCnt( stBlinkenMovie * pMovie ) { if( pMovie == NULL ) return 0; return pMovie->frameCnt; } stBlinkenFrame * BlinkenMovieGetFrame( stBlinkenMovie * pMovie, int frameNo ) { if( pMovie == NULL || pMovie->frameCnt < 1 ) return NULL; if( frameNo < 0 ) frameNo = 0; if( frameNo >= pMovie->frameCnt ) frameNo = pMovie->frameCnt - 1; return pMovie->ppFrames[frameNo]; } void BlinkenMovieSetFrame( stBlinkenMovie * pMovie, int frameNo, stBlinkenFrame * pFrame ) { if( pMovie == NULL || frameNo < 0 || frameNo >= pMovie->frameCnt ) return; BlinkenFrameResize( pFrame, pMovie->height, pMovie->width, pMovie->channels, pMovie->maxval ); pMovie->ppFrames[frameNo] = pFrame; } int BlinkenMovieInsertFrame( stBlinkenMovie * pMovie, int frameNo, stBlinkenFrame * pFrame ) { stBlinkenFrame * * ppNewFrames; int i; if( pMovie == NULL || frameNo < 0 || frameNo > pMovie->frameCnt ) return -1; ppNewFrames = (stBlinkenFrame * *)malloc1D( pMovie->frameCnt + 1, sizeof( stBlinkenFrame * ) ); if( ppNewFrames == NULL ) return -1; for( i = 0; i < frameNo; i++ ) ppNewFrames[i] = pMovie->ppFrames[i]; BlinkenFrameResize( pFrame, pMovie->height, pMovie->width, pMovie->channels, pMovie->maxval ); ppNewFrames[frameNo] = pFrame; for( i = frameNo; i < pMovie->frameCnt; i++ ) ppNewFrames[i+1] = pMovie->ppFrames[i]; free( pMovie->ppFrames ); pMovie->ppFrames = ppNewFrames; pMovie->frameCnt++; return 0; } int BlinkenMovieAppendFrame( stBlinkenMovie * pMovie, stBlinkenFrame * pFrame ) { if( pMovie == NULL ) return -1; return BlinkenMovieInsertFrame( pMovie, pMovie->frameCnt, pFrame ); } void BlinkenMovieDeleteFrame( stBlinkenMovie * pMovie, int frameNo ) { stBlinkenFrame * * ppNewFrames; int i; if( pMovie == NULL || frameNo < 0 || frameNo >= pMovie->frameCnt ) return; ppNewFrames = (stBlinkenFrame * *)malloc1D( pMovie->frameCnt - 1, sizeof( stBlinkenFrame * ) ); if( ppNewFrames == NULL ) return; for( i = 0; i < frameNo; i++ ) ppNewFrames[i] = pMovie->ppFrames[i]; BlinkenFrameFree( pMovie->ppFrames[frameNo] ); for( i = frameNo; i < pMovie->frameCnt - 1; i++ ) ppNewFrames[i] = pMovie->ppFrames[i+1]; free( pMovie->ppFrames ); pMovie->ppFrames = ppNewFrames; pMovie->frameCnt--; } void BlinkenMovieDeleteFrames( stBlinkenMovie * pMovie ) { stBlinkenFrame * * ppNewFrames; int i; if( pMovie == NULL ) return; ppNewFrames = (stBlinkenFrame * *)malloc1D( 0, sizeof( stBlinkenFrame * ) ); if( ppNewFrames == NULL ) return; for( i = 0; i < pMovie->frameCnt; i++ ) BlinkenFrameFree( pMovie->ppFrames[i] ); free( pMovie->ppFrames ); pMovie->ppFrames = ppNewFrames; pMovie->frameCnt = 0; } void BlinkenMovieResize( stBlinkenMovie * pMovie, int height, int width, int channels, int maxval ) { int i; if( pMovie == NULL ) return; if( height < BlinkenHeightMin ) height = BlinkenHeightMin; if( height > BlinkenHeightMax ) height = BlinkenHeightMax; if( width < BlinkenWidthMin ) width = BlinkenWidthMin; if( width > BlinkenWidthMax ) width = BlinkenWidthMax; if( channels < BlinkenChannelsMin ) channels = BlinkenChannelsMin; if( channels > BlinkenChannelsMax ) channels = BlinkenMaxvalMax; if( maxval < BlinkenMaxvalMin ) maxval = BlinkenMaxvalMin; if( maxval > BlinkenMaxvalMax ) maxval = BlinkenMaxvalMax; pMovie->height = height; pMovie->width = width; pMovie->channels = channels; pMovie->maxval = maxval; for( i = 0; i < pMovie->frameCnt; i++ ) BlinkenFrameResize( pMovie->ppFrames[i], height, width, channels, maxval ); } void BlinkenMovieScale( stBlinkenMovie * pMovie, int height, int width ) { int i; if( pMovie == NULL ) return; if( height < BlinkenHeightMin ) height = BlinkenHeightMin; if( height > BlinkenHeightMax ) height = BlinkenHeightMax; if( width < BlinkenWidthMin ) width = BlinkenWidthMin; if( width > BlinkenWidthMax ) width = BlinkenWidthMax; pMovie->height = height; pMovie->width = width; for( i = 0; i < pMovie->frameCnt; i++ ) BlinkenFrameScale( pMovie->ppFrames[i], height, width ); } char * BlinkenMovieToString( stBlinkenMovie * pMovie ) { char * * strs, * str, * ptr; int i, size; if( pMovie == NULL ) return NULL; strs = (char * *)malloc1D( pMovie->frameCnt, sizeof( char * ) ); if( strs == NULL ) return NULL; for( i = 0; i < pMovie->frameCnt; i++ ) { strs[i] = BlinkenFrameToString( pMovie->ppFrames[i] ); if( strs[i] == NULL ) { for( i--; i >= 0; i-- ) free( strs[i] ); free( strs ); return NULL; } } size = 128; for( i = 0; i < pMovie->infoCnt; i++ ) size += strlen( pMovie->pppInfos[i][0] ) + strlen( pMovie->pppInfos[i][1] ) + 8; for( i = 0; i < pMovie->frameCnt; i++ ) size += strlen( strs[i] ) + 32; str = (char *)malloc( size ); if( str == NULL ) { for( i = 0; i < pMovie->frameCnt; i++ ) free( strs[i] ); free( strs ); return NULL; } ptr = str; sprintf( ptr, "BlinkenMovie %ux%u-%u/%u\n", pMovie->width, pMovie->height, pMovie->channels, pMovie->maxval ); ptr += strlen( ptr ); for( i = 0; i < pMovie->infoCnt; i++ ) { sprintf( ptr, "%s = %s\n", pMovie->pppInfos[i][0], pMovie->pppInfos[i][1] ); ptr += strlen( ptr ); } for( i = 0; i < pMovie->frameCnt; i++ ) { sprintf( ptr, "frame %u\n%s", i, strs[i] ); ptr += strlen( ptr ); free( strs[i] ); } free( strs ); return str; } stBlinkenMovie * BlinkenMovieLoadBlm( char * pFilename ) { FILE * pFile; stBlinkenMovie * pMovie; stBlinkenFrame * pFrame; int width, height, y, x, chr, duration; char infoType[256], infoData[1024], pixel[2]; if( pFilename == NULL ) return NULL; //open file pFile = fopen( pFilename, "rt" ); if( pFile == NULL ) return NULL; //read magic and size if( fscanf( pFile, " # BlinkenLights Movie %ux%u", &width, &height ) != 2 ) { fclose( pFile ); return NULL; } //allocate a new movie pMovie = BlinkenMovieNew( height, width, 1, 1 ); if( pMovie == NULL ) { fclose( pFile ); return NULL; } //no frame yet pFrame = NULL; y = 0; //read frames while( ! feof( pFile ) ) { //skip rest of previous line (including newline) while( (chr = fgetc( pFile )) != '\n' && chr != EOF ); //info line if( fscanf( pFile, " # %255[A-Za-z0-9] %*[=:] %1023[^\n]", infoType, infoData ) == 2 ) { BlinkenMovieAppendInfo( pMovie, infoType, infoData ); } //start of frame else if( fscanf( pFile, " @ %u", &duration ) == 1 ) { //create new frame and append it to movie pFrame = BlinkenFrameNew( height, width, 1, 1, duration ); if( pFrame != NULL ) { BlinkenFrameClear( pFrame ); if( BlinkenMovieAppendFrame( pMovie, pFrame ) != 0 ) { BlinkenFrameFree( pFrame ); pFrame = NULL; } y = 0; } } //data line else if( fscanf( pFile, "%1[01]", pixel ) == 1 ) { if( pFrame != NULL ) { for( x = 0; ; x++ ) { BlinkenFrameSetPixel( pFrame, y, x, 0, pixel[0] == '1' ? 1 : 0 ); //set pixel if( fscanf( pFile, "%1[01]", pixel ) != 1 ) //read next pixel break; } y++; //next row } } } //while( ! feof( pFile ) ) //close file fclose( pFile ); return pMovie; } stBlinkenMovie * BlinkenMovieLoadBmm( char * pFilename ) { FILE * pFile; stBlinkenMovie * pMovie; stBlinkenFrame * pFrame; int width, height, y, x, chr, duration, val; char infoType[256], infoData[1024], pixel[8]; if( pFilename == NULL ) return NULL; //open file pFile = fopen( pFilename, "rt" ); if( pFile == NULL ) return NULL; //read magic and size if( fscanf( pFile, " # BlinkenMini Movie %ux%u", &width, &height ) != 2 ) { fclose( pFile ); return NULL; } //allocate a new movie pMovie = BlinkenMovieNew( height, width, 1, 255 ); if( pMovie == NULL ) { fclose( pFile ); return NULL; } //no frame yet pFrame = NULL; y = 0; //read frames while( ! feof( pFile ) ) { //skip rest of previous line (including newline) while( (chr = fgetc( pFile )) != '\n' && chr != EOF ); //info line if( fscanf( pFile, " # %255[A-Za-z0-9] %*[=:] %1023[^\n]", infoType, infoData ) == 2 ) { BlinkenMovieAppendInfo( pMovie, infoType, infoData ); } //start of frame else if( fscanf( pFile, " @ %u", &duration ) == 1 ) { //create new frame and append it to movie pFrame = BlinkenFrameNew( height, width, 1, 255, duration ); if( pFrame != NULL ) { BlinkenFrameClear( pFrame ); if( BlinkenMovieAppendFrame( pMovie, pFrame ) != 0 ) { BlinkenFrameFree( pFrame ); pFrame = NULL; } y = 0; } } //data line else if( fscanf( pFile, "%7[0-9A-FXa-fx]", pixel ) == 1 ) { if( pFrame != NULL ) { for( x = 0; ; x++ ) { if( sscanf( pixel, "%i", &val ) != 1 ) //convert pixel to number break; BlinkenFrameSetPixel( pFrame, y, x, 0, (unsigned char)val ); //set pixel fscanf( pFile, "%*[ \t]" ); //kill space if( fscanf( pFile, "%7[0-9A-FXa-fx]", pixel ) != 1 ) //read next pixel break; } y++; //next row } } } //while( ! feof( pFile ) ) //close file fclose( pFile ); return pMovie; } stBlinkenMovie * BlinkenMovieLoadBml( char * pFilename ) { FILE * pFile; stBlinkenMovie * pMovie; stBlinkenFrame * pFrame; int width, height, channels, bits, maxval, chrs, y, x, c, duration, val; char buffer[2048], infoType[256], infoData[1024], pixelFormat[16], pixel[8], * ptr, chr; if( pFilename == NULL ) return NULL; //open file pFile = fopen( pFilename, "rt" ); if( pFile == NULL ) return NULL; //no movie yet - blm tag not yet found pMovie = NULL; //no frame yet pFrame = NULL; y = 0; //read tags maxval = 0; while( ! feof( pFile ) ) { //skip to just before beginning of next tag fscanf( pFile, "%*[^<]" ); //skip beginning character of next tag if( fgetc( pFile ) != '<' ) //end loop (no more tags) break; //no blm tag yet if( pMovie == NULL ) { //blm tag if( fscanf( pFile, "blm%2047[^>]", buffer ) == 1 ) { //get attributes width = 0; height = 0; channels = 1; bits = 4; maxval = 15; if( (ptr = strstr( buffer, "height=\"" )) != NULL ) //height sscanf( ptr+8, "%u", &height ); if( (ptr = strstr( buffer, "width=\"" )) != NULL ) //width sscanf( ptr+7, "%u", &width ); if( (ptr = strstr( buffer, "channels=\"" )) != NULL ) //channels sscanf( ptr+10, "%u", &channels ); if( (ptr = strstr( buffer, "bits=\"" )) != NULL ) //bits sscanf( ptr+6, "%u", &bits ); maxval = (1 << bits) - 1; //maxval //allocate a new movie pMovie = BlinkenMovieNew( height, width, channels, maxval ); if( pMovie == NULL ) { fclose( pFile ); return NULL; } //get number of characters per channel chrs = (bits + 3) >> 2; //get fscanf formart string for reading a pixel sprintf( pixelFormat, "%%%d[0-9A-Fa-f]", chrs > 4 ? 5 : chrs ); //read max 5 chars (2 already in use by prefix) //initialize pixel buffer with hex prefix strcpy( pixel, "0x" ); } } //if( pMovie == NULL ) //blm tag was already found else //if( pMovie == NULL ) { //title tag if( fscanf( pFile, "title>%2047[^<]", buffer ) == 1 ) { //add info to movie BlinkenMovieAppendInfo( pMovie, "title", buffer ); } //description tag else if( fscanf( pFile, "description>%2047[^<]", buffer ) == 1 ) { //check if generic info if( sscanf( buffer, "%255[A-Za-z0-9] %*[=:] %1023[^\n]", infoType, infoData ) == 2 ) //add info to movie BlinkenMovieAppendInfo( pMovie, infoType, infoData ); else //add info to movie BlinkenMovieAppendInfo( pMovie, "description", buffer ); } //creator tag else if( fscanf( pFile, "creator>%2047[^<]", buffer ) == 1 ) { //add info to movie BlinkenMovieAppendInfo( pMovie, "creator", buffer ); } //author tag else if( fscanf( pFile, "author>%2047[^<]", buffer ) == 1 ) { //add info to movie BlinkenMovieAppendInfo( pMovie, "author", buffer ); } //email tag else if( fscanf( pFile, "email>%2047[^<]", buffer ) == 1 ) { //add info to movie BlinkenMovieAppendInfo( pMovie, "email", buffer ); } //url tag else if( fscanf( pFile, "url>%2047[^<]", buffer ) == 1 ) { //add info to movie BlinkenMovieAppendInfo( pMovie, "url", buffer ); } //frame tag else if( fscanf( pFile, "frame%2047[^>]", buffer ) == 1 ) { //get attributes duration = 0; if( (ptr = strstr( buffer, "duration=\"" )) != NULL ) //duration sscanf( ptr+10, "%u", &duration ); //create new frame and append it to movie pFrame = BlinkenFrameNew( height, width, channels, maxval, duration ); if( pFrame != NULL ) { BlinkenFrameClear( pFrame ); if( BlinkenMovieAppendFrame( pMovie, pFrame ) != 0 ) { BlinkenFrameFree( pFrame ); pFrame = NULL; } y = 0; } } //row tag else if( fscanf( pFile, "row%c", &chr ) == 1 && chr == '>' ) { if( pFrame != NULL ) { //parse row for( x = 0; x < width; x++ ) { for( c = 0; c < channels; c++ ) { //read next pixel (one channel of pixel) if( fscanf( pFile, pixelFormat, pixel+2 ) != 1 ) { x = width; //also terminate x loop break; } //convert pixel (one channel of pixel) to number if( sscanf( pixel, "%i", &val ) != 1 ) { x = width; //also terminate x loop break; } //set pixel (one channel of pixel) BlinkenFrameSetPixel( pFrame, y, x, c, (unsigned char)val ); } } y++; //next row } } } //if( pMovie == NULL ) ... else } //while( ! feof( pFile ) ) //close file fclose( pFile ); return pMovie; } stBlinkenMovie * BlinkenMovieLoadBbm( char * pFilename ) { FILE * pFile; stBlinkenMovie * pMovie; stBlinkenFrame * pFrame; unsigned char header[24], subHeader[6], frameStartMarker[4]; unsigned long headerMagic, headerFrameCnt, headerDuration, headerFramePtr; unsigned short headerHeight, headerWidth, headerChannels, headerMaxval; unsigned long subHeaderMagic, frameStartMarkerMagic; unsigned short subHeaderSize; unsigned char * pInfoHeader, * pInfoHeaderX, * pFrameData; int len, duration, y, x, c, i; if( pFilename == NULL ) return NULL; //open file pFile = fopen( pFilename, "rb" ); if( pFile == NULL ) return NULL; //read header if( fread( header, 1, 24, pFile ) != 24 ) { fclose( pFile ); return NULL; } headerMagic = (unsigned long)header[0] << 24 | (unsigned long)header[1] << 16 | (unsigned long)header[2] << 8 | (unsigned long)header[3]; headerHeight = (unsigned short)header[4] << 8 | (unsigned short)header[5]; headerWidth = (unsigned short)header[6] << 8 | (unsigned short)header[7]; headerChannels = (unsigned short)header[8] << 8 | (unsigned short)header[9]; headerMaxval = (unsigned short)header[10] << 8 | (unsigned short)header[11]; headerFrameCnt = (unsigned long)header[12] << 24 | (unsigned long)header[13] << 16 | (unsigned long)header[14] << 8 | (unsigned long)header[15]; headerDuration = (unsigned long)header[16] << 24 | (unsigned long)header[17] << 16 | (unsigned long)header[18] << 8 | (unsigned long)header[19]; headerFramePtr = (unsigned long)header[20] << 24 | (unsigned long)header[21] << 16 | (unsigned long)header[22] << 8 | (unsigned long)header[23]; //check magic if( headerMagic != 0x23542666 ) { fclose( pFile ); return NULL; } //allocate a new movie pMovie = BlinkenMovieNew( headerHeight, headerWidth, headerChannels, headerMaxval ); if( pMovie == NULL ) { fclose( pFile ); return NULL; } //read subheaders while( ftell( pFile ) + 6 <= (long)headerFramePtr ) { if( fread( subHeader, 1, 6, pFile ) != 6 ) { BlinkenMovieFree( pMovie ); fclose( pFile ); return NULL; } subHeaderMagic = (unsigned long)subHeader[0] << 24 | (unsigned long)subHeader[1] << 16 | (unsigned long)subHeader[2] << 8 | (unsigned long)subHeader[3]; subHeaderSize = (unsigned short)subHeader[4] << 8 | (unsigned short)subHeader[5]; //header fits into gap to frame start if( subHeaderSize >= 6 && ftell( pFile ) + subHeaderSize - 6 <= (long)headerFramePtr ) { //info header if( subHeaderMagic == 0x696E666F ) //'i' 'n' 'f' 'o' { //read rest of info header pInfoHeader = (unsigned char *)malloc( subHeaderSize - 6 ); if( pInfoHeader == NULL ) { BlinkenMovieFree( pMovie ); fclose( pFile ); return NULL; } if( fread( pInfoHeader, 1, subHeaderSize - 6, pFile ) != (unsigned short)(subHeaderSize - 6) ) { free( pInfoHeader ); BlinkenMovieFree( pMovie ); fclose( pFile ); return NULL; } //parse information if( (pInfoHeaderX = memchr( pInfoHeader, 0, subHeaderSize - 6 )) != NULL ) { pInfoHeaderX++; len = pInfoHeaderX - pInfoHeader; if( memchr( pInfoHeaderX, 0, subHeaderSize - 6 - len ) != NULL ) BlinkenMovieAppendInfo( pMovie, pInfoHeader, pInfoHeaderX ); } free( pInfoHeader ); } //unknown subHeader else //skip fseek( pFile, subHeaderSize - 6, SEEK_CUR ); } //if( ftell( pFile ) ... } //while( ftell( pFile ) ... //seek to start of frames fseek( pFile, headerFramePtr, SEEK_SET ); //read frame start marker if( fread( frameStartMarker, 1, 4, pFile ) != 4 ) { BlinkenMovieFree( pMovie ); fclose( pFile ); return NULL; } frameStartMarkerMagic = (unsigned long)frameStartMarker[0] << 24 | (unsigned long)frameStartMarker[1] << 16 | (unsigned long)frameStartMarker[2] << 8 | (unsigned long)frameStartMarker[3]; if( frameStartMarkerMagic != 0x66726D73 ) //'f' 'r' 'm' 's' { BlinkenMovieFree( pMovie ); fclose( pFile ); return NULL; } //allocate buffer for frame data len = 2 + headerHeight * headerWidth * headerChannels; pFrameData = (unsigned char *)malloc( len ); if( pFrameData == NULL ) { BlinkenMovieFree( pMovie ); fclose( pFile ); return NULL; } //read frames for( ; ; ) { //read frame if( fread( pFrameData, 1, len, pFile ) != (unsigned int)len ) break; duration = (unsigned short)pFrameData[0] << 8 | (unsigned short)pFrameData[1]; //build frame and append it to movie pFrame = BlinkenFrameNew( headerHeight, headerWidth, headerChannels, headerMaxval, duration ); if( pFrame == NULL ) break; i = 2; for( y = 0; y < headerHeight; y++ ) for( x = 0; x < headerWidth; x++ ) for( c = 0; c < headerChannels; c++, i++ ) BlinkenFrameSetPixel( pFrame, y, x, c, pFrameData[i] ); if( BlinkenMovieAppendFrame( pMovie, pFrame ) != 0 ) { BlinkenFrameFree( pFrame ); pFrame = NULL; } } //for( ; ; ) //free buffer for frame data free( pFrameData ); //close file fclose( pFile ); return pMovie; } stBlinkenMovie * BlinkenMovieLoad( char * pFilename ) { int len; if( pFilename == NULL ) return NULL; len = strlen( pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".blm" ) == 0 ) return BlinkenMovieLoadBlm( pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".bmm" ) == 0 ) return BlinkenMovieLoadBmm( pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".bml" ) == 0 ) return BlinkenMovieLoadBml( pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".bbm" ) == 0 ) return BlinkenMovieLoadBbm( pFilename ); return NULL; } int BlinkenMovieSaveBlm( stBlinkenMovie * pMovie, char * pFilename ) { stBlinkenMovie * pOutMovie; FILE * pFile; int i, y, x; if( pMovie == NULL || pFilename == NULL ) return -1; //convert movie to suitable format pOutMovie = BlinkenMovieClone( pMovie ); if( pOutMovie == NULL ) return -1; BlinkenMovieResize( pOutMovie, pOutMovie->height, pOutMovie->width, 1, 1 ); //open file pFile = fopen( pFilename, "wt" ); if( pFile == NULL ) { BlinkenMovieFree( pOutMovie ); return -1; } //write header line fprintf( pFile, "# BlinkenLights Movie %ux%u\n", pOutMovie->width, pOutMovie->height ); //write information lines for( i = 0; i < pOutMovie->infoCnt; i++ ) fprintf( pFile, "# %s = %s\n", pOutMovie->pppInfos[i][0], pOutMovie->pppInfos[i][1] ); //write frames for( i = 0; i < pOutMovie->frameCnt; i++ ) { fprintf( pFile, "\n@%u\n", BlinkenFrameGetDuration( pOutMovie->ppFrames[i] ) ); for( y = 0; y < pOutMovie->height; y++ ) { for( x = 0; x < pOutMovie->width; x++ ) { if( BlinkenFrameGetPixel( pOutMovie->ppFrames[i], y, x, 0 ) != 0 ) fprintf( pFile, "1" ); else fprintf( pFile, "0" ); } fprintf( pFile, "\n" ); } } //close file fclose( pFile ); //free copied movie BlinkenMovieFree( pOutMovie ); //success return 0; } int BlinkenMovieSaveBmm( stBlinkenMovie * pMovie, char * pFilename ) { stBlinkenMovie * pOutMovie; FILE * pFile; int i, y, x; if( pMovie == NULL || pFilename == NULL ) return -1; //convert movie to suitable format pOutMovie = BlinkenMovieClone( pMovie ); if( pOutMovie == NULL ) return -1; BlinkenMovieResize( pOutMovie, pOutMovie->height, pOutMovie->width, 1, 255 ); //open file pFile = fopen( pFilename, "wt" ); if( pFile == NULL ) { BlinkenMovieFree( pOutMovie ); return -1; } //write header line fprintf( pFile, "# BlinkenMini Movie %ux%u\n", pOutMovie->width, pOutMovie->height ); //write information lines for( i = 0; i < pOutMovie->infoCnt; i++ ) fprintf( pFile, "# %s = %s\n", pOutMovie->pppInfos[i][0], pOutMovie->pppInfos[i][1] ); //write frames for( i = 0; i < pOutMovie->frameCnt; i++ ) { fprintf( pFile, "\n@%u\n", BlinkenFrameGetDuration( pOutMovie->ppFrames[i] ) ); for( y = 0; y < pOutMovie->height; y++ ) { fprintf( pFile, "0x%02X", BlinkenFrameGetPixel( pOutMovie->ppFrames[i], y, 0, 0 ) ); for( x = 1; x < pOutMovie->width; x++ ) fprintf( pFile, " 0x%02X", BlinkenFrameGetPixel( pOutMovie->ppFrames[i], y, x, 0 ) ); fprintf( pFile, "\n" ); } } //close file fclose( pFile ); //free copied movie BlinkenMovieFree( pOutMovie ); //success return 0; } int BlinkenMovieSaveBml( stBlinkenMovie * pMovie, char * pFilename ) { stBlinkenMovie * pOutMovie; FILE * pFile; int bits, val, i, y, x, c; if( pMovie == NULL || pFilename == NULL ) return -1; //convert movie to suitable format pOutMovie = BlinkenMovieClone( pMovie ); if( pOutMovie == NULL ) return -1; val = pOutMovie->maxval; //get number of bits for( bits = 0; val != 0; val >>= 1, bits++ ); BlinkenMovieResize( pOutMovie, pOutMovie->height, pOutMovie->width, pOutMovie->channels, (1 << bits) - 1 ); //open file pFile = fopen( pFilename, "wt" ); if( pFile == NULL ) { BlinkenMovieFree( pOutMovie ); return -1; } //write header line fprintf( pFile, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); //write blm start tag fprintf( pFile, "<blm width=\"%u\" height=\"%u\" bits=\"%u\" channels=\"%u\">\n", pOutMovie->width, pOutMovie->height, bits, pOutMovie->channels ); //write information lines fprintf( pFile, "\t<header>\n" ); for( i = 0; i < pOutMovie->infoCnt; i++ ) { if( strcmp( pOutMovie->pppInfos[i][0], "title" ) == 0 ) fprintf( pFile, "\t\t<title>%s</title>\n", pOutMovie->pppInfos[i][1] ); else if( strcmp( pOutMovie->pppInfos[i][0], "description" ) == 0 ) fprintf( pFile, "\t\t<description>%s</description>\n", pOutMovie->pppInfos[i][1] ); else if( strcmp( pOutMovie->pppInfos[i][0], "creator" ) == 0 ) fprintf( pFile, "\t\t<creator>%s</creator>\n", pOutMovie->pppInfos[i][1] ); else if( strcmp( pOutMovie->pppInfos[i][0], "author" ) == 0) fprintf( pFile, "\t\t<author>%s</author>\n", pOutMovie->pppInfos[i][1] ); else if( strcmp( pOutMovie->pppInfos[i][0], "email" ) == 0) fprintf( pFile, "\t\t<email>%s</email>\n", pOutMovie->pppInfos[i][1] ); else if( strcmp( pOutMovie->pppInfos[i][0], "url" ) == 0) fprintf( pFile, "\t\t<url>%s</url>\n", pOutMovie->pppInfos[i][1] ); else fprintf( pFile, "\t\t<description>%s: %s</description>\n", pOutMovie->pppInfos[i][0], pOutMovie->pppInfos[i][1] ); } fprintf( pFile, "\t</header>\n" ); //write frames for( i = 0; i < pOutMovie->frameCnt; i++ ) { fprintf( pFile, "\n\t<frame duration=\"%u\">\n", BlinkenFrameGetDuration( pOutMovie->ppFrames[i] ) ); for( y = 0; y < pOutMovie->height; y++ ) { fprintf( pFile, "\t\t<row>" ); for( x = 0; x < pOutMovie->width; x++ ) for( c = 0; c < pOutMovie->channels; c++ ) fprintf( pFile, bits > 4 ? "%02X" : "%01X", BlinkenFrameGetPixel( pOutMovie->ppFrames[i], y, x, c ) ); fprintf( pFile, "</row>\n" ); } fprintf( pFile, "\t</frame>\n" ); } //write blm end tag fprintf( pFile, "</blm>\n" ); //close file fclose( pFile ); //free copied movie BlinkenMovieFree( pOutMovie ); //success return 0; } int BlinkenMovieSaveBbm( stBlinkenMovie * pMovie, char * pFilename ) { unsigned char * pFrameData; FILE * pFile; unsigned char header[24], infoHeader[6], framePointer[4], frameStartMarker[4]; int duration, len, len0, len1, i, j, y, x, c, val; long pos; if( pMovie == NULL || pFilename == NULL ) return -1; //allocate frame data buffer pFrameData = (unsigned char *)malloc( 2 + pMovie->height * pMovie->width * pMovie->channels ); if( pFrameData == NULL ) return -1; //open file pFile = fopen( pFilename, "wb" ); if( pFile == NULL ) { free( pFrameData ); return -1; } //write header header[0] = 0x23; //magic header[1] = 0x54; header[2] = 0x26; header[3] = 0x66; header[4] = (unsigned char)(pMovie->height >> 8); header[5] = (unsigned char)pMovie->height; header[6] = (unsigned char)(pMovie->width >> 8); header[7] = (unsigned char)pMovie->width; header[8] = (unsigned char)(pMovie->channels >> 8); header[9] = (unsigned char)pMovie->channels; header[10] = (unsigned char)(pMovie->maxval >> 8); header[11] = (unsigned char)pMovie->maxval; header[12] = (unsigned char)(pMovie->frameCnt >> 24); header[13] = (unsigned char)(pMovie->frameCnt >> 16); header[14] = (unsigned char)(pMovie->frameCnt >> 8); header[15] = (unsigned char)pMovie->frameCnt; duration = 0; for( i = 0; i < pMovie->frameCnt; i++ ) duration += BlinkenFrameGetDuration( pMovie->ppFrames[i] ); header[16] = (unsigned char)(duration >> 24); header[17] = (unsigned char)(duration >> 16); header[18] = (unsigned char)(duration >> 8); header[19] = (unsigned char)duration; header[20] = 0; //frame pointer is written later header[21] = 0; header[22] = 0; header[23] = 0; fwrite( header, 1, 24, pFile ); //write information for( i = 0; i < pMovie->infoCnt; i++ ) { len0 = strlen( pMovie->pppInfos[i][0] ); if( len0 > 32760 ) len0 = 32760; len1 = strlen( pMovie->pppInfos[i][1] ); if( len1 > 32760 ) len1 = 32760; len = 8 + len0 + len1; infoHeader[0] = 0x69; //'i' infoHeader[1] = 0x6E; //'n' infoHeader[2] = 0x66; //'f' infoHeader[3] = 0x6F; //'o' infoHeader[4] = (unsigned char)(len >> 8); infoHeader[5] = (unsigned char)len; fwrite( infoHeader, 1, 6, pFile ); fwrite( pMovie->pppInfos[i][0], 1, len0, pFile ); fwrite( "\0", 1, 1, pFile ); fwrite( pMovie->pppInfos[i][1], 1, len1, pFile ); fwrite( "\0", 1, 1, pFile ); } //write frame pointer pos = ftell( pFile ); framePointer[0] = (unsigned char)(pos >> 24); framePointer[1] = (unsigned char)(pos >> 16); framePointer[2] = (unsigned char)(pos >> 8); framePointer[3] = (unsigned char)pos; fseek( pFile, 20, SEEK_SET ); fwrite( framePointer, 1, 4, pFile ); fseek( pFile, pos, SEEK_SET ); //write frame start marker frameStartMarker[0] = 0x66; //'f' frameStartMarker[1] = 0x72; //'r' frameStartMarker[2] = 0x6D; //'m' frameStartMarker[3] = 0x73; //'s' fwrite( frameStartMarker, 1, 4, pFile ); //write frames for( i = 0; i < pMovie->frameCnt; i++ ) { val = BlinkenFrameGetDuration( pMovie->ppFrames[i] ); pFrameData[0] = (unsigned char)(val >> 8); pFrameData[1] = (unsigned char)val; for( j = 2, y = 0; y < pMovie->height; y++ ) for( x = 0; x < pMovie->width; x++ ) for( c = 0; c < pMovie->channels; c++, j++ ) pFrameData[j] = BlinkenFrameGetPixel( pMovie->ppFrames[i], y, x, c ); fwrite( pFrameData, 1, j, pFile ); } //free frame data buffer free( pFrameData ); //close file fclose( pFile ); //success return 0; } int BlinkenMovieSave( stBlinkenMovie * pMovie, char * pFilename ) { int len; if( pMovie == NULL || pFilename == NULL ) return -1; len = strlen( pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".blm" ) == 0 ) return BlinkenMovieSaveBlm( pMovie, pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".bmm" ) == 0 ) return BlinkenMovieSaveBmm( pMovie, pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".bml" ) == 0 ) return BlinkenMovieSaveBml( pMovie, pFilename ); if( len > 4 && strcmp( pFilename + len - 4, ".bbm" ) == 0 ) return BlinkenMovieSaveBbm( pMovie, pFilename ); return -1; } void BlinkenMovieSend( stBlinkenMovie * pMovie, int udpSocket, etBlinkenProto proto ) //udp socket must be "connected" { int i, len; char buffer[65536]; //64kB is more tham maximum UDP size for( i = 0; i < pMovie->frameCnt; i++ ) { len = BlinkenFrameToNetwork( pMovie->ppFrames[i], proto, buffer, sizeof( buffer ) ); if( len > 0 ) send( udpSocket, buffer, len, 0 ); usleep( BlinkenFrameGetDuration( pMovie->ppFrames[i] ) * 1000 ); } } stBlinkenMovie * BlinkenMovieReceive( int udpSocket, int timeout, etBlinkenProto * pProto ) //udp socket must be "bound" and should be "connected" //after timeout ms of no reception, the movie is considered to be complete //returns protocol in *pProto if pProto not NULL { stBlinkenMovie * pMovie; stBlinkenFrame * pLastFrame, * pFrame; etBlinkenProto proto, p; fd_set readFds; struct timeval timeo, lastTime, curTime; char buffer[65536]; //64kB is more tham maximum UDP size int len; //correct timeout if( timeout < 0 ) timeout = 0; //wait for frames pMovie = NULL; proto = BlinkenProtoNone; pLastFrame = NULL; for( ; ; ) { //wait for next frame FD_ZERO( &readFds ); FD_SET( udpSocket, &readFds ); timeo.tv_sec = timeout / 1000; timeo.tv_usec = (timeout % 1000) * 1000; if( select( udpSocket + 1, &readFds, NULL, NULL, &timeo ) <= 0 ) //timeout or error break; //fetch data len = recv( udpSocket, buffer, sizeof( buffer ), 0 ); if( len <= 0 ) break; //get frame from data pFrame = BlinkenFrameFromNetwork( buffer, len, &p ); if( pFrame != NULL ) { //valid protocol if( p != BlinkenProtoNone ) { //first frame if( proto == BlinkenProtoNone ) proto = p; //use this protocol //protocol matches if( p == proto ) { //no movie yet if( pMovie == NULL ) { //allocate a new movie pMovie = BlinkenMovieNew( BlinkenFrameGetHeight( pFrame ), BlinkenFrameGetWidth( pFrame ), BlinkenFrameGetChannels( pFrame ), BlinkenFrameGetMaxval( pFrame ) ); if( pMovie == NULL ) { BlinkenFrameFree( pFrame ); break; } } //append frame to movie if( BlinkenMovieAppendFrame( pMovie, pFrame ) == 0 ) { //get current time gettimeofday( &curTime, NULL ); //set duration of last frame if( pLastFrame != NULL ) BlinkenFrameSetDuration( pLastFrame, (curTime.tv_sec - lastTime.tv_sec) * 1000 + (curTime.tv_usec - lastTime.tv_usec) / 1000 ); //remember this frame as last frame appended to movie pLastFrame = pFrame; pFrame = NULL; //do not free this frame (it was appended) lastTime = curTime; //remember time of this frame } } //if( p == proto ) } //if( p != BlinkenProtoNone ) //free frame if it was not appended if( pFrame != NULL ) BlinkenFrameFree( pFrame ); } //if( pFrame != NULL ) } //for( ; ; ) //get current time gettimeofday( &curTime, NULL ); //set duration of last frame if( pLastFrame != NULL ) BlinkenFrameSetDuration( pLastFrame, (curTime.tv_sec - lastTime.tv_sec) * 1000 + (curTime.tv_usec - lastTime.tv_usec) / 1000 ); //return protocol if( pProto != NULL ) *pProto = proto; //return movie return pMovie; }