/**************************************************************************** * apps/system/nxplayer/nxplayer_mp3.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include "system/nxplayer.h" /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define ID3V2_BIT_MASK 0x7F /**************************************************************************** * Private Type Declarations ****************************************************************************/ const static uint16_t g_mpa_freq_tab[3] = { 44100, 48000, 32000 }; const static uint16_t g_mpa_bitrate_tab[2][3][15] = { { { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } }, { { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } } }; /**************************************************************************** * Private Functions ****************************************************************************/ static int nxplayer_check_mpeg(uint32_t header) { /* header */ if ((header & 0xffe00000) != 0xffe00000) { return -EINVAL; } /* version check */ if ((header & (3 << 19)) == 1 << 19) { return -EINVAL; } /* layer check */ if ((header & (3 << 17)) == 0) { return -EINVAL; } /* bit rate */ if ((header & (0xf << 12)) == 0xf << 12) { return -EINVAL; } /* frequency */ if ((header & (3 << 10)) == 3 << 10) { return -EINVAL; } return 0; } static int nxplayer_parse_mpeg(uint32_t header, FAR uint32_t *samplerate, FAR uint8_t *chans, FAR uint8_t *bps) { int sample_rate; int frame_size; int padding; int mpeg25; int sr_idx; int br_idx; int layer; int mode; int lsf; int ret; ret = nxplayer_check_mpeg(header); if (ret < 0) { return ret; } if (header & (1 << 20)) { lsf = (header & (1 << 19)) ? 0 : 1; mpeg25 = 0; } else { lsf = 1; mpeg25 = 1; } layer = 4 - ((header >> 17) & 3); br_idx = (header >> 12) & 0xf; sr_idx = (header >> 10) & 3; padding = (header >> 9) & 1; mode = (header >> 6) & 3; if (sr_idx >= sizeof(g_mpa_freq_tab) / sizeof(g_mpa_freq_tab[0]) || br_idx >= 0xf) { return -EINVAL; } sample_rate = g_mpa_freq_tab[sr_idx] >> (lsf + mpeg25); if (br_idx != 0) { frame_size = g_mpa_bitrate_tab[lsf][layer - 1][br_idx]; switch (layer) { case 1: frame_size = (frame_size * 12000) / sample_rate; frame_size = (frame_size + padding) * 4; break; case 2: frame_size = (frame_size * 144000) / sample_rate; frame_size += padding; break; default: case 3: frame_size = (frame_size * 144000) / (sample_rate << lsf); frame_size += padding; break; } } else { /* if no frame size computed, signal it */ return -EINVAL; } if (samplerate) { *samplerate = sample_rate; } if (chans) { *chans = mode == 3 ? 1 : 2; } if (bps) { *bps = 16; } return frame_size; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: nxplayer_parse_mp3 * * nxplayer_parse_mp3() parse mp3 header, get samplerate, channels, bps. * ****************************************************************************/ int nxplayer_parse_mp3(int fd, FAR uint32_t *samplerate, FAR uint8_t *chans, FAR uint8_t *bps) { uint32_t mpa_header; uint8_t buffer[10]; off_t position; int ret; ret = read(fd, buffer, sizeof(buffer)); if (ret < sizeof(buffer)) { return -ENODATA; } if (!memcmp(buffer, "ID3", 3)) { position = (buffer[6] & ID3V2_BIT_MASK) * 0x200000 + (buffer[7] & ID3V2_BIT_MASK) * 0x4000 + (buffer[8] & ID3V2_BIT_MASK) * 0x80 + (buffer[9] & ID3V2_BIT_MASK) + sizeof(buffer); lseek(fd, position, SEEK_SET); read(fd, buffer, 4); } else { position = 0; } mpa_header = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]; ret = nxplayer_parse_mpeg(mpa_header, samplerate, chans, bps); if (ret < 0) { return ret; } lseek(fd, position, SEEK_SET); return OK; } /**************************************************************************** * Name: nxplayer_fill_mp3 * * nxplayer_fill_mp3 fill mp3 data into apb buffer. * ****************************************************************************/ int nxplayer_fill_mp3(int fd, FAR struct ap_buffer_s *apb) { uint32_t mpa_header; uint8_t header[16]; int h_size = 4; int b_size; int size; int ret; ret = read(fd, header, h_size); if (ret < h_size) { return -ENODATA; } mpa_header = header[0] << 24 | header[1] << 16 | header[2] << 8 | header[3]; size = nxplayer_parse_mpeg(mpa_header, NULL, NULL, NULL); if (size < 0) { return size; } memcpy(apb->samp, header, h_size); b_size = size - h_size; ret = read(fd, apb->samp + h_size, b_size + 8); if (ret < b_size) { return -ENODATA; } lseek(fd, -8, SEEK_CUR); apb->nbytes = size + 8; apb->curbyte = 0; apb->flags = 0; return OK; }