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

📄 video.c

📁 编译后直接运行的MP3播放器全部C语言源代码 一个包含FAT文件系统、系统引导 Boot、FLASH Driver等内容的
💻 C
📖 第 1 页 / 共 2 页
字号:
    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 == BUTTON_PLAY);}int SeekTo(int fd, int nPos){    int read_now, got_now;    if (gPlay.bHasAudio)        rb->mp3_play_stop(); // stop audio ISR    if (gPlay.bHasVideo)        timer_set(0); // stop the timer 4    rb->lseek(fd, nPos, SEEK_SET);    gBuf.pBufFill = gBuf.pBufStart; // all empty    gBuf.pReadVideo = gBuf.pReadAudio = gBuf.pBufStart;    read_now = (PRECHARGE + gBuf.granularity - 1); // round up    read_now -= read_now % gBuf.granularity; // 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;        timer_set(gFileHdr.video_frametime); // start display interrupt    }    return 0;}// returns >0 if continue, =0 to stop, <0 to abort (USB)int PlayTick(int fd){    int button;    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));        }        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;                // 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        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.bRefilling             && rb->global_settings->disk_spindown < 20) // condition for test only        {            rb->ata_sleep(); // no point in leaving the disk run til timeout        }        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));            }            retval = 0; // signal "stop" to caller            break;        case SYS_USB_CONNECTED:            retval = -1; // signal "abort" to caller            break;        case BUTTON_PLAY:            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)                    and_b(~0x10, &TSTR); // stop the timer 4            }            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)                    or_b(0x10, &TSTR); // start the video            }            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;        case BUTTON_F1: // debug key        case BUTTON_F1 | BUTTON_REPEAT:            DrawBuf(); // show buffer status            gPlay.nTimeOSD = 30;            gPlay.bDirtyOSD = true;            break;        }    } /*  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)    {        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;}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);    // init statistics    rb->memset(&gStats, 0, sizeof(gStats));    gStats.minAudioAvail = gStats.minVideoAvail = INT_MAX;    // init playback state    rb->memset(&gPlay, 0, sizeof(gPlay));    // init buffer    rb->memset(&gBuf, 0, sizeof(gBuf));    gBuf.pOSD = rb->lcd_framebuffer + LCD_WIDTH*7; // last screen line    gBuf.pBufStart = rb->plugin_get_mp3_buffer(&gBuf.bufsize);    //gBuf.bufsize = 1700*1024; // test, like 2MB version!!!!    gBuf.pBufFill = gBuf.pBufStart; // all empty    // 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 = CLOCK / FPS;        gFileHdr.bps_peak = gFileHdr.bps_average = LCD_WIDTH * LCD_HEIGHT * FPS;    }        // 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 * gFileHdr.bps_peak / 8000;    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;        if (rb->global_settings->backlight_timeout > 0)            rb->backlight_set_timeout(1); // keep the light on    }    // 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);    rb->close(fd); // close the file    if (gPlay.bHasVideo)        timer_set(0); // stop video ISR, now I can use the display again    if (gPlay.bHasAudio)        rb->mp3_play_stop(); // stop audio ISR    // restore normal backlight setting    rb->backlight_set_timeout(rb->global_settings->backlight_timeout);    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), "ReadChunk: %d", gBuf.nReadChunk);        rb->lcd_puts(0, 4, gPrint);        rb->snprintf(gPrint, sizeof(gPrint), "SeekChunk: %d", gBuf.nSeekChunk);        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(struct plugin_api* api, void* parameter){    int ret;    /* 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        if (parameter == NULL)    {        rb->splash(HZ*2, true, "Play .rvf file!");        return PLUGIN_ERROR;    }    // now go ahead and have fun!    ret = main((char*) parameter);    if (ret==PLUGIN_USB_CONNECTED)        rb->usb_screen();    return ret;}#endif // #ifdef HAVE_LCD_BITMAP#endif // #ifndef SIMULATOR

⌨️ 快捷键说明

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