123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- #include <rtthread.h>
- #include <dfs_posix.h>
- #include <mp3/pub/mp3dec.h>
- #include <string.h>
- #include "board.h"
- #include "netbuffer.h"
- #include "player_ui.h"
- #include "player_bg.h"
- #define MP3_AUDIO_BUF_SZ 8192
- #ifndef MIN
- #define MIN(x, y) ((x) < (y)? (x) : (y))
- #endif
- rt_uint8_t mp3_fd_buffer[MP3_AUDIO_BUF_SZ];
- struct mp3_decoder
- {
- /* mp3 information */
- HMP3Decoder decoder;
- MP3FrameInfo frame_info;
- rt_uint32_t frames;
- /* mp3 file descriptor */
- rt_size_t (*fetch_data)(void* parameter, rt_uint8_t *buffer, rt_size_t length);
- void* fetch_parameter;
- /* mp3 read session */
- rt_uint8_t *read_buffer, *read_ptr;
- rt_int32_t read_offset;
- rt_uint32_t bytes_left, bytes_left_before_decoding;
- /* audio device */
- rt_device_t snd_device;
- };
- static rt_err_t mp3_decoder_tx_done(rt_device_t dev, void *buffer)
- {
- /* release memory block */
- sbuf_release(buffer);
- return RT_EOK;
- }
- void mp3_decoder_init(struct mp3_decoder* decoder)
- {
- RT_ASSERT(decoder != RT_NULL);
- /* init read session */
- decoder->read_ptr = RT_NULL;
- decoder->bytes_left_before_decoding = decoder->bytes_left = 0;
- decoder->frames = 0;
- // decoder->read_buffer = rt_malloc(MP3_AUDIO_BUF_SZ);
- decoder->read_buffer = &mp3_fd_buffer[0];
- if (decoder->read_buffer == RT_NULL) return;
- decoder->decoder = MP3InitDecoder();
- /* open audio device */
- decoder->snd_device = rt_device_find("snd");
- if (decoder->snd_device != RT_NULL)
- {
- /* set tx complete call back function */
- rt_device_set_tx_complete(decoder->snd_device, mp3_decoder_tx_done);
- rt_device_open(decoder->snd_device, RT_DEVICE_OFLAG_WRONLY);
- }
- }
- void mp3_decoder_detach(struct mp3_decoder* decoder)
- {
- RT_ASSERT(decoder != RT_NULL);
- /* close audio device */
- if (decoder->snd_device != RT_NULL)
- rt_device_close(decoder->snd_device);
- /* release mp3 decoder */
- MP3FreeDecoder(decoder->decoder);
- }
- struct mp3_decoder* mp3_decoder_create()
- {
- struct mp3_decoder* decoder;
- /* allocate object */
- decoder = (struct mp3_decoder*) rt_malloc (sizeof(struct mp3_decoder));
- if (decoder != RT_NULL)
- {
- mp3_decoder_init(decoder);
- }
- return decoder;
- }
- void mp3_decoder_delete(struct mp3_decoder* decoder)
- {
- RT_ASSERT(decoder != RT_NULL);
- /* de-init mp3 decoder object */
- mp3_decoder_detach(decoder);
- /* release this object */
- rt_free(decoder);
- }
- rt_uint32_t current_offset = 0;
- static rt_int32_t mp3_decoder_fill_buffer(struct mp3_decoder* decoder)
- {
- rt_size_t bytes_read;
- rt_size_t bytes_to_read;
- // rt_kprintf("left: %d. refilling inbuffer...\n", decoder->bytes_left);
- if (decoder->bytes_left > 0)
- {
- // better: move unused rest of buffer to the start
- rt_memmove(decoder->read_buffer, decoder->read_ptr, decoder->bytes_left);
- }
- bytes_to_read = (MP3_AUDIO_BUF_SZ - decoder->bytes_left) & ~(512 - 1);
- bytes_read = decoder->fetch_data(decoder->fetch_parameter,
- (rt_uint8_t *)(decoder->read_buffer + decoder->bytes_left),
- bytes_to_read);
- if (bytes_read != 0)
- {
- decoder->read_ptr = decoder->read_buffer;
- decoder->read_offset = 0;
- decoder->bytes_left = decoder->bytes_left + bytes_read;
- return 0;
- }
- else
- {
- rt_kprintf("can't read more data\n");
- return -1;
- }
- }
- int mp3_decoder_run(struct mp3_decoder* decoder)
- {
- int err;
- rt_uint16_t* buffer;
- rt_uint32_t delta;
- RT_ASSERT(decoder != RT_NULL);
- if (player_is_playing() != RT_TRUE) return -1;
- if ((decoder->read_ptr == RT_NULL) || decoder->bytes_left < 2*MAINBUF_SIZE)
- {
- if(mp3_decoder_fill_buffer(decoder) != 0)
- return -1;
- }
- // rt_kprintf("read offset: 0x%08x\n", decoder->read_ptr - decoder->read_buffer);
- decoder->read_offset = MP3FindSyncWord(decoder->read_ptr, decoder->bytes_left);
- if (decoder->read_offset < 0)
- {
- /* discard this data */
- rt_kprintf("outof sync, byte left: %d\n", decoder->bytes_left);
- decoder->bytes_left = 0;
- return 0;
- }
- decoder->read_ptr += decoder->read_offset;
- delta = decoder->read_offset;
- decoder->bytes_left -= decoder->read_offset;
- if (decoder->bytes_left < 1024)
- {
- /* fill more data */
- if(mp3_decoder_fill_buffer(decoder) != 0)
- return -1;
- }
- /* get a decoder buffer */
- buffer = (rt_uint16_t*)sbuf_alloc();
- decoder->bytes_left_before_decoding = decoder->bytes_left;
- err = MP3Decode(decoder->decoder, &decoder->read_ptr,
- (int*)&decoder->bytes_left, (short*)buffer, 0);
- delta += (decoder->bytes_left_before_decoding - decoder->bytes_left);
- current_offset += delta;
- player_set_position(current_offset);
- // rt_kprintf("bytes left after decode: %d\n", decoder->bytes_left);
- decoder->frames++;
- if (err != ERR_MP3_NONE)
- {
- switch (err)
- {
- case ERR_MP3_INDATA_UNDERFLOW:
- rt_kprintf("ERR_MP3_INDATA_UNDERFLOW\n");
- decoder->bytes_left = 0;
- if(mp3_decoder_fill_buffer(decoder) != 0)
- {
- /* release this memory block */
- sbuf_release(buffer);
- return -1;
- }
- break;
- case ERR_MP3_MAINDATA_UNDERFLOW:
- /* do nothing - next call to decode will provide more mainData */
- rt_kprintf("ERR_MP3_MAINDATA_UNDERFLOW\n");
- break;
- default:
- rt_kprintf("unknown error: %d, left: %d\n", err, decoder->bytes_left);
- // skip this frame
- if (decoder->bytes_left > 0)
- {
- decoder->bytes_left --;
- decoder->read_ptr ++;
- }
- else
- {
- // TODO
- RT_ASSERT(0);
- }
- break;
- }
- /* release this memory block */
- sbuf_release(buffer);
- }
- else
- {
- /* no error */
- MP3GetLastFrameInfo(decoder->decoder, &decoder->frame_info);
- /* set sample rate */
- /* write to sound device */
- if (decoder->frame_info.outputSamps > 0)
- {
- rt_device_write(decoder->snd_device, 0, buffer, decoder->frame_info.outputSamps * 2);
- }
- else
- {
- /* no output */
- sbuf_release(buffer);
- }
- }
- return 0;
- }
- static int mp3_parse_id3v1(int fd, struct tag_info *info)
- {
- lseek(fd, -128, SEEK_END);
- read(fd, (char *) mp3_fd_buffer, 128);
- /* ID3v1 */
- if (strncmp("TAG", (char *) mp3_fd_buffer, 3) == 0)
- {
- strncpy(info->title, (char *) mp3_fd_buffer + 3, MIN(30, sizeof(info->title) - 1));
- strncpy(info->artist, (char *) mp3_fd_buffer + 3 + 30, MIN(30, sizeof(info->artist) - 1));
- return 0;
- }
- return -1;
- }
- static int mp3_parse_id3v2(int fd, struct tag_info *info)
- {
- rt_uint32_t p = 0;
- lseek(fd, 0, SEEK_SET);
- read(fd, (char *) mp3_fd_buffer, sizeof(mp3_fd_buffer));
- if (strncmp("ID3", (char *) mp3_fd_buffer, 3) == 0)
- {
- rt_uint32_t tag_size, frame_size, i;
- rt_uint8_t version_major;
- int frame_header_size;
- tag_size = ((rt_uint32_t) mp3_fd_buffer[6] << 21) | ((rt_uint32_t) mp3_fd_buffer[7] << 14) | ((rt_uint16_t) mp3_fd_buffer[8] << 7) | mp3_fd_buffer[9];
- info->data_start = tag_size;
- version_major = mp3_fd_buffer[3];
- if (version_major >= 3)
- {
- frame_header_size = 10;
- }
- else
- {
- frame_header_size = 6;
- }
- i = p = 10;
- // iterate through frames
- while (p < tag_size)
- {
- if (version_major >= 3)
- {
- frame_size = ((rt_uint32_t) mp3_fd_buffer[i + 4] << 24) | ((rt_uint32_t) mp3_fd_buffer[i + 5] << 16) | ((rt_uint16_t) mp3_fd_buffer[i + 6] << 8) | mp3_fd_buffer[i + 7];
- }
- else
- {
- frame_size = ((rt_uint32_t) mp3_fd_buffer[i + 3] << 14) | ((rt_uint16_t) mp3_fd_buffer[i + 4] << 7) | mp3_fd_buffer[i + 5];
- }
- if (i + frame_size + frame_header_size + frame_header_size >= sizeof(mp3_fd_buffer))
- {
- if (frame_size + frame_header_size > sizeof(mp3_fd_buffer))
- {
- lseek(fd, p + frame_size + frame_header_size, SEEK_CUR);
- read(fd, (char *) mp3_fd_buffer, sizeof(mp3_fd_buffer));
- p += frame_size + frame_header_size;
- i = 0;
- continue;
- }
- else
- {
- int r = sizeof(mp3_fd_buffer) - i;
- memmove(mp3_fd_buffer, mp3_fd_buffer + i, r);
- read(fd, (char *) mp3_fd_buffer + r, i);
- i = 0;
- }
- }
- if (strncmp("TT2", (char *) mp3_fd_buffer + i, 3) == 0 || strncmp("TIT2", (char *) mp3_fd_buffer + i, 4) == 0)
- {
- strncpy(info->title, (char *) mp3_fd_buffer + i + frame_header_size + 1, MIN(frame_size - 1, sizeof(info->title) - 1));
- }
- else if (strncmp("TP1", (char *) mp3_fd_buffer + i, 3) == 0 || strncmp("TPE1", (char *) mp3_fd_buffer + i, 4) == 0)
- {
- strncpy(info->artist, (char *) mp3_fd_buffer + i + frame_header_size + 1, MIN(frame_size - 1, sizeof(info->artist) - 1));
- }
- p += frame_size + frame_header_size;
- i += frame_size + frame_header_size;
- }
- return 0;
- }
- return -1;
- }
- /* get mp3 information */
- void mp3_get_info(const char* filename, struct tag_info* info)
- {
- int fd;
- rt_size_t bytes_read;
- int sync_word;
- HMP3Decoder decoder;
- MP3FrameInfo frame_info;
- if (filename == RT_NULL || info == RT_NULL) return;
- fd = open(filename, O_RDONLY, 0);
- if (fd < 0) return; /* can't read file */
- /* init decoder */
- decoder = MP3InitDecoder();
- info->data_start = 0;
- /*
- * TODO - Add UTF-8 support and fix this.
- *
- * ID3 v2 is generally useless here, because it
- * uses UTF-8 encoding, which we can't handle right now.
- * But parsing v2 first is nesessary in order to
- * find the correct MP3 frame header location,
- * in case of the ID3 v2 tag should be there.
- */
- // if (mp3_parse_id3v2(fd, info) < 0)
- // {
- // // ID3 v2 is not available. Fall back to ID3 v1.
- // mp3_parse_id3v1(fd, info);
- // }
- mp3_parse_id3v2(fd, info);
- mp3_parse_id3v1(fd, info);
- lseek(fd, info->data_start, SEEK_SET);
- bytes_read = read(fd, (char *) mp3_fd_buffer, sizeof(mp3_fd_buffer));
- /* get frame information */
- sync_word = MP3FindSyncWord(mp3_fd_buffer, bytes_read);
- if (sync_word >= 0)
- {
- rt_uint32_t p;
- short samples_per_frame;
- /* get frame information */
- MP3GetNextFrameInfo(decoder, &frame_info, &mp3_fd_buffer[sync_word]);
- // Try to locate the Xing VBR header.
- if (frame_info.version == MPEG1)
- {
- p = frame_info.nChans == 2 ? 32 : 17;
- samples_per_frame = 1152;
- }
- else
- {
- p = frame_info.nChans == 2 ? 17 : 9;
- samples_per_frame = 576;
- }
- p += sync_word + 4;
- if (strncmp("Xing", (char *) mp3_fd_buffer + p, 4) == 0 || strncmp("Info", (char *) mp3_fd_buffer + p, 4) == 0)
- {
- // VBR
- if (mp3_fd_buffer[p + 7] & 1 == 1) /* Checks if the frames field exists */
- {
- rt_uint32_t frames = ((rt_uint32_t) mp3_fd_buffer[p + 8] << 24) | ((rt_uint32_t) mp3_fd_buffer[p + 9] << 16) | ((rt_uint32_t) mp3_fd_buffer[p + 10] << 8) | (rt_uint32_t) mp3_fd_buffer[p + 11];
- info->duration = frames * samples_per_frame / frame_info.samprate;
- info->bit_rate = lseek(fd, 0, SEEK_END) * 8 / info->duration;
- }
- else
- {
- // Calculate as CBR
- info->duration = lseek(fd, 0, SEEK_END) / (frame_info.bitrate / 8); /* second */
- info->bit_rate = frame_info.bitrate;
- }
- }
- /*
- * There're two other rarely used VBR header standards: VBRI & MLLT.
- * I can't find any sample with these headers. So I just ignored them. :)
- */
- else
- {
- // CBR
- info->duration = lseek(fd, 0, SEEK_END) / (frame_info.bitrate / 8); /* second */
- info->bit_rate = frame_info.bitrate;
- }
- info->sampling = frame_info.samprate;
- }
- /* set current position */
- info->position = 0;
- /* release mp3 decoder */
- MP3FreeDecoder(decoder);
- /* close file */
- close(fd);
- }
- #include <finsh.h>
- rt_size_t fd_fetch(void* parameter, rt_uint8_t *buffer, rt_size_t length)
- {
- int fd = (int)parameter;
- int read_bytes;
- read_bytes = read(fd, (char*)buffer, length);
- if (read_bytes <= 0) return 0;
- return read_bytes;
- }
- void mp3(char* filename)
- {
- int fd;
- struct mp3_decoder* decoder;
- extern rt_bool_t is_playing;
-
- is_playing = RT_TRUE;
- fd = open(filename, O_RDONLY, 0);
- if (fd >= 0)
- {
- decoder = mp3_decoder_create();
- if (decoder != RT_NULL)
- {
- decoder->fetch_data = fd_fetch;
- decoder->fetch_parameter = (void*)fd;
- current_offset = 0;
- while (mp3_decoder_run(decoder) != -1);
- /* delete decoder object */
- mp3_decoder_delete(decoder);
- }
- close(fd);
- }
- is_playing = RT_FALSE;
- }
- FINSH_FUNCTION_EXPORT(mp3, mp3 decode test);
- #if STM32_EXT_SRAM
- /* http mp3 */
- #include "http.h"
- static rt_size_t http_fetch(rt_uint8_t* ptr, rt_size_t len, void* parameter)
- {
- struct http_session* session = (struct http_session*)parameter;
- RT_ASSERT(session != RT_NULL);
- return http_session_read(session, ptr, len);
- }
- static void http_close(void* parameter)
- {
- struct http_session* session = (struct http_session*)parameter;
- RT_ASSERT(session != RT_NULL);
- http_session_close(session);
- }
- rt_size_t http_data_fetch(void* parameter, rt_uint8_t *buffer, rt_size_t length)
- {
- return net_buf_read(buffer, length);
- }
- void http_mp3(char* url)
- {
- struct http_session* session;
- struct mp3_decoder* decoder;
- extern rt_bool_t is_playing;
-
- is_playing = RT_TRUE;
- session = http_session_open(url);
- if (session != RT_NULL)
- {
- /* add a job to netbuf worker */
- net_buf_add_job(http_fetch, http_close, (void*)session);
- decoder = mp3_decoder_create();
- if (decoder != RT_NULL)
- {
- decoder->fetch_data = http_data_fetch;
- decoder->fetch_parameter = RT_NULL;
- current_offset = 0;
- while (mp3_decoder_run(decoder) != -1);
- /* delete decoder object */
- mp3_decoder_delete(decoder);
- }
- session = RT_NULL;
- }
- }
- FINSH_FUNCTION_EXPORT(http_mp3, http mp3 decode test);
- /* ice mp3 */
- static rt_size_t ice_fetch(rt_uint8_t* ptr, rt_size_t len, void* parameter)
- {
- struct shoutcast_session* session = (struct shoutcast_session*)parameter;
- RT_ASSERT(session != RT_NULL);
- return shoutcast_session_read(session, ptr, len);
- }
- static void ice_close(void* parameter)
- {
- struct shoutcast_session* session = (struct shoutcast_session*)parameter;
- RT_ASSERT(session != RT_NULL);
- shoutcast_session_close(session);
- }
- rt_size_t ice_data_fetch(void* parameter, rt_uint8_t *buffer, rt_size_t length)
- {
- return net_buf_read(buffer, length);
- }
- void ice_mp3(char* url)
- {
- struct shoutcast_session* session;
- struct mp3_decoder* decoder;
- extern rt_bool_t is_playing;
- is_playing = RT_TRUE;
- session = shoutcast_session_open(url);
- if (session != RT_NULL)
- {
- /* add a job to netbuf worker */
- net_buf_add_job(ice_fetch, ice_close, (void*)session);
- decoder = mp3_decoder_create();
- if (decoder != RT_NULL)
- {
- decoder->fetch_data = ice_data_fetch;
- decoder->fetch_parameter = RT_NULL;
- current_offset = 0;
- while (mp3_decoder_run(decoder) != -1);
- /* delete decoder object */
- mp3_decoder_delete(decoder);
- }
- session = RT_NULL;
- }
- }
- FINSH_FUNCTION_EXPORT(ice_mp3, shoutcast mp3 decode test);
- #endif
|