From 092c340a2062fa98b7387fc5fd63578ddae7d0b6 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 15 Jul 2020 19:40:55 -0400 Subject: [1/4] Remove SH support and all archos targets This removes all code specific to SH targets Change-Id: I7980523785d2596e65c06430f4638eec74a06061 --- apps/plugins/video.c | 1030 -------------------------------------------------- 1 file changed, 1030 deletions(-) delete mode 100644 apps/plugins/video.c (limited to 'apps/plugins/video.c') diff --git a/apps/plugins/video.c b/apps/plugins/video.c deleted file mode 100644 index 6a66324a79..0000000000 --- a/apps/plugins/video.c +++ /dev/null @@ -1,1030 +0,0 @@ -/*************************************************************************** -* __________ __ ___. -* Open \______ \ ____ ____ | | _\_ |__ _______ ___ -* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / -* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < -* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ -* \/ \/ \/ \/ \/ -* $Id$ -* -* Plugin for video playback -* Reads raw image data + audio data from a file -* !!!!!!!!!! Code Police free zone !!!!!!!!!! -* -* Copyright (C) 2003-2004 J�g Hohensohn aka [IDC]Dragon -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -* KIND, either express or implied. -* -****************************************************************************/ - - -/****************** imports ******************/ - -#include "plugin.h" -#include "sh7034.h" -#include "system.h" -#include "lib/helper.h" - -#ifdef HAVE_LCD_BITMAP /* and definitely not for the Player, haha */ - - - -/* variable button definitions */ -#if CONFIG_KEYPAD == RECORDER_PAD -#define VIDEO_STOP_SEEK BUTTON_PLAY -#define VIDEO_RESUME BUTTON_PLAY -#define VIDEO_DEBUG BUTTON_F1 -#define VIDEO_CONTRAST_DOWN BUTTON_F2 -#define VIDEO_CONTRAST_UP BUTTON_F3 - -#elif CONFIG_KEYPAD == ONDIO_PAD -#define VIDEO_STOP_SEEK_PRE BUTTON_MENU -#define VIDEO_STOP_SEEK (BUTTON_MENU | BUTTON_REL) -#define VIDEO_RESUME BUTTON_RIGHT -#define VIDEO_CONTRAST_DOWN (BUTTON_MENU | BUTTON_DOWN) -#define VIDEO_CONTRAST_UP (BUTTON_MENU | BUTTON_UP) - -#endif -/****************** constants ******************/ - -#define SCREENSIZE (LCD_WIDTH*LCD_HEIGHT/8) /* in bytes */ -#define FPS 68 /* default fps for headerless (old video-only) file */ -#define MAX_ACC 20 /* maximum FF/FR speedup */ -#define FF_TICKS 3000; /* experimentally found nice */ - -/* trigger levels, we need about 80 kB/sec */ -#define SPINUP_INIT 5000 /* from what level on to refill, in milliseconds */ -#define SPINUP_SAFETY 700 /* how much on top of the measured spinup time */ -#define CHUNK (1024*32) /* read size */ - - -/****************** prototypes ******************/ -static void timer4_isr(void); /* IMIA4 ISR */ -int check_button(void); /* determine next relative frame */ - - -/****************** data types ******************/ - -/* plugins don't introduce headers, so structs are repeated from rvf_format.h */ - -#define HEADER_MAGIC 0x52564668 /* "RVFh" at file start */ -#define AUDIO_MAGIC 0x41756446 /* "AudF" for each audio block */ -#define FILEVERSION 100 /* 1.00 */ - -/* format type definitions */ -#define VIDEOFORMAT_NO_VIDEO 0 -#define VIDEOFORMAT_RAW 1 -#define AUDIOFORMAT_NO_AUDIO 0 -#define AUDIOFORMAT_MP3 1 -#define AUDIOFORMAT_MP3_BITSWAPPED 2 - -/* bit flags */ -#define FLAG_LOOP 0x00000001 /* loop the playback, e.g. for stills */ - -typedef struct /* contains whatever might be useful to the player */ -{ - /* general info (16 entries = 64 byte) */ - unsigned long magic; /* HEADER_MAGIC */ - unsigned long version; /* file version */ - unsigned long flags; /* combination of FLAG_xx */ - unsigned long blocksize; /* how many bytes per block (=video frame) */ - unsigned long bps_average; /* bits per second of the whole stream */ - unsigned long bps_peak; /* max. of above (audio may be VBR) */ - unsigned long resume_pos; /* file position to resume to */ - unsigned long reserved[9]; /* reserved, should be zero */ - - /* video info (16 entries = 64 byte) */ - unsigned long video_format; /* one of VIDEOFORMAT_xxx */ - unsigned long video_1st_frame; /* byte position of first video frame */ - unsigned long video_duration; /* total length of video part, in ms */ - unsigned long video_payload_size; /* total amount of video data, in bytes */ - unsigned long video_bitrate; /* derived from resolution and frame time, in bps */ - unsigned long video_frametime; /* frame interval in 11.0592 MHz clocks */ - long video_preroll; /* video is how much ahead, in 11.0592 MHz clocks */ - unsigned long video_width; /* in pixels */ - unsigned long video_height; /* in pixels */ - unsigned long video_reserved[7]; /* reserved, should be zero */ - - /* audio info (16 entries = 64 byte) */ - unsigned long audio_format; /* one of AUDIOFORMAT_xxx */ - unsigned long audio_1st_frame; /* byte position of first video frame */ - unsigned long audio_duration; /* total length of audio part, in ms */ - unsigned long audio_payload_size; /* total amount of audio data, in bytes */ - unsigned long audio_avg_bitrate; /* average audio bitrate, in bits per second */ - unsigned long audio_peak_bitrate; /* maximum bitrate */ - unsigned long audio_headersize; /* offset to payload in audio frames */ - long audio_min_associated; /* minimum offset to video frame, in bytes */ - long audio_max_associated; /* maximum offset to video frame, in bytes */ - unsigned long audio_reserved[7]; /* reserved, should be zero */ - - /* more to come... ? */ - - /* Note: padding up to 'blocksize' with zero following this header */ -} tFileHeader; - -typedef struct /* the little header for all audio blocks */ -{ - unsigned long magic; /* AUDIO_MAGIC indicates an audio block */ - unsigned char previous_block; /* previous how many blocks backwards */ - unsigned char next_block; /* next how many blocks forward */ - short associated_video; /* offset to block with corresponding video */ - unsigned short frame_start; /* offset to first frame starting in this block */ - unsigned short frame_end; /* offset to behind last frame ending in this block */ -} tAudioFrameHeader; - - - -/****************** globals ******************/ - -static char gPrint[32]; /* a global printf buffer, saves stack */ - - -/* playstate */ -static struct -{ - enum - { - paused, - playing, - } state; - bool bAudioUnderrun; - bool bVideoUnderrun; - bool bHasAudio; - bool bHasVideo; - int nTimeOSD; /* OSD should stay for this many frames */ - bool bDirtyOSD; /* OSD needs redraw */ - bool bRefilling; /* set if refilling buffer */ - bool bSeeking; - int nSeekAcc; /* accelleration value for seek */ - int nSeekPos; /* current file position for seek */ - bool bDiskSleep; /* disk is suspended */ -#if FREQ == 12000000 /* Ondio speed kludge */ - int nFrameTimeAdjusted; -#endif -} gPlay; - -/* buffer information */ -static struct -{ - ssize_t bufsize; - int granularity; /* common multiple of block and sector size */ - unsigned char* pBufStart; /* start of ring buffer */ - unsigned char* pBufEnd; /* end of ring buffer */ - int osd_ypos; - int osd_height; - - int vidcount; /* how many video blocks are known in a row */ - unsigned char* pBufFill; /* write pointer for disk, owned by main task */ - unsigned char* pReadVideo; /* video readout, maintained by timer ISR */ - unsigned char* pReadAudio; /* audio readout, maintained by demand ISR */ - bool bEOF; /* flag for end of file */ - int low_water; /* reload threshold */ - int high_water; /* end of reload threshold */ - int spinup_safety; /* safety margin when recalculating low_water */ - int nReadChunk; /* how much data for normal buffer fill */ - int nSeekChunk; /* how much data while seeking */ -} gBuf; - -/* statistics */ -static struct -{ - int minAudioAvail; - int minVideoAvail; - int nAudioUnderruns; - int nVideoUnderruns; - long minSpinup; - long maxSpinup; -} gStats; - -tFileHeader gFileHdr; /* file header */ - -/****************** implementation ******************/ - -/* tool function: return how much playable audio/video is left */ -static int Available(unsigned char* pSnapshot) -{ - if (pSnapshot <= gBuf.pBufFill) - return gBuf.pBufFill - pSnapshot; - else - return gBuf.bufsize - (pSnapshot - gBuf.pBufFill); -} - -/* debug function to draw buffer indicators */ -#ifdef VIDEO_DEBUG -static void DrawBuf(void) -{ - int ypos, fill, video, audio; - - rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - rb->lcd_fillrect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - rb->lcd_set_drawmode(DRMODE_SOLID); - - ypos = gBuf.osd_ypos + gBuf.osd_height/2 - 3; /* center vertically */ - - rb->lcd_hline(1, LCD_WIDTH-2, ypos + 3); - rb->lcd_vline(0, ypos, ypos + 6); - rb->lcd_vline(LCD_WIDTH-1, ypos, ypos + 6); - - /* calculate new tick positions */ - fill = 1 + ((gBuf.pBufFill - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; - video = 1 + ((gBuf.pReadVideo - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; - audio = 1 + ((gBuf.pReadAudio - gBuf.pBufStart) * (LCD_WIDTH-2)) / gBuf.bufsize; - - rb->lcd_drawpixel(fill, ypos + 4); - rb->lcd_drawpixel(video, ypos + 2); - rb->lcd_drawpixel(audio, ypos + 1); - - if (gPlay.state == paused) /* we have to draw ourselves */ - rb->lcd_update_rect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - else - gPlay.bDirtyOSD = true; /* redraw it with next timer IRQ */ -} -#endif - - -/* helper function to draw a position indicator */ -static void DrawPosition(int pos, int total) -{ - int w, h; - int sec; /* estimated seconds */ - int ypos; - - rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - rb->lcd_fillrect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - rb->lcd_set_drawmode(DRMODE_SOLID); - - /* print the estimated position */ - sec = pos / (gFileHdr.bps_average/8); - if (sec < 100*60) /* fits into mm:ss format */ - rb->snprintf(gPrint, sizeof(gPrint), "%02d:%02dm", sec/60, sec%60); - else /* a very long clip, hh:mm format */ - rb->snprintf(gPrint, sizeof(gPrint), "%02d:%02dh", sec/3600, (sec/60)%60); - - rb->lcd_getstringsize(gPrint, &w, &h); - w++; - ypos = gBuf.osd_ypos + (gBuf.osd_height - h) / 2; - rb->lcd_putsxy(0, ypos, gPrint); - - /* draw a slider over the rest of the line */ - rb->gui_scrollbar_draw(rb->screens[SCREEN_MAIN], w, ypos, LCD_WIDTH-w, - h, total, 0, pos, HORIZONTAL); - - if (gPlay.state == paused) /* we have to draw ourselves */ - rb->lcd_update_rect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - else /* let the display time do it */ - { - gPlay.nTimeOSD = FPS; - gPlay.bDirtyOSD = true; /* redraw it with next timer IRQ */ - } -} - -/* Put text on OSD and activate it for 1 second */ -static void osd_show_text(void) -{ - int h, ypos; - - rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); - rb->lcd_fillrect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - rb->lcd_set_drawmode(DRMODE_SOLID); - - rb->lcd_getstringsize(gPrint, NULL, &h); - ypos = gBuf.osd_ypos + (gBuf.osd_height - h) / 2; - rb->lcd_putsxy(0, ypos, gPrint); - - if (gPlay.state == paused) /* we have to draw ourselves */ - rb->lcd_update_rect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - else /* let the display time do it */ - { - gPlay.nTimeOSD = FPS; /* display it for 1 sec */ - gPlay.bDirtyOSD = true; /* let the refresh copy it to LCD */ - } -} - -/* helper function to change the volume by a certain amount, +/- */ -static void ChangeVolume(int delta) -{ - int minvol = rb->sound_min(SOUND_VOLUME); - int maxvol = rb->sound_max(SOUND_VOLUME); - int vol = rb->global_settings->volume + delta; - - if (vol > maxvol) vol = maxvol; - else if (vol < minvol) vol = minvol; - if (vol != rb->global_settings->volume) - { - rb->sound_set(SOUND_VOLUME, vol); - rb->global_settings->volume = vol; - - rb->snprintf(gPrint, sizeof(gPrint), "Vol: %d dB", vol); - osd_show_text(); - } -} - - -/* helper function to change the LCD contrast by a certain amount, +/- */ -static void ChangeContrast(int delta) -{ - static int mycontrast = -1; /* the "permanent" value while running */ - int contrast; /* updated value */ - - if (mycontrast == -1) - mycontrast = rb->global_settings->contrast; - - contrast = mycontrast + delta; - if (contrast > 63) contrast = 63; - else if (contrast < 5) contrast = 5; - if (contrast != mycontrast) - { - rb->lcd_set_contrast(contrast); - mycontrast = contrast; - - rb->snprintf(gPrint, sizeof(gPrint), "Contrast: %d", contrast); - osd_show_text(); - } -} - - -/* sync the video to the current audio */ -static void SyncVideo(void) -{ - tAudioFrameHeader* pAudioBuf; - - pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadAudio); - if (pAudioBuf->magic == AUDIO_MAGIC) - { - gBuf.vidcount = 0; /* nothing known */ - /* sync the video position */ - gBuf.pReadVideo = gBuf.pReadAudio + - (long)pAudioBuf->associated_video * (long)gFileHdr.blocksize; - - /* handle possible wrap */ - if (gBuf.pReadVideo >= gBuf.pBufEnd) - gBuf.pReadVideo -= gBuf.bufsize; - else if (gBuf.pReadVideo < gBuf.pBufStart) - gBuf.pReadVideo += gBuf.bufsize; - } -} - - -/* timer interrupt handler to display a frame */ -static void timer4_isr(void) -{ - int available; - tAudioFrameHeader* pAudioBuf; - int height; /* height to display */ - - /* reduce height if we have OSD on */ - height = gFileHdr.video_height; - if (gPlay.nTimeOSD > 0) - { - gPlay.nTimeOSD--; - height = MIN(gBuf.osd_ypos, height); - if (gPlay.bDirtyOSD) - { - rb->lcd_update_rect(0, gBuf.osd_ypos, LCD_WIDTH, gBuf.osd_height); - gPlay.bDirtyOSD = false; - } - } - - rb->lcd_blit_mono(gBuf.pReadVideo, 0, 0, - gFileHdr.video_width, height/8, gFileHdr.video_width); - - available = Available(gBuf.pReadVideo); - - /* loop to skip audio frame(s) */ - while(1) - { - /* just for the statistics */ - if (!gBuf.bEOF && available < gStats.minVideoAvail) - gStats.minVideoAvail = available; - - if (available <= (int)gFileHdr.blocksize) - { /* no data for next frame */ - - if (gBuf.bEOF && (gFileHdr.flags & FLAG_LOOP)) - { /* loop now, assuming the looped clip fits in memory */ - gBuf.pReadVideo = gBuf.pBufStart + gFileHdr.video_1st_frame; - /* FixMe: pReadVideo is incremented below */ - } - else - { - gPlay.bVideoUnderrun = true; - rb->timer_unregister(); /* disable ourselves */ - return; /* no data available */ - } - } - else /* normal advance for next time */ - { - gBuf.pReadVideo += gFileHdr.blocksize; - if (gBuf.pReadVideo >= gBuf.pBufEnd) - gBuf.pReadVideo -= gBuf.bufsize; /* wraparound */ - available -= gFileHdr.blocksize; - } - - if (!gPlay.bHasAudio) - break; /* no need to skip any audio */ - - if (gBuf.vidcount) - { - /* we know the next is a video frame */ - gBuf.vidcount--; - break; /* exit the loop */ - } - - pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadVideo); - if (pAudioBuf->magic == AUDIO_MAGIC) - { /* we ran into audio, can happen after seek */ - gBuf.vidcount = pAudioBuf->next_block; - if (gBuf.vidcount) - gBuf.vidcount--; /* minus the audio block */ - } - } /* while */ -} - - -/* ISR function to get more mp3 data */ -static void GetMoreMp3(const void** start, size_t* size) -{ - int available; - int advance; - - tAudioFrameHeader* pAudioBuf = (tAudioFrameHeader*)(gBuf.pReadAudio); - - advance = pAudioBuf->next_block * gFileHdr.blocksize; - - available = Available(gBuf.pReadAudio); - - /* just for the statistics */ - if (!gBuf.bEOF && available < gStats.minAudioAvail) - gStats.minAudioAvail = available; - - if (available < advance + (int)gFileHdr.blocksize || advance == 0) - { - gPlay.bAudioUnderrun = true; - return; /* no data available */ - } - - gBuf.pReadAudio += advance; - if (gBuf.pReadAudio >= gBuf.pBufEnd) - gBuf.pReadAudio -= gBuf.bufsize; /* wraparound */ - - *start = gBuf.pReadAudio + gFileHdr.audio_headersize; - *size = gFileHdr.blocksize - gFileHdr.audio_headersize; -} - - -static int WaitForButton(void) -{ - int button; - - do - { - button = rb->button_get(true); - rb->default_event_handler(button); - } while ((button & BUTTON_REL) && button != SYS_USB_CONNECTED); - - return button; -} - - -static bool WantResume(int fd) -{ - int button; - - rb->lcd_puts(0, 0, "Resume to this"); - rb->lcd_puts(0, 1, "last position?"); - rb->lcd_puts(0, 2, "PLAY = yes"); - rb->lcd_puts(0, 3, "Any Other = no"); - rb->lcd_puts(0, 4, " (plays from start)"); - DrawPosition(gFileHdr.resume_pos, rb->filesize(fd)); - rb->lcd_update(); - - button = WaitForButton(); - return (button == VIDEO_RESUME); -} - - -static int SeekTo(int fd, int nPos) -{ - int read_now, got_now; - - if (gPlay.bHasAudio) - rb->mp3_play_stop(); /* stop audio ISR */ - if (gPlay.bHasVideo) - rb->timer_unregister(); /* stop the timer */ - - rb->lseek(fd, nPos, SEEK_SET); - - gBuf.pBufFill = gBuf.pBufStart; /* all empty */ - gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart; - - read_now = gBuf.low_water - 1; /* less than low water, so loading will continue */ - read_now -= read_now % gBuf.granularity; /* round down to granularity */ - got_now = rb->read(fd, gBuf.pBufFill, read_now); - gBuf.bEOF = (read_now != got_now); - gBuf.pBufFill += got_now; - - if (nPos == 0) - { /* we seeked to the start */ - if (gPlay.bHasVideo) - gBuf.pReadVideo += gFileHdr.video_1st_frame; - - if (gPlay.bHasAudio) - gBuf.pReadAudio += gFileHdr.audio_1st_frame; - } - else - { /* we have to search for the positions */ - if (gPlay.bHasAudio) /* prepare audio playback, if contained */ - { - /* search for audio frame */ - while (((tAudioFrameHeader*)(gBuf.pReadAudio))->magic != AUDIO_MAGIC) - gBuf.pReadAudio += gFileHdr.blocksize; - - if (gPlay.bHasVideo) - SyncVideo(); /* pick the right video for that */ - } - } - - /* synchronous start */ - gPlay.state = playing; - if (gPlay.bHasAudio) - { - gPlay.bAudioUnderrun = false; - rb->mp3_play_data(gBuf.pReadAudio + gFileHdr.audio_headersize, - gFileHdr.blocksize - gFileHdr.audio_headersize, GetMoreMp3); - rb->mp3_play_pause(true); /* kickoff audio */ - } - if (gPlay.bHasVideo) - { - gPlay.bVideoUnderrun = false; - /* start display interrupt */ -#if FREQ == 12000000 /* Ondio speed kludge */ - rb->timer_register(1, NULL, gPlay.nFrameTimeAdjusted, - timer4_isr IF_COP(, CPU)); -#else - rb->timer_register(1, NULL, gFileHdr.video_frametime, - timer4_isr IF_COP(, CPU)); -#endif - } - - return 0; -} - -/* called from default_event_handler_ex() or at end of playback */ -static void Cleanup(void *fd) -{ - rb->close(*(int*)fd); /* close the file */ - - if (gPlay.bHasVideo) - rb->timer_unregister(); /* stop video ISR, now I can use the display again */ - - if (gPlay.bHasAudio) - rb->mp3_play_stop(); /* stop audio ISR */ - - /* Turn on backlight timeout (revert to settings) */ - backlight_use_settings(); - - /* restore normal contrast */ - rb->lcd_set_contrast(rb->global_settings->contrast); -} - -/* returns >0 if continue, =0 to stop, <0 to abort (USB) */ -static int PlayTick(int fd) -{ - int button; - static int lastbutton = 0; - int avail_audio = -1, avail_video = -1; - int retval = 1; - int filepos; - - /* check buffer level */ - - if (gPlay.bHasAudio) - avail_audio = Available(gBuf.pReadAudio); - if (gPlay.bHasVideo) - avail_video = Available(gBuf.pReadVideo); - - if ((gPlay.bHasAudio && avail_audio < gBuf.low_water) - || (gPlay.bHasVideo && avail_video < gBuf.low_water)) - { - gPlay.bRefilling = true; /* go to refill mode */ - } - - if ((!gPlay.bHasAudio || gPlay.bAudioUnderrun) - && (!gPlay.bHasVideo || gPlay.bVideoUnderrun) - && gBuf.bEOF) - { - if (gFileHdr.resume_pos) - { /* we played til the end, clear resume position */ - gFileHdr.resume_pos = 0; - rb->lseek(fd, 0, SEEK_SET); /* save resume position */ - rb->write(fd, &gFileHdr, sizeof(gFileHdr)); - } - Cleanup(&fd); - return 0; /* all expired */ - } - - if (!gPlay.bRefilling || gBuf.bEOF) - { /* nothing to do */ - button = rb->button_get_w_tmo(HZ/10); - } - else - { /* refill buffer */ - int read_now, got_now; - int buf_free; - long spinup; /* measure the spinup time */ - - /* how much can we reload, don't fill completely, would appear empty */ - buf_free = gBuf.bufsize - MAX(avail_audio, avail_video) - gBuf.high_water; - if (buf_free < 0) - buf_free = 0; /* just for safety */ - buf_free -= buf_free % gBuf.granularity; /* round down to granularity */ - - /* in one piece max. up to buffer end (wrap after that) */ - read_now = MIN(buf_free, gBuf.pBufEnd - gBuf.pBufFill); - - /* load piecewise, to stay responsive */ - read_now = MIN(read_now, gBuf.nReadChunk); - - if (read_now == buf_free) - gPlay.bRefilling = false; /* last piece requested */ - - spinup = *rb->current_tick; /* in case this is interesting below */ - - got_now = rb->read(fd, gBuf.pBufFill, read_now); - if (got_now != read_now || read_now == 0) - { - gBuf.bEOF = true; - gPlay.bRefilling = false; - } - - if (gPlay.bDiskSleep) /* statistics about the spinup time */ - { - spinup = *rb->current_tick - spinup; - gPlay.bDiskSleep = false; - if (spinup > gStats.maxSpinup) - gStats.maxSpinup = spinup; - if (spinup < gStats.minSpinup) - gStats.minSpinup = spinup; - - /* recalculate the low water mark from real measurements */ - gBuf.low_water = (gStats.maxSpinup + gBuf.spinup_safety) - * gFileHdr.bps_peak / 8 / HZ; - } - - if (!gPlay.bRefilling -#ifdef HAVE_DISK_STORAGE - && rb->global_settings->disk_spindown < 20 /* condition for test only */ -#endif - ) - { - rb->storage_sleep(); /* no point in leaving the disk run til timeout */ - gPlay.bDiskSleep = true; - } - - gBuf.pBufFill += got_now; - if (gBuf.pBufFill >= gBuf.pBufEnd) - gBuf.pBufFill = gBuf.pBufStart; /* wrap */ - - rb->yield(); /* have mercy with the other threads */ - button = rb->button_get(false); - } - - /* check keypresses */ - - if (button != BUTTON_NONE) - { - filepos = rb->lseek(fd, 0, SEEK_CUR); - - if (gPlay.bHasVideo) /* video position is more accurate */ - filepos -= Available(gBuf.pReadVideo); /* take video position */ - else - filepos -= Available(gBuf.pReadAudio); /* else audio */ - - switch (button) { /* set exit conditions */ - case BUTTON_OFF: - if (gFileHdr.magic == HEADER_MAGIC /* only if file has header */ - && !(gFileHdr.flags & FLAG_LOOP)) /* not for stills */ - { - gFileHdr.resume_pos = filepos; - rb->lseek(fd, 0, SEEK_SET); /* save resume position */ - rb->write(fd, &gFileHdr, sizeof(gFileHdr)); - } - Cleanup(&fd); - retval = 0; /* signal "stopped" to caller */ - break; - case VIDEO_STOP_SEEK: -#ifdef VIDEO_STOP_SEEK_PRE - if (lastbutton != VIDEO_STOP_SEEK_PRE) - break; -#endif - if (gPlay.bSeeking) - { - gPlay.bSeeking = false; - gPlay.state = playing; - SeekTo(fd, gPlay.nSeekPos); - } - else if (gPlay.state == playing) - { - gPlay.state = paused; - if (gPlay.bHasAudio) - rb->mp3_play_pause(false); /* pause audio */ - if (gPlay.bHasVideo) - rb->timer_unregister(); /* stop the timer */ - } - else if (gPlay.state == paused) - { - gPlay.state = playing; - if (gPlay.bHasAudio) - { - if (gPlay.bHasVideo) - SyncVideo(); - rb->mp3_play_pause(true); /* play audio */ - } - if (gPlay.bHasVideo) - { /* start the video */ -#if FREQ == 12000000 /* Ondio speed kludge */ - rb->timer_register(1, NULL, - gPlay.nFrameTimeAdjusted, timer4_isr); -#else - rb->timer_register(1, NULL, - gFileHdr.video_frametime, timer4_isr); -#endif - } - } - break; - case BUTTON_UP: - case BUTTON_UP | BUTTON_REPEAT: - if (gPlay.bHasAudio) - ChangeVolume(1); - break; - case BUTTON_DOWN: - case BUTTON_DOWN | BUTTON_REPEAT: - if (gPlay.bHasAudio) - ChangeVolume(-1); - break; - case BUTTON_LEFT: - case BUTTON_LEFT | BUTTON_REPEAT: - if (!gPlay.bSeeking) /* prepare seek */ - { - gPlay.nSeekPos = filepos; - gPlay.bSeeking = true; - gPlay.nSeekAcc = 0; - } - else if (gPlay.nSeekAcc > 0) /* other direction, stop sliding */ - gPlay.nSeekAcc = 0; - else - gPlay.nSeekAcc--; - break; - case BUTTON_RIGHT: - case BUTTON_RIGHT | BUTTON_REPEAT: - if (!gPlay.bSeeking) /* prepare seek */ - { - gPlay.nSeekPos = filepos; - gPlay.bSeeking = true; - gPlay.nSeekAcc = 0; - } - else if (gPlay.nSeekAcc < 0) /* other direction, stop sliding */ - gPlay.nSeekAcc = 0; - else - gPlay.nSeekAcc++; - break; -#ifdef VIDEO_DEBUG - case VIDEO_DEBUG: /* debug key */ - case VIDEO_DEBUG | BUTTON_REPEAT: - DrawBuf(); /* show buffer status */ - gPlay.nTimeOSD = FPS/2; - gPlay.bDirtyOSD = true; - break; -#endif - case VIDEO_CONTRAST_DOWN: /* contrast down */ - case VIDEO_CONTRAST_DOWN | BUTTON_REPEAT: - if (gPlay.bHasVideo) - ChangeContrast(-1); - break; - case VIDEO_CONTRAST_UP: /* contrast up */ - case VIDEO_CONTRAST_UP | BUTTON_REPEAT: - if (gPlay.bHasVideo) - ChangeContrast(1); - break; - default: - if (rb->default_event_handler_ex(button, Cleanup, &fd) - == SYS_USB_CONNECTED) - retval = -1; /* signal "aborted" to caller */ - break; - } - - lastbutton = button; - } /* if (button != BUTTON_NONE) */ - - - /* handle seeking */ - - if (gPlay.bSeeking) /* seeking? */ - { - if (gPlay.nSeekAcc < -MAX_ACC) - gPlay.nSeekAcc = -MAX_ACC; - else if (gPlay.nSeekAcc > MAX_ACC) - gPlay.nSeekAcc = MAX_ACC; - - gPlay.nSeekPos += gPlay.nSeekAcc * gBuf.nSeekChunk; - if (gPlay.nSeekPos < 0) - gPlay.nSeekPos = 0; - if (gPlay.nSeekPos > rb->filesize(fd) - gBuf.granularity) - { - gPlay.nSeekPos = rb->filesize(fd); - gPlay.nSeekPos -= gPlay.nSeekPos % gBuf.granularity; - } - DrawPosition(gPlay.nSeekPos, rb->filesize(fd)); - } - - - /* check + recover underruns */ - - if ((gPlay.bAudioUnderrun || gPlay.bVideoUnderrun) && !gBuf.bEOF) - { - gBuf.spinup_safety += HZ/2; /* add extra spinup time for the future */ - filepos = rb->lseek(fd, 0, SEEK_CUR); - - if (gPlay.bHasVideo && gPlay.bVideoUnderrun) - { - gStats.nVideoUnderruns++; - filepos -= Available(gBuf.pReadVideo); /* take video position */ - SeekTo(fd, filepos); - } - else if (gPlay.bHasAudio && gPlay.bAudioUnderrun) - { - gStats.nAudioUnderruns++; - filepos -= Available(gBuf.pReadAudio); /* else audio */ - SeekTo(fd, filepos); - } - } - - return retval; -} - - -static int main(char* filename) -{ - int file_size; - int fd; /* file descriptor handle */ - int read_now, got_now; - int button = 0; - int retval; - - /* try to open the file */ - fd = rb->open(filename, O_RDWR); - if (fd < 0) - return PLUGIN_ERROR; - file_size = rb->filesize(fd); - - /* reset pitch value to ensure synchronous playback */ - rb->sound_set_pitch(PITCH_SPEED_100); - - /* init statistics */ - rb->memset(&gStats, 0, sizeof(gStats)); - gStats.minAudioAvail = gStats.minVideoAvail = INT_MAX; - gStats.minSpinup = INT_MAX; - - /* init playback state */ - rb->memset(&gPlay, 0, sizeof(gPlay)); - - /* init buffer */ - rb->memset(&gBuf, 0, sizeof(gBuf)); - gBuf.pBufStart = rb->plugin_get_audio_buffer((size_t *)&gBuf.bufsize); - /*gBuf.bufsize = 1700*1024; // test, like 2MB version!!!! */ - gBuf.pBufFill = gBuf.pBufStart; /* all empty */ - - /* init OSD */ - rb->lcd_getstringsize("X", NULL, &retval); - gBuf.osd_height = (retval + 7) & ~7; - gBuf.osd_ypos = LCD_HEIGHT - gBuf.osd_height; - - /* load file header */ - read_now = sizeof(gFileHdr); - got_now = rb->read(fd, &gFileHdr, read_now); - rb->lseek(fd, 0, SEEK_SET); /* rewind to restart sector-aligned */ - if (got_now != read_now) - { - rb->close(fd); - return (PLUGIN_ERROR); - } - - /* check header */ - if (gFileHdr.magic != HEADER_MAGIC) - { /* old file, use default info */ - rb->memset(&gFileHdr, 0, sizeof(gFileHdr)); - gFileHdr.blocksize = SCREENSIZE; - if (file_size < SCREENSIZE * FPS) /* less than a second */ - gFileHdr.flags |= FLAG_LOOP; - gFileHdr.video_format = VIDEOFORMAT_RAW; - gFileHdr.video_width = LCD_WIDTH; - gFileHdr.video_height = LCD_HEIGHT; - gFileHdr.video_frametime = 11059200 / FPS; - gFileHdr.bps_peak = gFileHdr.bps_average = LCD_WIDTH * LCD_HEIGHT * FPS; - } - -#if FREQ == 12000000 /* Ondio speed kludge, 625 / 576 == 12000000 / 11059200 */ - gPlay.nFrameTimeAdjusted = (gFileHdr.video_frametime * 625) / 576; -#endif - - /* continue buffer init: align the end, calc low water, read sizes */ - gBuf.granularity = gFileHdr.blocksize; - while (gBuf.granularity % 512) /* common multiple of sector size */ - gBuf.granularity *= 2; - gBuf.bufsize -= gBuf.bufsize % gBuf.granularity; /* round down */ - gBuf.pBufEnd = gBuf.pBufStart + gBuf.bufsize; - gBuf.low_water = SPINUP_INIT * gFileHdr.bps_peak / 8000; - gBuf.spinup_safety = SPINUP_SAFETY * HZ / 1000; /* in time ticks */ - if (gFileHdr.audio_min_associated < 0) - gBuf.high_water = 0 - gFileHdr.audio_min_associated; - else - gBuf.high_water = 1; /* never fill buffer completely, would appear empty */ - gBuf.nReadChunk = (CHUNK + gBuf.granularity - 1); /* round up */ - gBuf.nReadChunk -= gBuf.nReadChunk % gBuf.granularity;/* and align */ - gBuf.nSeekChunk = rb->filesize(fd) / FF_TICKS; - gBuf.nSeekChunk += gBuf.granularity - 1; /* round up */ - gBuf.nSeekChunk -= gBuf.nSeekChunk % gBuf.granularity; /* and align */ - - /* prepare video playback, if contained */ - if (gFileHdr.video_format == VIDEOFORMAT_RAW) - { - gPlay.bHasVideo = true; - /* Turn off backlight timeout */ - backlight_ignore_timeout(); - } - - /* prepare audio playback, if contained */ - if (gFileHdr.audio_format == AUDIOFORMAT_MP3_BITSWAPPED) - { - gPlay.bHasAudio = true; - } - - /* start playback by seeking to zero or resume position */ - if (gFileHdr.resume_pos && WantResume(fd)) /* ask the user */ - SeekTo(fd, gFileHdr.resume_pos); - else - SeekTo(fd, 0); - - /* all that's left to do is keep the buffer full */ - do /* the main loop */ - { - retval = PlayTick(fd); - } while (retval > 0); - - if (retval < 0) /* aborted? */ - { - return PLUGIN_USB_CONNECTED; - } - -#ifndef DEBUG /* for release compilations, only display the stats in case of error */ - if (gStats.nAudioUnderruns || gStats.nVideoUnderruns) -#endif - { - /* display statistics */ - rb->lcd_clear_display(); - rb->snprintf(gPrint, sizeof(gPrint), "%d Audio Underruns", gStats.nAudioUnderruns); - rb->lcd_puts(0, 0, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "%d Video Underruns", gStats.nVideoUnderruns); - rb->lcd_puts(0, 1, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "%d MinAudio bytes", gStats.minAudioAvail); - rb->lcd_puts(0, 2, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "%d MinVideo bytes", gStats.minVideoAvail); - rb->lcd_puts(0, 3, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "MinSpinup %ld.%02ld", gStats.minSpinup/HZ, gStats.minSpinup%HZ); - rb->lcd_puts(0, 4, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "MaxSpinup %ld.%02ld", gStats.maxSpinup/HZ, gStats.maxSpinup%HZ); - rb->lcd_puts(0, 5, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "LowWater: %d", gBuf.low_water); - rb->lcd_puts(0, 6, gPrint); - rb->snprintf(gPrint, sizeof(gPrint), "HighWater: %d", gBuf.high_water); - rb->lcd_puts(0, 7, gPrint); - - rb->lcd_update(); - button = WaitForButton(); - } - return (button == SYS_USB_CONNECTED) ? PLUGIN_USB_CONNECTED : PLUGIN_OK; -} - - -/***************** Plugin Entry Point *****************/ - -enum plugin_status plugin_start(const void* parameter) -{ - if (parameter == NULL) - { - rb->splash(HZ*2, "Play .rvf file!"); - return PLUGIN_ERROR; - } - - /* now go ahead and have fun! */ - return main((char*) parameter); -} - -#endif /* #ifdef HAVE_LCD_BITMAP */ - -- cgit v1.2.3