/* this is the codec entry point */ enum codec_status codec_main(void) { static size_t buff_size; int datasize, res, consumed, i, time_offset; uint8_t *bit_buffer; uint16_t fs,sps,h; uint32_t packet_count; int scrambling_unit_size, num_units; size_t resume_offset; next_track: if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } if (codec_wait_taginfo() != 0) goto done; resume_offset = ci->id3->offset; codec_set_replaygain(ci->id3); ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); ci->memset(&q,0,sizeof(COOKContext)); init_rm(&rmctx); ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); /* cook's sample representation is 21.11 * DSP_SET_SAMPLE_DEPTH = 11 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 26 */ ci->configure(DSP_SET_SAMPLE_DEPTH, 26); ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); packet_count = rmctx.nb_packets; rmctx.audio_framesize = rmctx.block_align; rmctx.block_align = rmctx.sub_packet_size; fs = rmctx.audio_framesize; sps= rmctx.block_align; h = rmctx.sub_packet_h; scrambling_unit_size = h*fs; res =cook_decode_init(&rmctx, &q); if(res < 0) { DEBUGF("failed to initialize cook decoder\n"); return CODEC_ERROR; } /* check for a mid-track resume and force a seek time accordingly */ if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; num_units = (int)resume_offset / scrambling_unit_size; /* put number of subpackets to skip in resume_offset */ resume_offset /= (sps + PACKET_HEADER_SIZE); ci->seek_time = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); } ci->set_elapsed(0); ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); /* The main decoder loop */ seek_start : while(packet_count) { bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); if(consumed < 0) { DEBUGF("rm_get_packet failed\n"); return CODEC_ERROR; } for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) { ci->yield(); if (ci->stop_codec || ci->new_track) goto done; if (ci->seek_time) { ci->set_elapsed(ci->seek_time); /* Do not allow seeking beyond the file's length */ if ((unsigned) ci->seek_time > ci->id3->length) { ci->seek_complete(); goto done; } ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); packet_count = rmctx.nb_packets; rmctx.audio_pkt_cnt = 0; rmctx.frame_number = 0; /* Seek to the start of the track */ if (ci->seek_time == 1) { ci->set_elapsed(0); ci->seek_complete(); goto seek_start; } num_units = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); if(consumed < 0) { DEBUGF("rm_get_packet failed\n"); return CODEC_ERROR; } packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; rmctx.frame_number = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate)); while(rmctx.audiotimestamp > (unsigned) ci->seek_time) { rmctx.audio_pkt_cnt = 0; ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); packet_count += rmctx.audio_pkt_cnt; num_units--; } time_offset = ci->seek_time - rmctx.audiotimestamp; i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); ci->seek_complete(); } res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align); rmctx.frame_number++; /* skip the first two frames; no valid audio */ if(rmctx.frame_number < 3) continue; if(res != rmctx.block_align) { DEBUGF("codec error\n"); return CODEC_ERROR; } ci->pcmbuf_insert(rm_outbuf, rm_outbuf+q.samples_per_channel, q.samples_per_channel); ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); } packet_count -= rmctx.audio_pkt_cnt; rmctx.audio_pkt_cnt = 0; ci->advance_buffer(consumed); } done : if (ci->request_next_track()) goto next_track; return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { static size_t buff_size; int datasize, res, consumed, i, time_offset; uint8_t *bit_buffer; uint16_t fs,sps,h; uint32_t packet_count; int scrambling_unit_size, num_units, elapsed = 0; int playback_on = -1; size_t resume_offset = ci->id3->offset; next_track: if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); codec_set_replaygain(ci->id3); ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); ci->memset(&q,0,sizeof(ATRAC3Context)); init_rm(&rmctx); ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); ci->configure(DSP_SET_SAMPLE_DEPTH, 17); /* Remark: atrac3 uses s15.0 by default, s15.2 was hacked. */ ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); packet_count = rmctx.nb_packets; rmctx.audio_framesize = rmctx.block_align; rmctx.block_align = rmctx.sub_packet_size; fs = rmctx.audio_framesize; sps= rmctx.block_align; h = rmctx.sub_packet_h; scrambling_unit_size = h*fs; res =atrac3_decode_init(&q, &rmctx); if(res < 0) { DEBUGF("failed to initialize atrac decoder\n"); return CODEC_ERROR; } /* check for a mid-track resume and force a seek time accordingly */ if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; num_units = (int)resume_offset / scrambling_unit_size; /* put number of subpackets to skip in resume_offset */ resume_offset /= (sps + PACKET_HEADER_SIZE); ci->seek_time = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); } ci->set_elapsed(0); ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); /* The main decoder loop */ seek_start : while((unsigned)elapsed < rmctx.duration) { bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); if(consumed < 0 && playback_on != 0) { if(playback_on == -1) { /* Error only if packet-parsing failed and playback hadn't started */ DEBUGF("rm_get_packet failed\n"); return CODEC_ERROR; } else goto done; } for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) { ci->yield(); if (ci->stop_codec || ci->new_track) goto done; if (ci->seek_time) { ci->set_elapsed(ci->seek_time); /* Do not allow seeking beyond the file's length */ if ((unsigned) ci->seek_time > ci->id3->length) { ci->seek_complete(); goto done; } ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); packet_count = rmctx.nb_packets; rmctx.audio_pkt_cnt = 0; rmctx.frame_number = 0; /* Seek to the start of the track */ if (ci->seek_time == 1) { ci->set_elapsed(0); ci->seek_complete(); goto seek_start; } num_units = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); if(consumed < 0 && playback_on != 0) { if(playback_on == -1) { /* Error only if packet-parsing failed and playback hadn't started */ DEBUGF("rm_get_packet failed\n"); return CODEC_ERROR; } else goto done; } packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; rmctx.frame_number = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate)); while(rmctx.audiotimestamp > (unsigned) ci->seek_time) { rmctx.audio_pkt_cnt = 0; ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); packet_count += rmctx.audio_pkt_cnt; num_units--; } time_offset = ci->seek_time - rmctx.audiotimestamp; i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i; ci->set_elapsed(elapsed); ci->seek_complete(); } if(pkt.length) res = atrac3_decode_frame(&rmctx, &q, &datasize, pkt.frames[i], rmctx.block_align); else /* indicates that there are no remaining frames */ goto done; if(res != rmctx.block_align) { DEBUGF("codec error\n"); return CODEC_ERROR; } if(datasize) ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024, q.samples_per_frame / rmctx.nb_channels); playback_on = 1; elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i; ci->set_elapsed(elapsed); rmctx.frame_number++; } packet_count -= rmctx.audio_pkt_cnt; rmctx.audio_pkt_cnt = 0; ci->advance_buffer(consumed); } done : if (ci->request_next_track()) goto next_track; return CODEC_OK; }
int main(int argc, char *argv[]) { int fd, fd_dec; int res, datasize,i; int nb_frames = 0; #ifdef DUMP_RAW_FRAMES char filename[15]; int fd_out; #endif int32_t outbuf[2048]; uint16_t fs,sps,h; uint32_t packet_count; COOKContext q; RMContext rmctx; RMPacket pkt; memset(&q,0,sizeof(COOKContext)); memset(&rmctx,0,sizeof(RMContext)); memset(&pkt,0,sizeof(RMPacket)); if (argc != 2) { DEBUGF("Incorrect number of arguments\n"); return -1; } fd = open(argv[1],O_RDONLY); if (fd < 0) { DEBUGF("Error opening file %s\n", argv[1]); return -1; } /* copy the input rm file to a memory buffer */ uint8_t * filebuf = (uint8_t *)calloc((int)filesize(fd),sizeof(uint8_t)); res = read(fd,filebuf,filesize(fd)); fd_dec = open_wav("output.wav"); if (fd_dec < 0) { DEBUGF("Error creating output file\n"); return -1; } res = real_parse_header(fd, &rmctx); packet_count = rmctx.nb_packets; rmctx.audio_framesize = rmctx.block_align; rmctx.block_align = rmctx.sub_packet_size; fs = rmctx.audio_framesize; sps= rmctx.block_align; h = rmctx.sub_packet_h; cook_decode_init(&rmctx,&q); /* change the buffer pointer to point at the first audio frame */ advance_buffer(&filebuf, rmctx.data_offset+ DATA_HEADER_SIZE); while(packet_count) { rm_get_packet(&filebuf, &rmctx, &pkt); //DEBUGF("total frames = %d packet count = %d output counter = %d \n",rmctx.audio_pkt_cnt*(fs/sps), packet_count,rmctx.audio_pkt_cnt); for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) { /* output raw audio frames that are sent to the decoder into separate files */ #ifdef DUMP_RAW_FRAMES snprintf(filename,sizeof(filename),"dump%d.raw",++x); fd_out = open(filename,O_WRONLY|O_CREAT|O_APPEND, 0666); write(fd_out,pkt.frames[i],sps); close(fd_out); #endif nb_frames = cook_decode_frame(&rmctx,&q, outbuf, &datasize, pkt.frames[i] , rmctx.block_align); rmctx.frame_number++; res = write(fd_dec,outbuf,datasize); } packet_count -= rmctx.audio_pkt_cnt; rmctx.audio_pkt_cnt = 0; } close_wav(fd_dec, &rmctx, &q); close(fd); return 0; }
/* this is called for each file to process */ enum codec_status codec_run(void) { size_t n; uint8_t *filebuf; int consumed, packet_offset; int playback_on = -1; size_t resume_offset; intptr_t param; enum codec_command_action action = CODEC_ACTION_NULL; if (codec_init()) { return CODEC_ERROR; } resume_offset = ci->id3->offset; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); ci->seek_buffer(ci->id3->first_frame_offset); /* Intializations */ state = a52_init(0); ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); init_rm(&rmctx); samplesdone = 0; /* check for a mid-track resume and force a seek time accordingly */ if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; /* put number of subpackets to skip in resume_offset */ resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); action = CODEC_ACTION_SEEK_TIME; } else { /* Seek to the first packet */ ci->set_elapsed(0); ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE ); } /* The main decoding loop */ while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate); ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE)); rmctx.audio_pkt_cnt = packet_offset; samplesdone = (rmctx.sample_rate/1000 * param); ci->set_elapsed(samplesdone/(frequency/1000)); ci->seek_complete(); } action = CODEC_ACTION_NULL; filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE); consumed = rm_get_packet(&filebuf, &rmctx, &pkt); if(consumed < 0 && playback_on != 0) { if(playback_on == -1) { /* Error only if packet-parsing failed and playback hadn't started */ DEBUGF("rm_get_packet failed\n"); return CODEC_ERROR; } else { break; } } playback_on = 1; a52_decode_data(filebuf, filebuf + rmctx.block_align); ci->advance_buffer(pkt.length); } return CODEC_OK; }