Commit aaa96476 authored by daFischer's avatar daFischer

Implemented more Messages, like FreehandAnnotation and CursorMessage

parent 9a7ee09f
......@@ -36,34 +36,41 @@ Audio::Audio(const char* path) {
return;
}
//Load our audio file from disk
string extension[4] = {".mp3", ".mp2", ".ogg", ".wav"};
string extension[EXTSIZE] = {".mp3", ".mp2", ".ogg", ".wav"};
ALboolean loop=false;
string filename;
for(int i=0;i<sizeof(extension);i++) //try loading audio of all possible extensions
for(int i=0;i<EXTSIZE;i++) //try loading audio of all possible extensions
{
filename=path+extension[i];
buffer=alutCreateBufferFromFile(filename.c_str());
if((error=alutGetError())==ALUT_ERROR_NO_ERROR)
break;
printf("Couldn't load %s: %d\n",filename.c_str(),error);
if(i == sizeof(extension) -1)
//printf("Couldn't load %s: %d\n",filename.c_str(),error);
if(i == EXTSIZE -1)
{
alDeleteBuffers(1, &buffer);
return;
}
}
alSourcei (source, AL_BUFFER, buffer);
if (alGetError() != AL_NO_ERROR)
if ((error=alGetError()) != AL_NO_ERROR)
{
printf("Audio last error\n");
printf("Audio error: %d\n",error);
return;
}
failed=false;
}
Audio::~Audio() {
alDeleteBuffers(1,&buffer);
alDeleteSources(1,&source);
alutExit();
}
void Audio::togglePlay(){
ALint state;
alGetSourcei(source, AL_SOURCE_STATE, &state);
......
......@@ -8,6 +8,8 @@
#ifndef AUDIO_H
#define AUDIO_H
#define EXTSIZE 4
#include <stdio.h>
#include <time.h>
#include <string>
......@@ -33,6 +35,7 @@ using namespace std;
class Audio: public AudioInterface{
public:
Audio(const char*);
~Audio();
void togglePlay();
int getPosition();
void setPosition(int pos);
......
......@@ -366,10 +366,10 @@ int ColorConverter::decodeColor(unsigned char* bytes, int byteNum, SDL_PixelForm
return color;
}
int ColorConverter::decodeColor8(int num){
/*int ColorConverter::decodeColor8(int num){
int color= (int)(colors[num][0]);
return color;
}
}*/
unsigned int ColorConverter::getAnnotationColor(int colorValue, SDL_PixelFormat* format){
......
......@@ -16,8 +16,8 @@ class ColorConverter {
public:
ColorConverter();
static unsigned int getAnnotationColor(int colorValue, SDL_PixelFormat* format);
int decodeColor(unsigned char* bytes, int byteNum, SDL_PixelFormat* format);
int decodeColor8(int num);
static int decodeColor(unsigned char* bytes, int byteNum, SDL_PixelFormat* format);
//int decodeColor8(int num);
private:
......
......@@ -10,6 +10,8 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define VERBOSE true
#define EXTENSION_INDEX_TABLE 1
#define EXTENSION_SEARCHBASE_TABLE_WITH_COORDINATES 2
......@@ -19,7 +21,6 @@
//message kinds
#define ANNOTATION 'a'
#define WHITEBOARD 'w'
#define EMPTY '0'
#define RAW 'r'
#define CURSOR 'c'
......
......@@ -57,6 +57,16 @@ Controls::Controls(Video* video, AudioInterface* audio) {
printf("font is ok\n");
}
Controls::~Controls() {
SDL_FreeSurface(surfPlay);
SDL_FreeSurface(surfVolume);
SDL_FreeSurface(surfVolume2);
SDL_FreeSurface(surfFullscreen);
TTF_CloseFont(font);
audio=NULL;
video=NULL;
}
void Controls::registerClick(Uint16 mx, Uint16 my){
if(my<y)
return;
......@@ -206,9 +216,10 @@ void Controls::draw(SDL_Surface *screen, bool hasDrawn){
SDL_Surface* times=TTF_RenderText_Solid(font,oss.str().c_str(),color);
redefineRect(&rect,192,y+timeLineHeight+4,times->w+4,times->h+4);
SDL_BlitSurface(times,NULL,screen,&rect);
SDL_FreeSurface(times);
if(mouseY>=y&&mouseY<y+timeLineHeight)
video->drawThumbnail(duration*mouseX/width,mouseX,y);
video->drawThumbnail(duration*mouseX/width*1000,mouseX,y);
SDL_UpdateRect(screen, 0,y,width,screenHeight-y);
//SDL_Flip(screen);
......
......@@ -30,6 +30,7 @@ using namespace std;
class Controls {
public:
Controls(Video* video, AudioInterface* audio);
~Controls();
void update();
void registerClick(Uint16 mx, Uint16 my);
void registerMouseUp();
......@@ -39,6 +40,13 @@ public:
SDL_Rect videoUpdate;
private:
void togglePlay();
void toggleFullscreen();
void skipTo(int position);
Uint32 emColor(Uint32);
void redefineRect(SDL_Rect* rect, int x, int y, int w, int h);
void changeVolume(float volume);
Video* video;
AudioInterface* audio;
......@@ -57,13 +65,6 @@ private:
SDL_Surface* surfVolume2;
SDL_Surface* surfFullscreen;
TTF_Font* font;
void togglePlay();
void toggleFullscreen();
void skipTo(int position);
Uint32 emColor(Uint32);
void redefineRect(SDL_Rect* rect, int x, int y, int w, int h);
void changeVolume(float volume);
};
//#ifdef EMSCRIPTEN
......
......@@ -15,72 +15,190 @@ Index::Index(Inflater* in, int numBytes) {
int searchableLength;
SizedArray* searchableArray;
SDL_Surface* image;
short entryNumber;
in->readShort(&entryNumber);
numBytes-=2;
for(int i=0;i<entryNumber;i++)
{
numBytes -= 2;
for (int i = 0; i < entryNumber; i++) {
in->readInt(&timestamp);
in->readByte((char*) &titleLength);
title=in->readCharArray(titleLength,true);
title[titleLength]=0;
title = in->readCharArray(titleLength, true);
title[titleLength] = 0;
in->readInt(&searchableLength);
searchableArray=new SizedArray(searchableLength);
searchableArray = new SizedArray(searchableLength);
in->readSizedArray(searchableArray);
numBytes-=9+titleLength+searchableLength;
image=readThumbnail(in, &numBytes);
index.push_back(new IndexEntry(title,timestamp,searchableArray,image));
numBytes -= 9 + titleLength + searchableLength;
image = readThumbnail(in, &numBytes);
index.push_back(new IndexEntry(title, timestamp, searchableArray, image));
}
if(numBytes>0)
{
if (numBytes > 0) {
printf("Index skipping %d bytes\n", numBytes);
in->skipBytes(numBytes);
}
it = index.begin();
//TODO: what if too many bytes have been read?
}
Index::Index(Message** messages, int numMessages) {
if (VERBOSE)
printf("\ncompute index table:\n");
// TODO: set as option
// possible slide should at least cover 20% of maximum size
int minSlideArea = ProtocolPreferences::framebufferWidth * ProtocolPreferences::framebufferHeight / 5;
// TODO: set as option
// there should be at least 5 or 10 sec between two slides
int minSlideDiffMsecs = 10000;
int minSequenceLength = 5;
// count sequence with gaps less than minSlideDiffMsecs
int animationCount = 0;
int timestamp = -minSlideDiffMsecs * 2;
int previous_timestamp = -1;
int area = 0;
// build index based on covered area
for (int i = 0; i < numMessages; i++) {
Message* message = messages[i];
// sum up area(s)
if (message->type == RAW) {
area += message->getArea();
//printf("%d,",area);
} else if (area == 0)
// only FramebufferUpdates are useful - skip others
// Note: do not skip if same timestamp as previous framebufferupdate
continue;
// cumulate areas of same timestamp
if (i + 1 < numMessages && message->timestamp == messages[i + 1]->timestamp)
continue;
// check size
if (area > minSlideArea) {
// reset cumulated area
area = 0;
// no animation or first index
if ((message->timestamp - timestamp > minSlideDiffMsecs) || index.size() == 0) {
if (animationCount > 0 && animationCount < minSequenceLength && previous_timestamp >= 0) {
// no animation, take last message of sequence
// (animations take first message of sequence as index)
index.push_back(new IndexEntry(NULL, previous_timestamp, NULL, NULL));
if (index.size() > 0)
index.back()->timestamp = previous_timestamp;
else
// first index
index.push_back(new IndexEntry(NULL, previous_timestamp, NULL, NULL));
if (VERBOSE)
printf(" RESET");
}
animationCount = 0;
if (VERBOSE)
cout << "\nIndex " << (index.size() < 9 ? " " : "") << (index.size() + 1) << ": " << message->timestamp;
index.push_back(new IndexEntry(NULL, message->timestamp, NULL, NULL));
} else {
// distinguish animations from multiple slide changes
animationCount++;
previous_timestamp = message->timestamp;
if (VERBOSE)
cout << "\t" << message->timestamp << "(" << animationCount << ")";
}
timestamp = message->timestamp;
}
}
// fix last index if needed
if (animationCount > 0 && animationCount < minSequenceLength && previous_timestamp >= 0 && index.size() > 0) {
// no animation, take last message of sequence
// (animations take first message of sequence as index)
index.back()->timestamp = previous_timestamp;
if (VERBOSE)
printf(" RESET");
}
if ((index.size() > 0)
&& (index.back()->timestamp >= messages[numMessages - 1]->timestamp)) {
index.pop_back();
if (VERBOSE)
printf(" - Removing last index, because it uses timestamp of last message->");
}
// add index at beginning if needed
if (index.size() == 0 || index.front()->timestamp > 2000) {
index.push_front(new IndexEntry(NULL, 0, NULL, NULL));
if (VERBOSE)
printf("\nIndex added index at beginning.");
}
if (VERBOSE)
printf("\n\nGenerated index with %d entries.\n\n", index.size());
it = index.begin();
}
SDL_Surface* Index::readThumbnail(Inflater* in, int* numBytes) {
int imageSize;
in->readInt(&imageSize);
*numBytes-=4;
if(imageSize==0)
*numBytes -= 4;
if (imageSize == 0)
// thumbnail not available
return NULL;
else
{
char* imageArray = (char*) malloc(imageSize);
imageArray=in->readCharArray(imageSize,false);
*numBytes-=imageSize;/*
//#ifdef EMSCRIPTEN
//write to file (emscripten has no IMG_LoadPNG_RW method, but IMG_Load exists)
ofstream file;
file.open("Assets/thumbnail.png",ofstream::out | ofstream::trunc);
file.write(imageArray,imageSize);
file.close();
//create from file
SDL_Surface* bufferedImage = IMG_Load("Assets/thumbnail.png");*/
//#else
SDL_Surface* bufferedImage = IMG_Load_RW(SDL_RWFromMem((void*)imageArray,imageSize),1);
//#endif
else {
//printf("Index numBytes = %d, imageSize = %d\n",*numBytes, imageSize);
char* imageArray;// = (char*) malloc(imageSize);
imageArray = in->readCharArray(imageSize, false);
*numBytes -= imageSize;
SDL_RWops* source=SDL_RWFromMem((void*) imageArray, imageSize);
SDL_Surface* bufferedImage = IMG_Load_RW(source, 0);
delete(imageArray);
//ImageIO.read(new ByteArrayInputStream(image_array));
//thumbnail_scale_factor = recording.prefs.framebufferHeight / bufferedImage.getHeight();
return bufferedImage;
}
}
void Index::fillSurface(SDL_Surface* screen, Message** messages, int numMessages, ProtocolPreferences* prefs) {
if (it == index.end())
return;
SDL_Surface* waypoint = SDL_CreateRGBSurface(SDL_ANYFORMAT, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
if (it == index.begin()) {
currentMessage = 0;
} else {
it--;
(*it)->paintWaypoint(waypoint);
it++;
}
while (currentMessage < numMessages) {
if (messages[currentMessage]->timestamp > (*it)->timestamp)
break;
if (messages[currentMessage]->type == RAW)
messages[currentMessage]->paint(waypoint, prefs);
currentMessage++;
}
(*it)->setWaypoint(waypoint);
it++;
}
IndexEntry* Index::lastBefore(int timestamp) {
for(std::list<IndexEntry*>::reverse_iterator it=index.rbegin();it!=index.rend();it++)
if((*it)->timestamp <= timestamp*1000)
return (IndexEntry*) *it;
for (std::list<IndexEntry*>::reverse_iterator it = index.rbegin(); it != index.rend(); it++)
if ((*it)->timestamp <= timestamp && (*it)->hasImages)
{
return (IndexEntry*) * it;
}
return index.front();
}
Index::~Index() {
while (index.size() > 0) {
delete(index.front());
index.pop_front();
}
}
......@@ -23,13 +23,17 @@ using namespace std;
class Index {
public:
Index(Inflater* in, int numBytes);
Index(Message**, int numMessages);
Index(Message** messages, int numMessages);
virtual ~Index();
IndexEntry* lastBefore(int timestamp);
void fillSurface(SDL_Surface* screen, Message** messages, int numMessages, ProtocolPreferences* prefs);
private:
//void fillSurfaces(SDL_Surface* screen, Message** messages, int numMessages, ProtocolPreferences* prefs);
SDL_Surface* readThumbnail(Inflater* in, int* numBytes);
list<IndexEntry*> index;
std::list<IndexEntry*>::iterator it;
int currentMessage;
};
#endif /* INDEXEXTENSION_H */
......
......@@ -8,25 +8,93 @@
#include <SDL/SDL_video.h>
#include "IndexEntry.h"
#include "ProtocolPreferences.h"
IndexEntry::IndexEntry(char* title, int timestamp, SizedArray* searchable, SDL_Surface* image) {
this->title=title;
this->timestamp=timestamp;
this->searchable=searchable;
this->image=image;
waypoint=NULL;
hasImages=false;
}
void IndexEntry::setWaypoint(SDL_Surface* waypoint) {
this->waypoint=waypoint;
if(image==NULL)
image=scaleDownSurface(waypoint, 5);
hasImages=true;
}
void IndexEntry::paintWaypoint(SDL_Surface* screen) {
SDL_Rect rect = {0,0,screen->w,screen->h};
SDL_BlitSurface(waypoint,NULL,screen,&rect);
}
IndexEntry::~IndexEntry() {
SDL_FreeSurface(image);
SDL_FreeSurface(waypoint);
if(title!=NULL)
free(title);
delete(searchable);
}
SDL_Rect IndexEntry::getRect(SDL_Surface* screen, int x, int y) {
if(image==NULL)
{
SDL_Rect r= {0,0,0,0};
return r;
}
SDL_Rect r= {max(0,min(screen->w-image->w,x-image->w/2)),y-image->h,image->w,image->h};
return r;
}
void IndexEntry::paintAt(SDL_Surface* screen, int x, int y) {
void IndexEntry::paintThumbnail(SDL_Surface* screen, int x, int y) {
if(image==NULL)
return;
SDL_Rect rect = getRect(screen,x,y);
SDL_UpdateRect(screen, rect.x,rect.y,rect.w,rect.h);
SDL_BlitSurface(image,NULL,screen,&rect);
SDL_UpdateRect(screen, rect.x,rect.y,rect.w,rect.h);
}
Uint32 readPixel(SDL_Surface* source, int x, int y){
switch(source->format->BytesPerPixel)
{
case 1:
return ((unsigned char*)source->pixels)[x+source->w*y];
case 2:
return ((unsigned short*)source->pixels)[x+source->w*y];
default:
return ((unsigned int*)source->pixels)[x+source->w*y];
}
}
void writePixel(SDL_Surface* target, int x, int y, Uint32 color){
switch(target->format->BytesPerPixel)
{
case 1:
((unsigned char*)target->pixels)[x+target->w*y]=(unsigned char)color;
case 2:
((unsigned short*)target->pixels)[x+target->w*y]=(unsigned short)color;
default:
((unsigned int*)target->pixels)[x+target->w*y]=(unsigned int)color;
}
}
SDL_Surface* IndexEntry::scaleDownSurface(SDL_Surface* source, char factor) {
SDL_Surface* result=SDL_CreateRGBSurface(0,source->w/factor,source->h/factor,source->format->BitsPerPixel,source->format->Rmask,source->format->Gmask,source->format->Bmask,source->format->Amask);
Uint32 alpha,red,green,blue;
Uint32 color, colorPart;
for(int i=0;i<result->w;i++)
for(int j=0;j<result->h;j++)
{
color=readPixel(source,i*factor,j*factor);
writePixel(result,i,j,color);
/*for(int k=0;k<factor;k++)
for(int l=0;l<factor;l++)
{
readPixel(source,i+k,j+l);
}*/
}
return result;
}
......@@ -21,14 +21,20 @@ public:
IndexEntry(char* title, int timestamp, SizedArray* searchable, SDL_Surface* image);
virtual ~IndexEntry();
SDL_Rect getRect(SDL_Surface* screen, int x, int y);
void paintAt(SDL_Surface* screen, int x, int y);
void paintThumbnail(SDL_Surface* screen, int x, int y);
void paintWaypoint(SDL_Surface* screen);
void setWaypoint(SDL_Surface* waypoint);
int timestamp;
bool hasImages;
private:
SDL_Surface* scaleDownSurface(SDL_Surface* source, char factor);
char* title;
SizedArray* searchable;
SDL_Surface* image;
SDL_Surface* waypoint;
};
#endif /* INDEXENTRY_H */
......
......@@ -14,6 +14,10 @@ Inflater::Inflater(FILE* f)
source=f;
outOffset=0;
/*fseek(source,0,SEEK_END);
printf("Inflater file size: %ld\n",ftell(source));
fseek(source,0,SEEK_SET);*/
// allocate inflate state
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
......@@ -66,13 +70,15 @@ Inflater::~Inflater()
(void)inflateEnd(&strm);
ret = Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
printf("Inflater Endresult: %d\n",ret);
fclose(source);
}
bool Inflater::readByte(char* Byte)
{
if (ret != Z_OK)
{
printf("Video Inflation failed: %d\n",ret);
//printf("Video Inflation failed: %d\n",ret);
*Byte=0;
return Z_ERRNO;
}
if(outOffset >= CHUNK - strm.avail_out) //Array out has to be refilled
......@@ -142,7 +148,11 @@ char* Inflater::readCharArray(int length, bool end)
{
r=readByte(&(byteArray[i]));
if(r!=Z_OK)
{
printf("Inflater error: %x\n",r);
free(byteArray);
return NULL;
}
}