2003-12-15 07:44:43 +00:00
|
|
|
|
/***************************************************************************
|
|
|
|
|
* __________ __ ___.
|
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
|
* $Id$
|
|
|
|
|
*
|
|
|
|
|
* Experimental plugin for halftoning
|
|
|
|
|
* Reads raw image data from a file
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2003 J<EFBFBD>rg Hohensohn [IDC]Dragon
|
|
|
|
|
*
|
|
|
|
|
* All files in this archive are subject to the GNU General Public License.
|
|
|
|
|
* See the file COPYING in the source tree root for full license agreement.
|
|
|
|
|
*
|
|
|
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
|
* KIND, either express or implied.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
#include "plugin.h"
|
|
|
|
|
#include "system.h"
|
|
|
|
|
|
2003-12-15 08:00:45 +00:00
|
|
|
|
#ifndef SIMULATOR /* not for simulator by now */
|
|
|
|
|
#ifdef HAVE_LCD_BITMAP /* and definitely not for the Player, haha */
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
#define INT_MAX ((int)(~(unsigned)0 >> 1))
|
|
|
|
|
#define INT_MIN (-INT_MAX-1)
|
|
|
|
|
|
2003-12-15 07:44:43 +00:00
|
|
|
|
#define SCREENSIZE (LCD_WIDTH*LCD_HEIGHT/8) /* in bytes */
|
|
|
|
|
#define FILEBUFSIZE SCREENSIZE*4 /* must result in a multiple of 512 */
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
#define WIND_STEP 5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* globals */
|
2003-12-15 07:44:43 +00:00
|
|
|
|
static struct plugin_api* rb; /* here is a global api struct pointer */
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
static enum
|
|
|
|
|
{
|
|
|
|
|
playing,
|
|
|
|
|
paused,
|
|
|
|
|
stop,
|
|
|
|
|
exit
|
|
|
|
|
} state = playing;
|
|
|
|
|
|
|
|
|
|
static int playstep = 1; /* forcurrent speed and direction */
|
|
|
|
|
static long time; /* to calculate the playing time */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* test for button, returns relative frame and may change state */
|
|
|
|
|
int check_button(void)
|
|
|
|
|
{
|
|
|
|
|
int button;
|
|
|
|
|
int frame;
|
|
|
|
|
bool loop;
|
|
|
|
|
|
|
|
|
|
frame = playstep; /* default */
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
loop = false;
|
|
|
|
|
if (state == playing)
|
|
|
|
|
button = rb->button_get(false);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
long current = *rb->current_tick;
|
|
|
|
|
button = rb->button_get(true); /* block */
|
|
|
|
|
time += *rb->current_tick - current; /* don't time while waiting */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(button)
|
|
|
|
|
{
|
|
|
|
|
case BUTTON_NONE:
|
|
|
|
|
break; /* quick exit */
|
|
|
|
|
|
|
|
|
|
case BUTTON_LEFT | BUTTON_REPEAT:
|
|
|
|
|
if (state == paused)
|
|
|
|
|
frame = -1; /* single step back */
|
|
|
|
|
else if (state == playing)
|
|
|
|
|
playstep = -WIND_STEP; /* FR */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_RIGHT | BUTTON_REPEAT:
|
|
|
|
|
if (state == paused)
|
|
|
|
|
frame = 1; /* single step */
|
|
|
|
|
else if (state == playing)
|
|
|
|
|
playstep = WIND_STEP; /* FF */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_PLAY:
|
|
|
|
|
if (state == playing && playstep == 1)
|
|
|
|
|
state = paused;
|
|
|
|
|
else if (state == paused)
|
|
|
|
|
state = playing;
|
|
|
|
|
playstep = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_LEFT:
|
|
|
|
|
if (state == paused)
|
|
|
|
|
frame = -1; /* single step back */
|
|
|
|
|
else if (state == playing)
|
|
|
|
|
playstep = -1; /* rewind */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_RIGHT:
|
|
|
|
|
if (state == paused)
|
|
|
|
|
frame = 1; /* single step */
|
|
|
|
|
else if (state == playing)
|
|
|
|
|
playstep = 1; /* forward */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_UP:
|
|
|
|
|
if (state == paused)
|
|
|
|
|
frame = INT_MAX; /* end of clip */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_DOWN:
|
|
|
|
|
frame = INT_MIN; /* start of clip */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BUTTON_OFF:
|
|
|
|
|
state = stop;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SYS_USB_CONNECTED:
|
|
|
|
|
state = exit;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if (state != playing)
|
|
|
|
|
loop = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
while (loop);
|
|
|
|
|
|
|
|
|
|
return frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-12-15 07:44:43 +00:00
|
|
|
|
int WaitForButton(void)
|
|
|
|
|
{
|
|
|
|
|
int button;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
button = rb->button_get(true);
|
|
|
|
|
} while ((button & BUTTON_REL) && button != SYS_USB_CONNECTED);
|
|
|
|
|
|
|
|
|
|
return button;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* play from memory, loop until OFF is pressed */
|
|
|
|
|
int show_buffer(unsigned char* p_start, int frames)
|
|
|
|
|
{
|
|
|
|
|
unsigned char* p_current = p_start;
|
|
|
|
|
unsigned char* p_end = p_start + SCREENSIZE * frames;
|
|
|
|
|
int shown = 0;
|
2003-12-18 22:36:35 +00:00
|
|
|
|
int delta; /* next frame */
|
2003-12-15 07:44:43 +00:00
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
rb->lcd_blit(p_current, 0, 0, LCD_WIDTH, LCD_HEIGHT/8, LCD_WIDTH);
|
|
|
|
|
|
|
|
|
|
rb->yield(); /* yield to the other treads */
|
|
|
|
|
shown++;
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
delta = check_button();
|
|
|
|
|
if (delta == INT_MIN)
|
|
|
|
|
p_current = p_start;
|
|
|
|
|
else if (delta == INT_MAX)
|
|
|
|
|
p_current = p_end - SCREENSIZE;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p_current += delta * SCREENSIZE;
|
|
|
|
|
if (p_current >= p_end || p_current < p_start)
|
|
|
|
|
p_current = p_start; /* wrap */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while(state != stop && state != exit);
|
2003-12-15 07:44:43 +00:00
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
return (state != exit) ? shown : -1;
|
2003-12-15 07:44:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* play from file, exit if OFF is pressed */
|
|
|
|
|
int show_file(unsigned char* p_buffer, int fd)
|
|
|
|
|
{
|
|
|
|
|
int shown = 0;
|
2003-12-18 22:36:35 +00:00
|
|
|
|
int delta; /* next frame */
|
2003-12-15 07:44:43 +00:00
|
|
|
|
/* tricky buffer handling to read only whole sectors, then no copying needed */
|
|
|
|
|
unsigned char* p_file = p_buffer; /* file read */
|
|
|
|
|
unsigned char* p_screen = p_buffer; /* display */
|
|
|
|
|
unsigned char* p_end = p_buffer + FILEBUFSIZE; /* for wraparound test */
|
|
|
|
|
int needed; /* read how much data to complete a frame */
|
2003-12-18 22:36:35 +00:00
|
|
|
|
int got_now; /* how many gotten for this frame */
|
2003-12-15 07:44:43 +00:00
|
|
|
|
int read_now; /* size to read for this frame, 512 or 1024 */
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
needed = SCREENSIZE - (p_file - p_screen); /* minus what we have */
|
|
|
|
|
read_now = (needed + (SECTOR_SIZE-1)) & ~(SECTOR_SIZE-1); /* round up to whole sectors */
|
|
|
|
|
|
|
|
|
|
got_now = rb->read(fd, p_file, read_now); /* read the sector(s) */
|
|
|
|
|
rb->lcd_blit(p_screen, 0, 0, LCD_WIDTH, LCD_HEIGHT/8, LCD_WIDTH);
|
|
|
|
|
|
|
|
|
|
p_screen += SCREENSIZE;
|
|
|
|
|
if (p_screen >= p_end)
|
|
|
|
|
p_screen = p_buffer; /* wrap */
|
|
|
|
|
|
|
|
|
|
p_file += got_now;
|
|
|
|
|
if (p_file >= p_end)
|
|
|
|
|
p_file = p_buffer; /* wrap */
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
delta = check_button();
|
|
|
|
|
|
2003-12-15 07:44:43 +00:00
|
|
|
|
if (read_now < SCREENSIZE) /* below average? time to do something else */
|
|
|
|
|
rb->yield(); /* yield to the other treads */
|
2003-12-18 22:36:35 +00:00
|
|
|
|
|
|
|
|
|
if (delta != 1)
|
|
|
|
|
{ /* need to seek */
|
|
|
|
|
long newpos;
|
|
|
|
|
|
|
|
|
|
rb->yield(); /* yield in case we didn't do it above */
|
|
|
|
|
|
|
|
|
|
if (delta == INT_MIN)
|
|
|
|
|
newpos = 0;
|
|
|
|
|
else if (delta == INT_MAX)
|
|
|
|
|
newpos = rb->filesize(fd) - SCREENSIZE;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool pause = false;
|
|
|
|
|
newpos = rb->lseek(fd, 0, SEEK_CUR) - (p_file - p_screen) + (delta-1) * SCREENSIZE;
|
|
|
|
|
|
|
|
|
|
if (newpos < 0)
|
|
|
|
|
{
|
|
|
|
|
newpos = 0;
|
|
|
|
|
pause = true; /* go in paused mode */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (newpos > rb->filesize(fd) - SCREENSIZE)
|
|
|
|
|
{
|
|
|
|
|
newpos = rb->filesize(fd) - SCREENSIZE;
|
|
|
|
|
pause = true; /* go in paused mode */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pause && state == playing)
|
|
|
|
|
state = paused;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newpos -= newpos % SCREENSIZE; /* should be "even", just to make shure */
|
|
|
|
|
|
|
|
|
|
rb->lseek(fd, newpos & ~(SECTOR_SIZE-1), SEEK_SET); /* round down to sector */
|
|
|
|
|
newpos %= FILEBUFSIZE; /* make it an offset within buffer */
|
|
|
|
|
p_screen = p_buffer + newpos;
|
|
|
|
|
p_file = p_buffer + (newpos & ~(SECTOR_SIZE-1));
|
2003-12-15 07:44:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shown++;
|
2003-12-18 22:36:35 +00:00
|
|
|
|
} while (got_now >= needed && state != stop && state != exit);
|
2003-12-15 07:44:43 +00:00
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
return (state != exit) ? shown : -1;
|
2003-12-15 07:44:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main(char* filename)
|
|
|
|
|
{
|
|
|
|
|
char buf[32];
|
|
|
|
|
int buffer_size, file_size;
|
|
|
|
|
unsigned char* p_buffer;
|
|
|
|
|
int fd; /* file descriptor handle */
|
|
|
|
|
int got_now; /* how many bytes read from file */
|
|
|
|
|
int frames, shown;
|
|
|
|
|
int button;
|
2003-12-18 22:36:35 +00:00
|
|
|
|
int fps;
|
2003-12-15 07:44:43 +00:00
|
|
|
|
|
|
|
|
|
p_buffer = rb->plugin_get_buffer(&buffer_size);
|
|
|
|
|
if (buffer_size < FILEBUFSIZE)
|
|
|
|
|
return PLUGIN_ERROR; /* not enough memory */
|
|
|
|
|
|
|
|
|
|
fd = rb->open(filename, O_RDONLY);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return PLUGIN_ERROR;
|
|
|
|
|
|
|
|
|
|
file_size = rb->filesize(fd);
|
|
|
|
|
if (file_size <= buffer_size)
|
|
|
|
|
{ /* we can read the whole file in advance */
|
|
|
|
|
got_now = rb->read(fd, p_buffer, file_size);
|
|
|
|
|
rb->close(fd);
|
|
|
|
|
frames = got_now / (LCD_WIDTH*LCD_HEIGHT/8);
|
|
|
|
|
time = *rb->current_tick;
|
|
|
|
|
shown = show_buffer(p_buffer, frames);
|
|
|
|
|
time = *rb->current_tick - time;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ /* we need to stream */
|
|
|
|
|
time = *rb->current_tick;
|
|
|
|
|
shown = show_file(p_buffer, fd);
|
|
|
|
|
time = *rb->current_tick - time;
|
|
|
|
|
rb->close(fd);
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
if (shown == -1) /* exception */
|
2003-12-15 07:44:43 +00:00
|
|
|
|
return PLUGIN_USB_CONNECTED;
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
fps = (shown * HZ *100) / time; /* 100 times fps */
|
|
|
|
|
|
2003-12-15 07:44:43 +00:00
|
|
|
|
rb->lcd_clear_display();
|
2003-12-18 22:36:35 +00:00
|
|
|
|
rb->snprintf(buf, sizeof(buf), "%d frames shown", shown);
|
2003-12-15 07:44:43 +00:00
|
|
|
|
rb->lcd_puts(0, 0, buf);
|
|
|
|
|
rb->snprintf(buf, sizeof(buf), "%d.%02d seconds", time/HZ, time%HZ);
|
|
|
|
|
rb->lcd_puts(0, 1, buf);
|
2003-12-18 22:36:35 +00:00
|
|
|
|
rb->snprintf(buf, sizeof(buf), "%d.%02d fps", fps/100, fps%100);
|
2003-12-15 07:44:43 +00:00
|
|
|
|
rb->lcd_puts(0, 2, buf);
|
|
|
|
|
rb->snprintf(buf, sizeof(buf), "file: %d bytes", file_size);
|
|
|
|
|
rb->lcd_puts(0, 6, buf);
|
|
|
|
|
rb->snprintf(buf, sizeof(buf), "buffer: %d bytes", buffer_size);
|
|
|
|
|
rb->lcd_puts(0, 7, buf);
|
|
|
|
|
rb->lcd_update();
|
|
|
|
|
button = WaitForButton();
|
|
|
|
|
return (button == SYS_USB_CONNECTED) ? PLUGIN_USB_CONNECTED : PLUGIN_OK;
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
|
2003-12-15 07:44:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************** Plugin Entry Point *****************/
|
|
|
|
|
|
|
|
|
|
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
|
|
|
|
|
{
|
2003-12-22 23:10:04 +00:00
|
|
|
|
int ret;
|
2003-12-15 07:44:43 +00:00
|
|
|
|
/* this macro should be called as the first thing you do in the plugin.
|
|
|
|
|
it test that the api version and model the plugin was compiled for
|
|
|
|
|
matches the machine it is running on */
|
|
|
|
|
TEST_PLUGIN_API(api);
|
|
|
|
|
|
|
|
|
|
rb = api; /* copy to global api pointer */
|
|
|
|
|
|
2003-12-18 22:36:35 +00:00
|
|
|
|
if (parameter == NULL)
|
|
|
|
|
{
|
2003-12-22 23:10:04 +00:00
|
|
|
|
rb->splash(HZ*2, 0, true, "Play .rvf file!");
|
2003-12-18 22:36:35 +00:00
|
|
|
|
return PLUGIN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-15 07:44:43 +00:00
|
|
|
|
/* now go ahead and have fun! */
|
2003-12-22 23:10:04 +00:00
|
|
|
|
ret = main((char*) parameter);
|
|
|
|
|
if (ret==PLUGIN_USB_CONNECTED)
|
|
|
|
|
rb->usb_screen();
|
|
|
|
|
return ret;
|
2003-12-15 07:44:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-12-15 08:00:45 +00:00
|
|
|
|
#endif /* #ifdef HAVE_LCD_BITMAP */
|
|
|
|
|
#endif /* #ifndef SIMULATOR */
|