⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video.c

📁 编译后直接运行的MP3播放器全部C语言源代码 一个包含FAT文件系统、系统引导 Boot、FLASH Driver等内容的
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************             __________               __   ___.*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \*                     \/            \/     \/    \/            \/* $Id: video.c,v 1.15 2004/03/08 20:14:04 hohensoh Exp $** 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** 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.*****************************************************************************//****************** imports ******************/#include "plugin.h"#include "sh7034.h"#include "system.h"#include "../apps/recorder/widgets.h" // not in search path, booh#ifndef SIMULATOR // not for simulator by now#ifdef HAVE_LCD_BITMAP // and definitely not for the Player, haha/****************** constants ******************/#define IMIA4 (*((volatile unsigned long*)0x09000180)) // timer 4#define INT_MAX ((int)(~(unsigned)0 >> 1))#define INT_MIN (-INT_MAX-1)#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 PRECHARGE (1024 * 64) // the initial filling before starting to play#define SPINUP 3300 // from what level on to refill, in milliseconds#define CHUNK (1024*32) // read size/****************** prototypes ******************/void timer_set(unsigned period); // setup ISR and timer registersvoid timer4_isr(void) __attribute__((interrupt_handler)); // IMIA4 ISRint 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#define CLOCK 11059200 // SH CPU clock// 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 stillstypedef 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 struct plugin_api* rb; /* here is a global api struct pointer */static char gPrint[32]; /* a global printf buffer, saves stack */// playstatestatic 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} gPlay;// buffer informationstatic struct{    int bufsize;    int granularity; // common multiple of block and sector size    unsigned char* pBufStart; // start of ring buffer    unsigned char* pBufEnd; // end of ring buffer    unsigned char* pOSD; // OSD memory (112 bytes for 112*8 pixels)    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 nReadChunk; // how much data for normal buffer fill    int nSeekChunk; // how much data while seeking} gBuf;// statisticsstatic struct{    int minAudioAvail;    int minVideoAvail;    int nAudioUnderruns;    int nVideoUnderruns;} gStats;tFileHeader gFileHdr; // file header/****************** implementation ******************/// tool function: return how much playable audio/video is leftint Available(unsigned char* pSnapshot){    if (pSnapshot <= gBuf.pBufFill)        return gBuf.pBufFill - pSnapshot;    else        return gBuf.bufsize - (pSnapshot - gBuf.pBufFill);}// debug function to draw buffer indicatorsvoid DrawBuf(void){    int fill, video, audio;    rb->memset(gBuf.pOSD, 0x10, LCD_WIDTH); // draw line    gBuf.pOSD[0] = gBuf.pOSD[LCD_WIDTH-1] = 0xFE; // ends    // 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;    gBuf.pOSD[fill] |= 0x20; // below the line, two pixels    gBuf.pOSD[video] |= 0x08; // one above    gBuf.pOSD[audio] |= 0x04; // two above    if (gPlay.state == paused) // we have to draw ourselves        rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);    else        gPlay.bDirtyOSD = true; // redraw it with next timer IRQ}// helper function to draw a position indicatorvoid DrawPosition(int pos, int total){    int w,h;    int sec; // estimated seconds    int percent;    /* 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_puts(0, 7, gPrint);    /* draw a slider over the rest of the line */    rb->lcd_getstringsize(gPrint, &w, &h);    w++;    percent = pos/(total/100);    rb->slidebar(w, LCD_HEIGHT-7, LCD_WIDTH-w, 7, percent, Grow_Right);    if (gPlay.state == paused) // we have to draw ourselves        rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);    else // let the display time do it    {        gPlay.nTimeOSD = 70;        gPlay.bDirtyOSD = true; // redraw it with next timer IRQ    }}// helper function to change the volume by a certain amount, +/-void ChangeVolume(int delta){    int vol = rb->global_settings->volume + delta;    if (vol > 100) vol = 100;    else if (vol < 0) vol = 0;    if (vol != rb->global_settings->volume)    {        rb->mpeg_sound_set(SOUND_VOLUME, vol);        rb->global_settings->volume = vol;        rb->snprintf(gPrint, sizeof(gPrint), "Vol: %d", vol);        rb->lcd_puts(0, 7, gPrint);        if (gPlay.state == paused) // we have to draw ourselves            rb->lcd_update_rect(0, LCD_HEIGHT-8, LCD_WIDTH, 8);        else // let the display time do it        {            gPlay.nTimeOSD = 50; // display it for 50 frames            gPlay.bDirtyOSD = true; // let the refresh copy it to LCD        }    }}// sync the video to the current audiovoid 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;    }}// setup ISR and timer registersvoid timer_set(unsigned period){    if (period)    {        and_b(~0x10, &TSTR); // Stop the timer 4        and_b(~0x10, &TSNC); // No synchronization        and_b(~0x10, &TMDR); // Operate normally        IMIA4 = (unsigned long)timer4_isr; // install ISR        TSR4 &= ~0x01;        TIER4 = 0xF9; // Enable GRA match interrupt        GRA4 = (unsigned short)(period/4 - 1);        TCR4 = 0x22; // clear at GRA match, sysclock/4        IPRD = (IPRD & 0xFF0F) | 0x0010; // interrupt priority 1 (lowest)        or_b(0x10, &TSTR); // start timer 4    }    else    {        and_b(~0x10, &TSTR); // stop the timer 4        IPRD = (IPRD & 0xFF0F); // disable interrupt    }}// timer interrupt handler to display a framevoid timer4_isr(void) // IMIA4{    int available;    tAudioFrameHeader* pAudioBuf;    int height; // height to display    TSR4 &= ~0x01; // clear the interrupt    // xor_b(0x40, &PBDRL); // test: toggle LED (PB6)    // debug code/*    gPlay.nTimeOSD = 1;    DrawBuf();    gPlay.bDirtyOSD = true;*/    // reduce height if we have OSD on    height = gFileHdr.video_height/8;            if (gPlay.nTimeOSD > 0)    {        gPlay.nTimeOSD--;        height = MIN(LCD_HEIGHT/8-1, height); // reserve bottom line        if (gPlay.bDirtyOSD)        {   // OSD to bottom line            rb->lcd_blit(gBuf.pOSD, 0, LCD_HEIGHT/8-1,                 LCD_WIDTH, 1, LCD_WIDTH);            gPlay.bDirtyOSD = false;        }    }    rb->lcd_blit(gBuf.pReadVideo, 0, 0,         gFileHdr.video_width, height, 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;                timer_set(0); // 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 datavoid GetMoreMp3(unsigned char** start, int* 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;}int WaitForButton(void){    int button;        do    {        button = rb->button_get(true);    } while ((button & BUTTON_REL) && button != SYS_USB_CONNECTED);        return button;}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");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -