📄 mpeg.c
字号:
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: mpeg.c,v 1.263 2004/01/15 15:32:49 bagder Exp $ * * Copyright (C) 2002 by Linus Nielsen Feltzing * * 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 <stdbool.h>#include "config.h"#include "debug.h"#include "panic.h"#include "id3.h"#include "mpeg.h"#include "ata.h"#include "string.h"#include <kernel.h>#include "thread.h"#include "errno.h"#include "mp3data.h"#include "buffer.h"#include "mp3_playback.h"#ifndef SIMULATOR#include "i2c.h"#include "mas.h"#include "dac.h"#include "system.h"#include "usb.h"#include "file.h"#include "hwcompat.h"#endif /* #ifndef SIMULATOR */extern void bitswap(unsigned char *data, int length);#ifdef HAVE_MAS3587Fstatic void init_recording(void);static void start_prerecording(void);static void start_recording(void);static void stop_recording(void);static int get_unsaved_space(void);#endif /* #ifdef HAVE_MAS3587F */#ifndef SIMULATORstatic int get_unplayed_space(void);static int get_playable_space(void);static int get_unswapped_space(void);#endif /* #ifndef SIMULATOR */#define MPEG_PLAY 1#define MPEG_STOP 2#define MPEG_PAUSE 3#define MPEG_RESUME 4#define MPEG_NEXT 5#define MPEG_PREV 6#define MPEG_FF_REWIND 7#define MPEG_FLUSH_RELOAD 8#define MPEG_RECORD 9#define MPEG_INIT_RECORDING 10#define MPEG_INIT_PLAYBACK 11#define MPEG_NEW_FILE 12#define MPEG_NEED_DATA 100#define MPEG_TRACK_CHANGE 101#define MPEG_SAVE_DATA 102#define MPEG_STOP_DONE 103#ifdef HAVE_MAS3587Fextern enum /* from mp3_playback.c */{ MPEG_DECODER, MPEG_ENCODER} mpeg_mode;#endif /* #ifdef HAVE_MAS3587F */extern char* playlist_peek(int steps);extern bool playlist_check(int steps);extern int playlist_next(int steps);extern int playlist_amount(void);extern void update_file_pos( int id, int pos );/* list of tracks in memory */#define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */#define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1)struct id3tag{ struct mp3entry id3; int mempos; bool used;};static struct id3tag *id3tags[MAX_ID3_TAGS];static struct id3tag _id3tags[MAX_ID3_TAGS];static unsigned int current_track_counter = 0;static unsigned int last_track_counter = 0;#ifndef SIMULATORstatic int tag_read_idx = 0;static int tag_write_idx = 0;static int num_tracks_in_memory(void){ return (tag_write_idx - tag_read_idx) & MAX_ID3_TAGS_MASK;}#endif /* #ifndef SIMULATOR */#ifndef SIMULATORstatic void debug_tags(void){#ifdef DEBUG_TAGS int i; for(i = 0;i < MAX_ID3_TAGS;i++) { DEBUGF("id3tags[%d]: %08x", i, id3tags[i]); if(id3tags[i]) DEBUGF(" - %s", id3tags[i]->id3.path); DEBUGF("\n"); } DEBUGF("read: %d, write :%d\n", tag_read_idx, tag_write_idx); DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory());#endif /* #ifdef DEBUG_TAGS */}static bool append_tag(struct id3tag *tag){ if(num_tracks_in_memory() < MAX_ID3_TAGS - 1) { id3tags[tag_write_idx] = tag; tag_write_idx = (tag_write_idx+1) & MAX_ID3_TAGS_MASK; debug_tags(); return true; } else { DEBUGF("Tag memory is full\n"); return false; }}static void remove_current_tag(void){ int oldidx = tag_read_idx; if(num_tracks_in_memory() > 0) { /* First move the index, so nobody tries to access the tag */ tag_read_idx = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; /* Now delete it */ id3tags[oldidx]->used = false; id3tags[oldidx] = NULL; debug_tags(); }}static void remove_all_non_current_tags(void){ int i = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; while (i != tag_write_idx) { id3tags[i]->used = false; id3tags[i] = NULL; i = (i+1) & MAX_ID3_TAGS_MASK; } tag_write_idx = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; debug_tags();}static void remove_all_tags(void){ int i; for(i = 0;i < MAX_ID3_TAGS;i++) remove_current_tag(); tag_write_idx = tag_read_idx; debug_tags();}#endif /* #ifndef SIMULATOR */static void set_elapsed(struct mp3entry* id3){ if ( id3->vbr ) { if ( id3->has_toc ) { /* calculate elapsed time using TOC */ int i; unsigned int remainder, plen, relpos, nextpos; /* find wich percent we're at */ for (i=0; i<100; i++ ) { if ( id3->offset < (int)(id3->toc[i] * (id3->filesize / 256)) ) { break; } } i--; if (i < 0) i = 0; relpos = id3->toc[i]; if (i < 99) { nextpos = id3->toc[i+1]; } else { nextpos = 256; } remainder = id3->offset - (relpos * (id3->filesize / 256)); /* set time for this percent (divide before multiply to prevent overflow on long files. loss of precision is negligible on short files) */ id3->elapsed = i * (id3->length / 100); /* calculate remainder time */ plen = (nextpos - relpos) * (id3->filesize / 256); id3->elapsed += (((remainder * 100) / plen) * (id3->length / 10000)); } else { /* no TOC exists. set a rough estimate using average bitrate */ int tpk = id3->length / (id3->filesize / 1024); id3->elapsed = id3->offset / 1024 * tpk; } } else /* constant bitrate == simple frame calculation */ id3->elapsed = id3->offset / id3->bpf * id3->tpf;}static bool paused; /* playback is paused */static unsigned int mpeg_errno;#ifdef SIMULATORstatic bool is_playing = false;static bool playing = false;#elsestatic int last_dma_tick = 0;extern unsigned long mas_version_code;static struct event_queue mpeg_queue;static char mpeg_stack[DEFAULT_STACK_SIZE + 0x1000];static char mpeg_thread_name[] = "mpeg";static int mp3buflen;static int mp3buf_write;static int mp3buf_swapwrite;static int mp3buf_read;static int last_dma_chunk_size;static bool playing; /* We are playing an MP3 stream */static bool play_pending; /* We are about to start playing */static bool is_playing; /* We are (attempting to) playing MP3 files */static bool filling; /* We are filling the buffer with data from disk */static bool dma_underrun; /* True when the DMA has stopped because of slow disk reading (read error, shaking) */static int low_watermark; /* Dynamic low watermark level */static int low_watermark_margin; /* Extra time in seconds for watermark */static int lowest_watermark_level; /* Debug value to observe the buffer usage */#ifdef HAVE_MAS3587Fstatic bool is_recording; /* We are recording */static bool stop_pending;unsigned long record_start_time; /* Value of current_tick when recording was started */static bool saving; /* We are saving the buffer to disk */static char recording_filename[MAX_PATH];static int rec_frequency_index; /* For create_xing_header() calls */static int rec_version_index; /* For create_xing_header() calls */static bool disable_xing_header; /* When splitting files */static bool prerecording; /* True if prerecording is enabled */static bool is_prerecording; /* True if we are prerecording */static int prerecord_buffer[MPEG_MAX_PRERECORD_SECONDS]; /* Array of buffer indexes for each prerecorded second */static int prerecord_index; /* Current index in the prerecord buffer */static int prerecording_max_seconds; /* Max number of seconds to store */static int prerecord_count; /* Number of seconds in the prerecord buffer */static int prerecord_timeout; /* The tick count of the next prerecord data store */#endif /* #ifdef HAVE_MAS3587F */static int mpeg_file;/* Synchronization variables */#ifdef HAVE_MAS3587Fstatic bool init_recording_done;static bool init_playback_done;#endif /* #ifdef HAVE_MAS3587F */static bool mpeg_stop_done;static void recalculate_watermark(int bitrate){ int bytes_per_sec; int time = ata_spinup_time; /* A bitrate of 0 probably means empty VBR header. We play safe and set a high threshold */ if(bitrate == 0) bitrate = 320; bytes_per_sec = bitrate * 1000 / 8; if(time) { /* No drive spins up faster than 3.5s */ if(time < 350) time = 350; time = time * 3; low_watermark = ((low_watermark_margin * HZ + time) * bytes_per_sec) / HZ; } else { low_watermark = MPEG_LOW_WATER; }}void mpeg_set_buffer_margin(int seconds){ low_watermark_margin = seconds;}void mpeg_get_debugdata(struct mpeg_debug *dbgdata){ dbgdata->mp3buflen = mp3buflen; dbgdata->mp3buf_write = mp3buf_write; dbgdata->mp3buf_swapwrite = mp3buf_swapwrite; dbgdata->mp3buf_read = mp3buf_read; dbgdata->last_dma_chunk_size = last_dma_chunk_size; dbgdata->dma_on = (SCR0 & 0x80) != 0; dbgdata->playing = playing; dbgdata->play_pending = play_pending; dbgdata->is_playing = is_playing; dbgdata->filling = filling; dbgdata->dma_underrun = dma_underrun; dbgdata->unplayed_space = get_unplayed_space(); dbgdata->playable_space = get_playable_space(); dbgdata->unswapped_space = get_unswapped_space(); dbgdata->low_watermark_level = low_watermark; dbgdata->lowest_watermark_level = lowest_watermark_level;}#ifdef DEBUGstatic void dbg_timer_start(void){ /* We are using timer 2 */ TSTR &= ~0x04; /* Stop the timer */ TSNC &= ~0x04; /* No synchronization */ TMDR &= ~0x44; /* Operate normally */ TCNT2 = 0; /* Start counting at 0 */ TCR2 = 0x03; /* Sysclock/8 */ TSTR |= 0x04; /* Start timer 2 */}static int dbg_cnt2us(unsigned int cnt){ return (cnt * 10000) / (FREQ/800);}#endif /* #ifdef DEBUG */static int get_unplayed_space(void){ int space = mp3buf_write - mp3buf_read; if (space < 0) space += mp3buflen; return space;}static int get_playable_space(void){ int space = mp3buf_swapwrite - mp3buf_read; if (space < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -