📄 mpeg.c
字号:
/* Stop the current stream */ mp3_play_stop(); playing = false; filling = false; if(mpeg_file >= 0) close(mpeg_file); mpeg_file = -1; remove_all_tags();}static void update_playlist(void){ int index; if (num_tracks_in_memory() > 0) { index = playlist_next(id3tags[tag_read_idx]->id3.index); id3tags[tag_read_idx]->id3.index = index; }}static void track_change(void){ DEBUGF("Track change\n");#ifdef HAVE_MAS3587F /* Reset the AVC */ mpeg_sound_set(SOUND_AVC, -1);#endif /* #ifdef HAVE_MAS3587F */ remove_current_tag(); update_playlist(); current_track_counter++;}#ifdef DEBUGvoid hexdump(unsigned char *buf, int len){ int i; for(i = 0;i < len;i++) { if(i && (i & 15) == 0) { DEBUGF("\n"); } DEBUGF("%02x ", buf[i]); } DEBUGF("\n");}#endif /* #ifdef DEBUG */static void start_playback_if_ready(void){ int playable_space; playable_space = mp3buf_swapwrite - mp3buf_read; if(playable_space < 0) playable_space += mp3buflen; /* See if we have started playing yet. If not, do it. */ if(play_pending || dma_underrun) { /* If the filling has stopped, and we still haven't reached the watermark, the file must be smaller than the watermark. We must still play it. */ if((playable_space >= MPEG_PLAY_PENDING_THRESHOLD) || !filling || dma_underrun) { DEBUGF("P\n"); play_pending = false; playing = true; if (!paused) { last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); mp3_play_data(mp3buf + mp3buf_read, last_dma_chunk_size, transfer_end); dma_underrun = false; last_dma_tick = current_tick; mp3_play_pause(true); } /* Tell ourselves that we need more data */ queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); } }}static bool swap_one_chunk(void){ int free_space_left; int amount_to_swap; free_space_left = get_unswapped_space(); if(free_space_left == 0 && !play_pending) return false; /* Swap in larger chunks when the user is waiting for the playback to start, or when there is dangerously little playable data left */ if(play_pending) amount_to_swap = MIN(MPEG_PLAY_PENDING_SWAPSIZE, free_space_left); else { if(get_playable_space() < low_watermark) amount_to_swap = MIN(MPEG_LOW_WATER_SWAP_CHUNKSIZE, free_space_left); else amount_to_swap = MIN(MPEG_SWAP_CHUNKSIZE, free_space_left); } if(mp3buf_write < mp3buf_swapwrite) amount_to_swap = MIN(mp3buflen - mp3buf_swapwrite, amount_to_swap); else amount_to_swap = MIN(mp3buf_write - mp3buf_swapwrite, amount_to_swap); bitswap(mp3buf + mp3buf_swapwrite, amount_to_swap); mp3buf_swapwrite += amount_to_swap; if(mp3buf_swapwrite >= mp3buflen) { mp3buf_swapwrite = 0; } return true;}static const unsigned char empty_id3_header[] ={ 'I', 'D', '3', 0x04, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x76 /* Size is 4096 minus 10 bytes for the header */};#ifdef HAVE_MAS3587Fstatic unsigned long get_last_recorded_header(void){ unsigned long tmp[2]; /* Read the frame data from the MAS and reconstruct it with the frame sync and all */ mas_readmem(MAS_BANK_D0, 0xfd1, tmp, 2); return 0xffe00000 | ((tmp[0] & 0x7c00) << 6) | (tmp[1] & 0xffff);}#endif /* #ifdef HAVE_MAS3587F */static void mpeg_thread(void){ static int pause_tick = 0; static unsigned int pause_track = 0; struct event ev; int len; int free_space_left; int unplayed_space_left; int amount_to_read; int t1, t2; int start_offset;#ifdef HAVE_MAS3587F int amount_to_save; int writelen; int framelen; unsigned long saved_header = 0; int startpos; int rc; int offset; int countdown;#endif /* #ifdef HAVE_MAS3587F */ is_playing = false; play_pending = false; playing = false; mpeg_file = -1; while(1) {#ifdef HAVE_MAS3587F if(mpeg_mode == MPEG_DECODER) {#endif /* #ifdef HAVE_MAS3587F */ yield(); /* Swap if necessary, and don't block on the queue_wait() */ if(swap_one_chunk()) { queue_wait_w_tmo(&mpeg_queue, &ev, 0); } else { DEBUGF("S R:%x W:%x SW:%x\n", mp3buf_read, mp3buf_write, mp3buf_swapwrite); queue_wait(&mpeg_queue, &ev); } start_playback_if_ready(); switch(ev.id) { case MPEG_PLAY: DEBUGF("MPEG_PLAY\n");#ifdef HAVE_FMRADIO /* Silence the A/D input, it may be on because the radio may be playing */ mas_codec_writereg(6, 0x0000);#endif /* #ifdef HAVE_FMRADIO */ /* Stop the current stream */ play_pending = false; playing = false; paused = false; mp3_play_pause(false); reset_mp3_buffer(); remove_all_tags(); if(mpeg_file >= 0) close(mpeg_file); if ( new_file(0) == -1 ) { is_playing = false; track_change(); break; } start_offset = (int)ev.data; /* mid-song resume? */ if (start_offset) { struct mp3entry* id3 = &id3tags[tag_read_idx]->id3; lseek(mpeg_file, start_offset, SEEK_SET); id3->offset = start_offset; set_elapsed(id3); } else { /* skip past id3v2 tag */ lseek(mpeg_file, id3tags[tag_read_idx]->id3.first_frame_offset, SEEK_SET); } /* Make it read more data */ filling = true; queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); /* Tell the file loading code that we want to start playing as soon as we have some data */ play_pending = true; update_playlist(); current_track_counter++; break; case MPEG_STOP: DEBUGF("MPEG_STOP\n"); is_playing = false; paused = false; stop_playing(); mpeg_stop_done = true; break; case MPEG_PAUSE: DEBUGF("MPEG_PAUSE\n"); /* Stop the current stream */ paused = true; playing = false; pause_tick = current_tick; pause_track = current_track_counter; mp3_play_pause(false); break; case MPEG_RESUME: DEBUGF("MPEG_RESUME\n"); /* Continue the current stream */ paused = false; if (!play_pending) { playing = true; if ( current_track_counter == pause_track ) last_dma_tick += current_tick - pause_tick; else last_dma_tick = current_tick; pause_tick = 0; mp3_play_pause(true); } break; case MPEG_NEXT: DEBUGF("MPEG_NEXT\n"); /* is next track in ram? */ if ( num_tracks_in_memory() > 1 ) { int unplayed_space_left, unswapped_space_left; /* stop the current stream */ play_pending = false; playing = false; mp3_play_pause(false); track_change(); mp3buf_read = id3tags[tag_read_idx]->mempos; last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); mp3_play_data(mp3buf + mp3buf_read, last_dma_chunk_size, transfer_end); dma_underrun = false; last_dma_tick = current_tick; unplayed_space_left = get_unplayed_space(); unswapped_space_left = get_unswapped_space(); /* should we start reading more data? */ if(!filling && (unplayed_space_left < low_watermark)) { filling = true; queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); play_pending = true; } else if(unswapped_space_left && unswapped_space_left > unplayed_space_left) { /* Stop swapping the data from the previous file */ mp3buf_swapwrite = mp3buf_read; play_pending = true; } else { playing = true; if (!paused) mp3_play_pause(true); } } else { if (!playlist_check(1)) break; /* stop the current stream */ play_pending = false; playing = false; mp3_play_pause(false); reset_mp3_buffer(); remove_all_tags(); /* Open the next file */ if (mpeg_file >= 0) close(mpeg_file); if (new_file(1) < 0) { DEBUGF("No more files to play\n"); filling = false; } else { /* Make it read more data */ filling = true; queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); /* Tell the file loading code that we want to start playing as soon as we have some data */ play_pending = true; update_playlist(); current_track_counter++; } } break; case MPEG_PREV: { DEBUGF("MPEG_PREV\n"); if (!playlist_check(-1)) break; /* stop the current stream */ play_pending = false; playing = false; mp3_play_pause(false); reset_mp3_buffer(); remove_all_tags(); /* Open the next file */ if (mpeg_file >= 0) close(mpeg_file); if (new_file(-1) < 0) { DEBUGF("No more files to play\n"); filling = false; } else { /* Make it read more data */ filling = true; queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); /* Tell the file loading code that we want to start playing as soon as we have some data */ play_pending = true; update_playlist(); current_track_counter++; } break; } case MPEG_FF_REWIND: { struct mp3entry *id3 = mpeg_current_track(); unsigned int oldtime = id3->elapsed; unsigned int newtime = (unsigned int)ev.data; int curpos, newpos, diffpos; DEBUGF("MPEG_FF_REWIND\n"); id3->elapsed = newtime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -