BlinkenArea - GitList
Repositories
Blog
Wiki
BlinkenLib
Code
Commits
Branches
Tags
Search
Tree:
e71a0ff
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
src
BlinkenMovie.c
move msleep and get_ms to tools, make public
Stefan Schuermans
commited
e71a0ff
at 2023-08-18 09:57:23
BlinkenMovie.c
Blame
History
Raw
/* BlinkenLib Copyright 2004-2023 Stefan Schuermans <stefan@schuermans.info> Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html a blinkenarea.org project */ #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef WIN32 #include <windows.h> #include <winsock2.h> #else #include <sys/select.h> #include <sys/socket.h> #include <sys/time.h> #include <sys/types.h> #include <unistd.h> #endif #include <BlinkenLib/BlinkenFrame.h> #include <BlinkenLib/BlinkenMovie.h> #include "BlinkenConstants.h" #include "Tools.h" #ifdef BLINKENLIB_CFG_MNG #include "BlinkenMng.h" #endif // #ifdef BLINKENLIB_CFG_MNG #ifdef BLINKENLIB_CFG_GIF #include "BlinkenGif.h" #endif // #ifdef BLINKENLIB_CFG_GIF 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 ***)BlinkenMalloc2D(0, 2, sizeof(char *)); if (pMovie->pppInfos == NULL) { free(pMovie); return NULL; } pMovie->frameCnt = 0; pMovie->ppFrames = (stBlinkenFrame **)BlinkenMalloc1D(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, const char *pInfoType, const 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, const char *pInfoType, const char *pInfoData) { char ***pppNewInfos, *pType, *pData; int i; if (pMovie == NULL || infoNo < 0 || infoNo > pMovie->infoCnt) return; pppNewInfos = (char ***)BlinkenMalloc2D(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, const char *pInfoType, const 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 ***)BlinkenMalloc2D(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 ***)BlinkenMalloc2D(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 **)BlinkenMalloc1D(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 **)BlinkenMalloc1D(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 **)BlinkenMalloc1D(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; } int BlinkenMovieConcat(stBlinkenMovie *pMovie, stBlinkenMovie *pMovie2 /* appended and freed */) { stBlinkenFrame **ppNewFrames, **ppNewFrames2; int i; if (pMovie == NULL || pMovie2 == NULL) return -1; BlinkenMovieResize(pMovie2, pMovie->height, pMovie->width, pMovie->channels, pMovie->maxval); ppNewFrames = (stBlinkenFrame **)BlinkenMalloc1D( pMovie->frameCnt + pMovie2->frameCnt, sizeof(stBlinkenFrame *)); if (ppNewFrames == NULL) return -1; ppNewFrames2 = (stBlinkenFrame **)BlinkenMalloc1D(0, sizeof(stBlinkenFrame *)); if (ppNewFrames2 == NULL) { free(ppNewFrames); return -1; } for (i = 0; i < pMovie->frameCnt; i++) ppNewFrames[i] = pMovie->ppFrames[i]; for (i = 0; i < pMovie2->frameCnt; i++) ppNewFrames[pMovie->frameCnt + i] = pMovie2->ppFrames[i]; free(pMovie->ppFrames); pMovie->ppFrames = ppNewFrames; pMovie->frameCnt += pMovie2->frameCnt; free(pMovie2->ppFrames); pMovie2->ppFrames = ppNewFrames2; pMovie2->frameCnt = 0; BlinkenMovieFree(pMovie2); return 0; } void BlinkenMovieReverse(stBlinkenMovie *pMovie) { int i, j; stBlinkenFrame *pFrame; for (i = 0, j = pMovie->frameCnt - 1; i < pMovie->frameCnt / 2; i++, j--) { pFrame = pMovie->ppFrames[i]; pMovie->ppFrames[i] = pMovie->ppFrames[j]; pMovie->ppFrames[j] = pFrame; } } void BlinkenMovieCutTime(stBlinkenMovie *pMovie, int begin /* in ms */, int end /* in ms */) { int i, duration, curtime, idx_begin, idx_end, duration_begin, duration_end; int frameCnt; stBlinkenFrame **ppNewFrames; // do nothing if no movie or empty movie if (pMovie == NULL || pMovie->frameCnt < 1) return; // get movie duration duration = 0; for (i = 0; i < pMovie->frameCnt; i++) duration += BlinkenFrameGetDuration(pMovie->ppFrames[i]); // sanitize inputs if (begin < 0) begin = 0; if (begin > duration) begin = duration; if (end < begin) end = begin; if (end > duration) end = duration; // get begin and end indices, also get duration of begin and end frames if (begin >= end) { // empty result movie idx_begin = 1; idx_end = 0; duration_begin = 0; duration_end = 0; } else { // at least one frame in result movie curtime = 0; idx_begin = 0; duration_begin = BlinkenFrameGetDuration(pMovie->ppFrames[idx_begin]); idx_end = pMovie->frameCnt - 1; duration_end = BlinkenFrameGetDuration(pMovie->ppFrames[idx_end]); for (i = 0; i < pMovie->frameCnt; i++) { duration = BlinkenFrameGetDuration(pMovie->ppFrames[i]); // begin and end in current frame if (curtime <= begin && curtime + duration >= end) { idx_begin = i; idx_end = i; duration_begin = end - begin; duration_end = end - begin; break; } // begin in current frame if (curtime <= begin && curtime + duration > begin) { idx_begin = i; duration_begin = curtime + duration - begin; } // end in current frame if (curtime < end && curtime + duration >= end) { idx_end = i; duration_end = end - curtime; break; } curtime += duration; } } // remove/free unneeded frames frameCnt = idx_end - idx_begin + 1; ppNewFrames = (stBlinkenFrame **)BlinkenMalloc1D(frameCnt, sizeof(stBlinkenFrame *)); if (ppNewFrames == NULL) return; for (i = 0; i < idx_begin; i++) BlinkenFrameFree(pMovie->ppFrames[i]); for (; i <= idx_end; i++) ppNewFrames[i - idx_begin] = pMovie->ppFrames[i]; for (; i < pMovie->frameCnt; i++) BlinkenFrameFree(pMovie->ppFrames[i]); free(pMovie->ppFrames); pMovie->ppFrames = ppNewFrames; pMovie->frameCnt = frameCnt; // change duration of begin and end frame if (frameCnt > 0) { BlinkenFrameSetDuration(pMovie->ppFrames[0], duration_begin); BlinkenFrameSetDuration(pMovie->ppFrames[frameCnt - 1], duration_end); } } void BlinkenMovieAdaptDuration(stBlinkenMovie *pMovie, int duration /* in ms */) { int old_duration, old_curtime, curtime; int i, old_dur, dur, old_end, end; // do nothing if no movie, empty movie or invalid duration if (pMovie == NULL || pMovie->frameCnt < 1 || duration <= 0) return; // get movie duration old_duration = 0; for (i = 0; i < pMovie->frameCnt; i++) old_duration += BlinkenFrameGetDuration(pMovie->ppFrames[i]); // adapt duration of frames old_curtime = 0; curtime = 0; for (i = 0; i < pMovie->frameCnt; i++) { // get old end time of current frame old_dur = BlinkenFrameGetDuration(pMovie->ppFrames[i]); old_end = old_curtime + old_dur; // compute new end time and new duration end = (int)((double)old_end / (double)old_duration * (double)duration + 0.5); dur = end - curtime; if (dur < BlinkenDurationMin) dur = BlinkenDurationMin; if (dur > BlinkenDurationMax) dur = BlinkenDurationMax; // update frame duration BlinkenFrameSetDuration(pMovie->ppFrames[i], dur); // advance time old_curtime += old_dur; curtime += dur; } } void BlinkenMovieAdaptMaxFrameDuration(stBlinkenMovie *pMovie, int maxDuration /* in ms */) { int i, j, cmp, dur, lastdur; unsigned int extraFrames; stBlinkenFrame **ppNewFrames; stBlinkenFrame *pNewFrame; if (pMovie == NULL) return; if (maxDuration < BlinkenDurationMin) { maxDuration = BlinkenDurationMin; } if (maxDuration > BlinkenDurationMax) { maxDuration = BlinkenDurationMax; } // compute how many extra frames are needed extraFrames = 0; for (i = 0; i < pMovie->frameCnt; i++) { dur = BlinkenFrameGetDuration(pMovie->ppFrames[i]); extraFrames += (dur + maxDuration - 1) / maxDuration - 1; } // allocate new frame array ppNewFrames = (stBlinkenFrame **)BlinkenMalloc1D( pMovie->frameCnt + extraFrames, sizeof(stBlinkenFrame *)); if (!ppNewFrames) { return; } // merge/split frames in time j = 0; for (i = 0; i < pMovie->frameCnt; i++) { // join frame with last one if equal if (j > 0) { cmp = BlinkenFrameCompare(pMovie->ppFrames[i], ppNewFrames[j - 1]); if (cmp == 0) { // frame equal to last one dur = BlinkenFrameGetDuration(pMovie->ppFrames[i]); lastdur = BlinkenFrameGetDuration(ppNewFrames[j - 1]); if (lastdur + dur <= maxDuration) { // merge frame completely BlinkenFrameSetDuration(ppNewFrames[j - 1], lastdur + dur); BlinkenFrameFree(pMovie->ppFrames[i]); pMovie->ppFrames[i] = NULL; continue; // frame completely merged } else { // move as much duration to previous frame BlinkenFrameSetDuration(ppNewFrames[j - 1], maxDuration); BlinkenFrameSetDuration(pMovie->ppFrames[i], lastdur + dur - maxDuration); } } } // split frames longer than maxDuration while (1) { dur = BlinkenFrameGetDuration(pMovie->ppFrames[i]); if (dur <= maxDuration) { break; } pNewFrame = BlinkenFrameClone(pMovie->ppFrames[i]); if (!pNewFrame) { break; } // add new frame with max duration BlinkenFrameSetDuration(pNewFrame, maxDuration); ppNewFrames[j++] = pNewFrame; // reduce duration of current frame BlinkenFrameSetDuration(pMovie->ppFrames[i], dur - maxDuration); } // while (1) // overtake current frame ppNewFrames[j++] = pMovie->ppFrames[i]; pMovie->ppFrames[i] = NULL; } // for (i ... // use new frames array in movie free(pMovie->ppFrames); pMovie->ppFrames = ppNewFrames; pMovie->frameCnt = j; } 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 BlinkenMovieCrop(stBlinkenMovie *pMovie, int top, int left, int height, int width) { int i; if (pMovie == NULL) return; if (top < 0) top = 0; if (top > pMovie->height - BlinkenHeightMin) top = pMovie->height - BlinkenHeightMin; if (height < BlinkenHeightMin) height = BlinkenHeightMin; if (height > pMovie->height - top) height = pMovie->height - top; if (left < 0) left = 0; if (left > pMovie->width - BlinkenWidthMin) left = pMovie->width - BlinkenWidthMin; if (width < BlinkenWidthMin) width = BlinkenWidthMin; if (width > pMovie->width - left) width = pMovie->width - left; if (top == 0 && left == 0 && height == pMovie->height && width == pMovie->width) return; pMovie->height = height; pMovie->width = width; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameCrop(pMovie->ppFrames[i], top, left, height, width); } 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); } void BlinkenMovieColorize(stBlinkenMovie *pMovie, int channels, int mode) { int i, step; if (pMovie == NULL) return; if (channels < BlinkenChannelsMin) channels = BlinkenChannelsMin; if (channels > BlinkenChannelsMax) channels = BlinkenMaxvalMax; pMovie->channels = channels; pMovie->maxval = BlinkenMaxvalMax; step = 0; for (i = 0; i < pMovie->frameCnt; i++) { BlinkenFrameColorize(pMovie->ppFrames[i], channels, mode, step); step += BlinkenFrameGetDuration(pMovie->ppFrames[i]); } } void BlinkenMovieCopyRect(stBlinkenMovie *pDest, int destY, int destX, stBlinkenMovie *pSrc, int srcY, int srcX, int height, int width) { int dcnt, scnt, di, si, dest_dur, src_dur, src_time_ofs; stBlinkenFrame *pFrame; if (pDest == NULL || pSrc == NULL) return; // exit if both movies empty dcnt = pDest->frameCnt; scnt = pSrc->frameCnt; if (dcnt == 0 || scnt == 0) return; // go throuh all source frames di = 0; si = 0; dest_dur = dcnt > 0 ? BlinkenFrameGetDuration(pDest->ppFrames[0]) : 0; src_dur = scnt > 0 ? BlinkenFrameGetDuration(pSrc->ppFrames[0]) : 0; src_time_ofs = 0; while (si < scnt) { // make sure there is a frame in destination movie if (di >= dcnt) { // append new empty frame that last until end of source frame pFrame = BlinkenFrameNew(pDest->height, pDest->width, pDest->channels, pDest->maxval, src_dur - src_time_ofs); if (pFrame == NULL) return; BlinkenFrameClear(pFrame); if (BlinkenMovieAppendFrame(pDest, pFrame) != 0) return; dcnt++; dest_dur = src_dur - src_time_ofs; } // make sure destination frame does not last longer than source frame if (dest_dur > src_dur - src_time_ofs) { // split destination frame into two pFrame = BlinkenFrameClone(pDest->ppFrames[di]); if (pFrame == NULL) return; if (BlinkenMovieInsertFrame(pDest, di + 1, pFrame) != 0) return; dcnt++; BlinkenFrameSetDuration(pDest->ppFrames[di], src_dur - src_time_ofs); BlinkenFrameSetDuration(pDest->ppFrames[di + 1], dest_dur - (src_dur - src_time_ofs)); dest_dur = src_dur - src_time_ofs; } // copy from source frame to destination frame BlinkenFrameCopyRect(pDest->ppFrames[di], destY, destX, pSrc->ppFrames[si], srcY, srcX, height, width); src_time_ofs += dest_dur; di++; dest_dur = di < dcnt ? BlinkenFrameGetDuration(pDest->ppFrames[di]) : 0; // go to next source frame if (src_time_ofs >= src_dur) { si++; src_dur = si < scnt ? BlinkenFrameGetDuration(pSrc->ppFrames[si]) : 0; src_time_ofs = 0; } } // while (si < scnt) } void BlinkenMovieRotateCw(stBlinkenMovie *pMovie) { int tmp, i; if (pMovie == NULL) return; tmp = pMovie->height; pMovie->height = pMovie->width; pMovie->width = tmp; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameRotateCw(pMovie->ppFrames[i]); } void BlinkenMovieRotateCcw(stBlinkenMovie *pMovie) { int tmp, i; if (pMovie == NULL) return; tmp = pMovie->height; pMovie->height = pMovie->width; pMovie->width = tmp; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameRotateCcw(pMovie->ppFrames[i]); } void BlinkenMovieRotateHalf(stBlinkenMovie *pMovie) { int i; if (pMovie == NULL) return; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameRotateHalf(pMovie->ppFrames[i]); } void BlinkenMovieMirrorHor(stBlinkenMovie *pMovie) { int i; if (pMovie == NULL) return; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameMirrorHor(pMovie->ppFrames[i]); } void BlinkenMovieMirrorVer(stBlinkenMovie *pMovie) { int i; if (pMovie == NULL) return; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameMirrorVer(pMovie->ppFrames[i]); } void BlinkenMovieMirrorDiag(stBlinkenMovie *pMovie) { int tmp, i; if (pMovie == NULL) return; tmp = pMovie->height; pMovie->height = pMovie->width; pMovie->width = tmp; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameMirrorDiag(pMovie->ppFrames[i]); } void BlinkenMovieMirrorDiag2(stBlinkenMovie *pMovie) { int tmp, i; if (pMovie == NULL) return; tmp = pMovie->height; pMovie->height = pMovie->width; pMovie->width = tmp; for (i = 0; i < pMovie->frameCnt; i++) BlinkenFrameMirrorDiag2(pMovie->ppFrames[i]); } char *BlinkenMovieToString(stBlinkenMovie *pMovie) { char **strs, *str, *ptr; int i, size; if (pMovie == NULL) return NULL; strs = (char **)BlinkenMalloc1D(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 + 1); 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(const 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, // set pixel (unsigned char)(pixel[0] == '1' ? 1 : 0)); 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(const 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, // set pixel (unsigned char)val); if (fscanf(pFile, "%*[ \t]") != 0) // kill space break; 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(const 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[24], 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 if (fscanf(pFile, "%*[^<]") != 0) // end loop (error) break; // 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 // read max 5 chars (2 already in use by prefix) sprintf(pixelFormat, "%%%d[0-9A-Fa-f]", chrs > 4 ? 5 : chrs); // 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(const char *pFilename) { FILE *pFile; stBlinkenMovie *pMovie; stBlinkenFrame *pFrame; unsigned char header[24], subHeader[6], frameStartMarker[4]; unsigned long headerMagic, headerFramePtr; unsigned short headerHeight, headerWidth, headerChannels, headerMaxval; unsigned long subHeaderMagic, frameStartMarkerMagic; unsigned short subHeaderSize; char *pInfoHeader, *pInfoHeaderX; unsigned char *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]; 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 = (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; } #ifdef BLINKENLIB_CFG_MNG stBlinkenMovie *BlinkenMovieLoadMng(const char *pFilename) { return BlinkenMngLoad(pFilename); } #endif // #ifdef BLINKENLIB_CFG_MNG #ifdef BLINKENLIB_CFG_GIF stBlinkenMovie *BlinkenMovieLoadGif(const char *pFilename) { return BlinkenGifLoad(pFilename); } #endif // #ifdef BLINKENLIB_CFG_GIF stBlinkenMovie *BlinkenMovieLoad(const 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); #ifdef BLINKENLIB_CFG_MNG if (len > 4 && strcmp(pFilename + len - 4, ".mng") == 0) return BlinkenMovieLoadMng(pFilename); #endif // #ifdef BLINKENLIB_CFG_MNG #ifdef BLINKENLIB_CFG_GIF if (len > 4 && strcmp(pFilename + len - 4, ".gif") == 0) return BlinkenMovieLoadGif(pFilename); #endif // #ifdef BLINKENLIB_CFG_GIF return NULL; } int BlinkenMovieSaveBlm(stBlinkenMovie *pMovie, const 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, const 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, const 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, const 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; } #ifdef BLINKENLIB_CFG_MNG int BlinkenMovieSaveMng(stBlinkenMovie *pMovie, const char *pFilename) { return BlinkenMngSave(pMovie, pFilename); } #endif // #ifdef BLINKENLIB_CFG_MNG #ifdef BLINKENLIB_CFG_GIF int BlinkenMovieSaveGif(stBlinkenMovie *pMovie, const char *pFilename) { return BlinkenGifSave(pMovie, pFilename); } #endif // #ifdef BLINKENLIB_CFG_GIF int BlinkenMovieSave(stBlinkenMovie *pMovie, const 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); #ifdef BLINKENLIB_CFG_MNG if (len > 4 && strcmp(pFilename + len - 4, ".mng") == 0) return BlinkenMovieSaveMng(pMovie, pFilename); #endif // #ifdef BLINKENLIB_CFG_MNG #ifdef BLINKENLIB_CFG_GIF if (len > 4 && strcmp(pFilename + len - 4, ".gif") == 0) return BlinkenMovieSaveGif(pMovie, pFilename); #endif // #ifdef BLINKENLIB_CFG_GIF return -1; } void BlinkenMovieSend(stBlinkenMovie *pMovie, SOCKET udpSocket, etBlinkenProto proto, int maxidle) // udp socket must be "connected" // maxidle is the maximum idle time between two frames in ms (last frame is // repeated after this time), use 0 to turn off this feature { int i, len, duration, dur; char buffer[65536]; // 64kB is more than maximum UDP size for (i = 0; i < pMovie->frameCnt; i++) { len = BlinkenFrameToNetwork(pMovie->ppFrames[i], proto, buffer, sizeof(buffer)); duration = BlinkenFrameGetDuration(pMovie->ppFrames[i]); if (len > 0) { while (duration > 0) { send(udpSocket, buffer, len, 0); dur = maxidle > 0 ? mini(maxidle, duration) : duration; BlinkenMSleep(dur); duration -= dur; } } } } stBlinkenMovie *BlinkenMovieReceive(SOCKET 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; unsigned int lastTime, curTime; char buffer[65536]; // 64kB is more than maximum UDP size int len; // correct timeout if (timeout < 0) timeout = 0; // wait for frames pMovie = NULL; proto = BlinkenProtoNone; pLastFrame = NULL; lastTime = BlinkenGetMs(); for (;;) { // wait for next frame FD_ZERO(&readFds); FD_SET(udpSocket, &readFds); timeo.tv_sec = timeout / 1000; timeo.tv_usec = (timeout % 1000) * 1000; // timeout or error if (select(udpSocket + 1, &readFds, NULL, NULL, &timeo) <= 0) 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; } } // ignore frame if it is equal to last one if (pMovie->frameCnt > 0) { if (BlinkenFrameCompare( pFrame, pMovie->ppFrames[pMovie->frameCnt - 1]) == 0) { BlinkenFrameFree(pFrame); continue; } } // append frame to movie if (BlinkenMovieAppendFrame(pMovie, pFrame) == 0) { // get current time curTime = BlinkenGetMs(); // set duration of last frame if (pLastFrame != NULL) BlinkenFrameSetDuration(pLastFrame, curTime - lastTime); // 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 curTime = BlinkenGetMs(); // set duration of last frame if (pLastFrame != NULL) BlinkenFrameSetDuration(pLastFrame, curTime - lastTime); // return protocol if (pProto != NULL) *pProto = proto; // return movie return pMovie; }