int32_t buffered_reader_read(buffered_reader_t * reader, void *buffer, uint32_t size) { if (!reader->cache_enabled) { return sceIoRead(reader->handle, buffer, size); } if (reader->current_position == reader->length) return 0; if (size <= reader->position_2 - reader->current_position) { if (reader->current_position < reader->position_1) { if (size <= reader->position_1 - reader->current_position) { memcpy(buffer, reader->first_buffer + (reader->current_position - reader->position_0), size); } else { memcpy(buffer, reader->first_buffer + (reader->current_position - reader->position_0), reader->position_1 - reader->current_position); memcpy(buffer + (reader->position_1 - reader->current_position), reader->second_buffer, size - (reader->position_1 - reader->current_position)); } } else { memcpy(buffer, reader->second_buffer + (reader->current_position - reader->position_1), size); } reader->current_position += size; if (reader->current_position == reader->position_2) buffered_reader_seek(reader, reader->position_2); return size; } else { uint32_t data_size; data_size = reader->position_2 - reader->current_position; buffered_reader_read(reader, buffer, data_size); data_size += buffered_reader_read(reader, buffer + data_size, size - data_size); return data_size; } }
/** * MP3音乐播放回调函数,ME版本 * 负责将解码数据填充声音缓存区 * * @note 声音缓存区的格式为双声道,16位低字序 * * @param buf 声音缓冲区指针 * @param reqn 缓冲区帧大小 * @param pdata 用户数据,无用 */ static int memp3_audiocallback(void *buf, unsigned int reqn, void *pdata) { int avail_frame; int snd_buf_frame_size = (int) reqn; signed short *audio_buf = buf; double incr; uint16_t *output; UNUSED(pdata); if (g_status != ST_PLAYING) { if (handle_seek() == -1) { __end(); return -1; } xAudioClearSndBuf(buf, snd_buf_frame_size); xrKernelDelayThread(100000); return 0; } while (snd_buf_frame_size > 0) { avail_frame = g_buff_frame_size - g_buff_frame_start; if (avail_frame >= snd_buf_frame_size) { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], snd_buf_frame_size, 2); g_buff_frame_start += snd_buf_frame_size; audio_buf += snd_buf_frame_size * 2; snd_buf_frame_size = 0; } else { int frame_size, ret, brate = 0; send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], avail_frame, 2); snd_buf_frame_size -= avail_frame; audio_buf += avail_frame * 2; do { if (mp3_data.use_buffer) { if ((frame_size = search_valid_frame_me_buffered(&mp3_data, &brate)) < 0) { __end(); return -1; } } else { if ((frame_size = search_valid_frame_me(&mp3_data, &brate)) < 0) { __end(); return -1; } } if (mp3_data.use_buffer) ret = buffered_reader_read(mp3_data.r, memp3_input_buf, frame_size); else ret = xrIoRead(mp3_data.fd, memp3_input_buf, frame_size); if (ret < 0) { __end(); return -1; } ret = memp3_decode(memp3_input_buf, ret, memp3_decoded_buf); } while (ret < 0); output = &g_buff[0]; memcpy(output, memp3_decoded_buf, mp3info.spf * 4); g_buff_frame_size = mp3info.spf; g_buff_frame_start = 0; incr = (double) mp3info.spf / mp3info.sample_freq; g_play_time += incr; add_bitrate(&g_inst_br, brate * 1000, incr); } } return 0; }
/** * MP3音乐播放回调函数, * 负责将解码数据填充声音缓存区 * * @note 声音缓存区的格式为双声道,16位低字序 * * @param buf 声音缓冲区指针 * @param reqn 缓冲区帧大小 * @param pdata 用户数据,无用 */ static int mp3_audiocallback(void *buf, unsigned int reqn, void *pdata) { int avail_frame; int snd_buf_frame_size = (int) reqn; int ret; double incr; signed short *audio_buf = buf; unsigned i; uint16_t *output; UNUSED(pdata); if (g_status != ST_PLAYING) { if (handle_seek() == -1) { __end(); return -1; } xAudioClearSndBuf(buf, snd_buf_frame_size); xrKernelDelayThread(100000); return 0; } while (snd_buf_frame_size > 0) { avail_frame = g_buff_frame_size - g_buff_frame_start; if (avail_frame >= snd_buf_frame_size) { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], snd_buf_frame_size, 2); g_buff_frame_start += snd_buf_frame_size; audio_buf += snd_buf_frame_size * 2; snd_buf_frame_size = 0; } else { send_to_sndbuf(audio_buf, &g_buff[g_buff_frame_start * 2], avail_frame, 2); snd_buf_frame_size -= avail_frame; audio_buf += avail_frame * 2; if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) { size_t read_size, remaining = 0; uint8_t *read_start; int bufsize; if (stream.next_frame != NULL) { remaining = stream.bufend - stream.next_frame; memmove(g_input_buff, stream.next_frame, remaining); read_start = g_input_buff + remaining; read_size = BUFF_SIZE - remaining; } else { read_size = BUFF_SIZE; read_start = g_input_buff; remaining = 0; } if (mp3_data.use_buffer) bufsize = buffered_reader_read(mp3_data.r, read_start, read_size); else bufsize = xrIoRead(mp3_data.fd, read_start, read_size); if (bufsize <= 0) { __end(); return -1; } if (bufsize < read_size) { uint8_t *guard = read_start + read_size; memset(guard, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } mad_stream_buffer(&stream, g_input_buff, read_size + remaining); stream.error = 0; } ret = mad_frame_decode(&frame, &stream); if (ret == -1) { if (MAD_RECOVERABLE(stream.error) || stream.error == MAD_ERROR_BUFLEN) { if (stream.error == MAD_ERROR_LOSTSYNC) { long tagsize = id3_tag_query(stream.this_frame, stream.bufend - stream.this_frame); if (tagsize > 0) { mad_stream_skip(&stream, tagsize); } if (mad_header_decode(&frame.header, &stream) == -1) { if (stream.error != MAD_ERROR_BUFLEN) { if (!MAD_RECOVERABLE(stream.error)) { __end(); return -1; } } } else { stream.error = MAD_ERROR_NONE; } } g_buff_frame_size = 0; g_buff_frame_start = 0; continue; } else { __end(); return -1; } } output = &g_buff[0]; if (stream.error != MAD_ERROR_NONE) { continue; } mad_synth_frame(&synth, &frame); for (i = 0; i < synth.pcm.length; i++) { signed short sample; if (MAD_NCHANNELS(&frame.header) == 2) { /* Left channel */ sample = MadFixedToSshort(synth.pcm.samples[0][i]); *(output++) = sample; sample = MadFixedToSshort(synth.pcm.samples[1][i]); *(output++) = sample; } else { sample = MadFixedToSshort(synth.pcm.samples[0][i]); *(output++) = sample; *(output++) = sample; } } g_buff_frame_size = synth.pcm.length; g_buff_frame_start = 0; incr = frame.header.duration.seconds; incr += mad_timer_fraction(frame.header.duration, MAD_UNITS_MILLISECONDS) / 1000.0; g_play_time += incr; add_bitrate(&g_inst_br, frame.header.bitrate, incr); } } return 0; }
/** * 搜索下一个有效MP3 frame * * @return * - <0 失败 * - 0 成功 */ static int seek_valid_frame(void) { int cnt = 0; int ret; mad_stream_finish(&stream); mad_stream_init(&stream); do { cnt++; if (stream.buffer == NULL || stream.error == MAD_ERROR_BUFLEN) { size_t read_size, remaining = 0; uint8_t *read_start; int bufsize; if (stream.next_frame != NULL) { remaining = stream.bufend - stream.next_frame; memmove(g_input_buff, stream.next_frame, remaining); read_start = g_input_buff + remaining; read_size = BUFF_SIZE - remaining; } else { read_size = BUFF_SIZE; read_start = g_input_buff; remaining = 0; } if (mp3_data.use_buffer) bufsize = buffered_reader_read(mp3_data.r, read_start, read_size); else bufsize = xrIoRead(mp3_data.fd, read_start, read_size); if (bufsize <= 0) { return -1; } if (bufsize < read_size) { uint8_t *guard = read_start + read_size; memset(guard, 0, MAD_BUFFER_GUARD); read_size += MAD_BUFFER_GUARD; } mad_stream_buffer(&stream, g_input_buff, read_size + remaining); stream.error = 0; } if ((ret = mad_header_decode(&frame.header, &stream)) == -1) { /* * MAD_ERROR_BUFLEN should be ignored * * We haven't reached the EOF as long as xrIoRead returned positive. */ if (!MAD_RECOVERABLE(stream.error) && stream.error != MAD_ERROR_BUFLEN) { return -1; } } else { ret = 0; stream.error = 0; } } while (!(ret == 0 && stream.sync == 1)); dbg_printf(d, "%s: tried %d times", __func__, cnt); return 0; }