/* this is called for each file to process */ enum codec_status codec_run(void) { size_t n; unsigned char *filebuf; int sample_loc; intptr_t param; if (codec_init()) return CODEC_ERROR; ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); /* Intialise the A52 decoder and check for success */ state = a52_init(0); samplesdone = 0; /* The main decoding loop */ if (ci->id3->offset) { if (ci->seek_buffer(ci->id3->offset)) { samplesdone = (ci->id3->offset / ci->id3->bytesperframe) * A52_SAMPLESPERFRAME; ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000)); } } else { ci->seek_buffer(ci->id3->first_frame_offset); ci->set_elapsed(0); } while (1) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { sample_loc = param/1000 * ci->id3->frequency; if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) { samplesdone = sample_loc; ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); } ci->seek_complete(); } filebuf = ci->request_buffer(&n, BUFFER_SIZE); if (n == 0) /* End of Stream */ break; a52_decode_data(filebuf, filebuf + n); ci->advance_buffer(n); } return CODEC_OK; }
/* This sets the DSP parameters based on the current logical bitstream * (sampling rate, number of channels, etc). */ static bool vorbis_set_codec_parameters(OggVorbis_File *vf) { vorbis_info *vi; vi = ov_info(vf, -1); if (vi == NULL) { return false; } ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); if (vi->channels == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); } else if (vi->channels == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } return true; }
/* this is the codec entry point */ enum codec_status codec_main(void) { size_t n; demux_res_t demux_res; stream_t input_stream; uint32_t samplesdone; uint32_t elapsedtime; uint32_t sample_duration; uint32_t sample_byte_size; int samplesdecoded; unsigned int i; unsigned char* buffer; alac_file alac; int retval; /* Generic codec initialisation */ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1); next_track: if (codec_init()) { LOGF("ALAC: Error initialising codec\n"); retval = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); stream_create(&input_stream,ci); /* Read from ci->id3->offset before calling qtmovie_read. */ samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) / (ci->id3->bitrate*128)); /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ if (!qtmovie_read(&input_stream, &demux_res)) { LOGF("ALAC: Error initialising file\n"); retval = CODEC_ERROR; goto done; } /* initialise the sound converter */ create_alac(demux_res.sound_sample_size, demux_res.num_channels,&alac); alac_set_info(&alac, demux_res.codecdata); /* Set i for first frame, seek to desired sample position for resuming. */ i=0; if (samplesdone > 0) { if (alac_seek(&demux_res, &input_stream, samplesdone, &samplesdone, (int*) &i)) { elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsedtime); } else { samplesdone = 0; } } /* The main decoding loop */ while (i < demux_res.num_sample_byte_sizes) { ci->yield(); if (ci->stop_codec || ci->new_track) { break; } /* Deal with any pending seek requests */ if (ci->seek_time) { if (alac_seek(&demux_res, &input_stream, ((ci->seek_time-1)/10) * (ci->id3->frequency/100), &samplesdone, (int *)&i)) { elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); ci->set_elapsed(elapsedtime); } ci->seek_complete(); } /* Lookup the length (in samples and bytes) of block i */ if (!get_sample_info(&demux_res, i, &sample_duration, &sample_byte_size)) { LOGF("ALAC: Error in get_sample_info\n"); retval = CODEC_ERROR; goto done; } /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n,sample_byte_size); if (n!=sample_byte_size) { retval = CODEC_ERROR; goto done; } /* Decode one block - returned samples will be host-endian */ ci->yield(); samplesdecoded=alac_decode_frame(&alac, buffer, outputbuffer, ci->yield); /* Advance codec buffer n bytes */ ci->advance_buffer(n); /* Output the audio */ ci->yield(); ci->pcmbuf_insert(outputbuffer[0], outputbuffer[1], samplesdecoded); /* Update the elapsed-time indicator */ samplesdone+=sample_duration; elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); ci->set_elapsed(elapsedtime); i++; } retval = CODEC_OK; done: LOGF("ALAC: Decoded %ld samples\n",samplesdone); if (ci->request_next_track()) goto next_track; exit: return retval; }
/* this is called for each file to process */ enum codec_status codec_run(void) { int error = CODEC_ERROR; SpeexBits bits; int eof = 0; spx_ogg_sync_state oy; spx_ogg_page og; spx_ogg_packet op; spx_ogg_stream_state os; spx_int64_t page_granule = 0; spx_int64_t cur_granule = 0; int enh_enabled = 1; int nframes = 2; int eos = 0; SpeexStereoState *stereo; int channels = -1; int samplerate = ci->id3->frequency; int extra_headers = 0; int stream_init = 0; /* rockbox: comment 'set but unused' variables int page_nb_packets; */ int frame_size; int packet_count = 0; int lookahead; int headerssize = 0; unsigned long strtoffset = ci->id3->offset; void *st = NULL; int j = 0; intptr_t param; memset(&bits, 0, sizeof(bits)); memset(&oy, 0, sizeof(oy)); /* Ogg handling still uses mallocs, so reset the malloc buffer per track */ if (codec_init()) { goto exit; } ci->seek_buffer(0); ci->set_elapsed(0); stereo = speex_stereo_state_init(); spx_ogg_sync_init(&oy); spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE); codec_set_replaygain(ci->id3); eof = 0; while (!eof) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /*seek (seeks to the page before the position) */ if (action == CODEC_ACTION_SEEK_TIME) { if(samplerate!=0&&packet_count>1){ LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", ((spx_int64_t)param/1000) * (spx_int64_t)samplerate, page_granule, param, (page_granule/samplerate)*1000, samplerate); speex_seek_page_granule(((spx_int64_t)param/1000) * (spx_int64_t)samplerate, page_granule, &oy, headerssize); } ci->set_elapsed(param); ci->seek_complete(); } next_page: /*Get the ogg buffer for writing*/ if(get_more_data(&oy)<1){/*read error*/ goto done; } /* Loop for all complete pages we got (most likely only one) */ while (spx_ogg_sync_pageout(&oy, &og) == 1) { int packet_no; if (stream_init == 0) { spx_ogg_stream_init(&os, spx_ogg_page_serialno(&og)); stream_init = 1; } /* Add page to the bitstream */ spx_ogg_stream_pagein(&os, &og); page_granule = spx_ogg_page_granulepos(&og); /* page_nb_packets = spx_ogg_page_packets(&og); */ cur_granule = page_granule; /* Extract all available packets */ packet_no=0; while (!eos && spx_ogg_stream_packetout(&os, &op)==1){ /* If first packet, process as Speex header */ if (packet_count==0){ st = process_header(&op, enh_enabled, &frame_size, &samplerate, &nframes, &channels, stereo, &extra_headers); speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead); if (!nframes) nframes=1; if (!st){ goto done; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); ci->configure(DSP_SET_SAMPLE_DEPTH, 16); if (channels == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (channels == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } /* Speex header in its own page, add the whole page headersize */ headerssize += og.header_len+og.body_len; } else if (packet_count<=1+extra_headers){ /* add packet to headersize */ headerssize += op.bytes; /* Ignore extra headers */ } else { if (packet_count <= 2+extra_headers) { if (strtoffset) { ci->seek_buffer(strtoffset); spx_ogg_sync_reset(&oy); packet_count++; goto next_page; } } packet_no++; if (op.e_o_s) /* End of stream condition */ eos=1; /* Set Speex bitstream to point to Ogg packet */ speex_bits_set_bit_buffer(&bits, (char *)op.packet, op.bytes); for (j = 0; j != nframes; j++){ int ret; /* Decode frame */ ret = speex_decode_int(st, &bits, output); if (ret == -1) break; if (ret == -2) break; if (speex_bits_remaining(&bits) < 0) break; if (channels == 2) speex_decode_stereo_int(output, frame_size, stereo); if (frame_size > 0) { spx_int16_t *frame_start = output + lookahead; if (channels == 2) frame_start += lookahead; ci->pcmbuf_insert(frame_start, NULL, frame_size - lookahead); lookahead = 0; /* 2 bytes/sample */ cur_granule += frame_size / 2; ci->set_offset((long) ci->curpos); ci->set_elapsed((samplerate == 0) ? 0 : cur_granule * 1000 / samplerate); } } } packet_count++; } } } error = CODEC_OK; done: /* Clean things up for the next track */ speex_bits_destroy(&bits); if (st) speex_decoder_destroy(st); if (stream_init) spx_ogg_stream_destroy(&os); spx_ogg_sync_destroy(&oy); exit: return error; }
/* this is called for each file to process */ enum codec_status codec_run(void) { static size_t buff_size; int datasize, res, frame_counter, total_frames, seek_frame_offset; uint8_t *bit_buffer; int elapsed = 0; size_t resume_offset; intptr_t param; long action; if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } action = CODEC_ACTION_NULL; param = ci->id3->elapsed; resume_offset = ci->id3->offset; codec_set_replaygain(ci->id3); ci->memset(&q,0,sizeof(ATRAC3Context)); 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, ci->id3->channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); ci->seek_buffer(0); res = atrac3_decode_init(&q, ci->id3); if(res < 0) { DEBUGF("failed to initialize OMA atrac decoder\n"); return CODEC_ERROR; } total_frames = (ci->id3->filesize - ci->id3->first_frame_offset) / FRAMESIZE; frame_counter = 0; /* check for a mid-track resume and force a seek time accordingly */ if (resume_offset) { resume_offset -= MIN(resume_offset, ci->id3->first_frame_offset); /* calculate resume_offset in frames */ param = (resume_offset/FRAMESIZE) * ((FRAMESIZE * 8)/BITRATE); } if ((unsigned long)param) { action = CODEC_ACTION_SEEK_TIME; } else { ci->set_elapsed(0); ci->seek_buffer(ci->id3->first_frame_offset); } /* The main decoder loop */ while(frame_counter < total_frames) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { /* Do not allow seeking beyond the file's length */ if ((unsigned long) param > ci->id3->length) { ci->set_elapsed(ci->id3->length); ci->seek_complete(); break; } /* Seek to the start of the track */ if (param == 0) { elapsed = 0; ci->set_elapsed(0); ci->seek_buffer(ci->id3->first_frame_offset); ci->seek_complete(); action = CODEC_ACTION_NULL; continue; } seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE); frame_counter = seek_frame_offset; ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE); elapsed = param; ci->set_elapsed(elapsed); ci->seek_complete(); } action = CODEC_ACTION_NULL; bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE); if(res != (int)FRAMESIZE) { DEBUGF("codec error\n"); return CODEC_ERROR; } if(datasize) ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024, q.samples_per_frame / ci->id3->channels); elapsed += (FRAMESIZE * 8) / BITRATE; ci->set_elapsed(elapsed); ci->advance_buffer(FRAMESIZE); frame_counter++; } return CODEC_OK; }
/* this is called for each file to process */ enum codec_status codec_run(void) { WavpackContext *wpc; char error [80]; /* rockbox: comment 'set but unused' variables int bps; */ int nchans, sr_100; intptr_t param; if (codec_init()) return CODEC_ERROR; ci->seek_buffer (ci->id3->offset); /* Create a decoder instance */ wpc = WavpackOpenFileInput (read_callback, error); if (!wpc) return CODEC_ERROR; ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc)); codec_set_replaygain(ci->id3); /* bps = WavpackGetBytesPerSample (wpc); */ nchans = WavpackGetReducedChannels (wpc); ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); sr_100 = ci->id3->frequency / 100; ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); /* The main decoder loop */ while (1) { int32_t nsamples; enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; int n, d, skip; if (param > curpos_ms) { n = param - curpos_ms; d = ci->id3->length - curpos_ms; skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d); ci->seek_buffer (ci->curpos + skip); } else if (curpos_ms != 0) { n = curpos_ms - param; d = curpos_ms; skip = (int)((int64_t) ci->curpos * n / d); ci->seek_buffer (ci->curpos - skip); } wpc = WavpackOpenFileInput (read_callback, error); if (!wpc) { ci->seek_complete(); break; } ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->seek_complete(); } nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans); if (!nsamples) break; ci->pcmbuf_insert (temp_buffer, NULL, nsamples); ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); } return CODEC_OK; }
/* this is called for each file to process */ enum codec_status codec_run(void) { size_t n; demux_res_t demux_res; stream_t input_stream; uint32_t samplesdone; uint32_t elapsedtime = 0; int samplesdecoded; unsigned int i; unsigned char* buffer; alac_file alac; intptr_t param; /* Clean and initialize decoder structures */ memset(&demux_res , 0, sizeof(demux_res)); if (codec_init()) { LOGF("ALAC: Error initialising codec\n"); return CODEC_ERROR; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); ci->seek_buffer(0); stream_create(&input_stream,ci); /* Read from ci->id3->offset before calling qtmovie_read. */ samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) / (ci->id3->bitrate*128)); /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ if (!qtmovie_read(&input_stream, &demux_res)) { LOGF("ALAC: Error initialising file\n"); return CODEC_ERROR; } /* initialise the sound converter */ alac_set_info(&alac, demux_res.codecdata); /* Set i for first frame, seek to desired sample position for resuming. */ i=0; if (samplesdone > 0) { if (m4a_seek(&demux_res, &input_stream, samplesdone, &samplesdone, (int*) &i)) { elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsedtime); } else { samplesdone = 0; } } ci->set_elapsed(elapsedtime); /* The main decoding loop */ while (i < demux_res.num_sample_byte_sizes) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE); /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { if (m4a_seek(&demux_res, &input_stream, (param/10) * (ci->id3->frequency/100), &samplesdone, (int *)&i)) { elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); } ci->set_elapsed(elapsedtime); ci->seek_complete(); } /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE); /* Decode one block - returned samples will be host-endian */ samplesdecoded=alac_decode_frame(&alac, buffer, outputbuffer, ci->yield); ci->yield(); /* Advance codec buffer by amount of consumed bytes */ ci->advance_buffer(alac.bytes_consumed); /* Output the audio */ ci->pcmbuf_insert(outputbuffer[0], outputbuffer[1], samplesdecoded); /* Update the elapsed-time indicator */ samplesdone+=samplesdecoded; elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); ci->set_elapsed(elapsedtime); i++; } LOGF("ALAC: Decoded %lu samples\n",(unsigned long)samplesdone); return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { uint32_t elapsedtime; int retval; asf_waveformatex_t wfx; /* Holds the stream properties */ size_t resume_offset; int res; /* Return values from asf_read_packet() and decode_packet() */ uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ int audiobufsize; /* Payload size */ int packetlength = 0; /* Logical packet size (minus the header size) */ int outlen = 0; /* Number of bytes written to the output buffer */ int pktcnt = 0; /* Count of the packets played */ uint8_t *data; /* Pointer to decoder input buffer */ int size; /* Size of the input frame to the decoder */ /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, WMAPRO_DSP_SAMPLE_DEPTH); next_track: /* Wait for the metadata to be read */ while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); retval = CODEC_OK; /* Remember the resume position */ resume_offset = ci->id3->offset; restart_track: if (codec_init()) { LOGF("(WMA PRO) Error: Error initialising codec\n"); retval = CODEC_ERROR; goto done; } /* Copy the format metadata we've stored in the id3 TOC field. This saves us from parsing it again here. */ memcpy(&wfx, ci->id3->toc, sizeof(wfx)); ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); codec_set_replaygain(ci->id3); if (decode_init(&wfx) < 0) { LOGF("(WMA PRO) Error: Unsupported or corrupt file\n"); retval = CODEC_ERROR; goto done; } /* Now advance the file position to the first frame */ ci->seek_buffer(ci->id3->first_frame_offset); elapsedtime = 0; resume_offset = 0; /* The main decoding loop */ while (pktcnt < wfx.numpackets) { ci->yield(); if (ci->stop_codec || ci->new_track) { goto done; } /* Deal with any pending seek requests */ if (ci->seek_time) { if (ci->seek_time == 1) { ci->seek_complete(); goto restart_track; /* Pretend you never saw this... */ } elapsedtime = asf_seek(ci->seek_time, &wfx); if (elapsedtime < 1) { ci->seek_complete(); goto next_track; } ci->set_elapsed(elapsedtime); ci->seek_complete(); } res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); if (res < 0) { LOGF("(WMA PRO) Warning: asf_read_packet returned %d", res); goto done; } else { data = audiobuf; size = audiobufsize; pktcnt++; /* We now loop on the packet, decoding and outputting the subframes * one-by-one. For more information about how wma pro structures its * audio frames, see libwmapro/wmaprodec.c */ while(size > 0) { res = decode_packet(&wfx, dec, &outlen, data, size); if(res < 0) { LOGF("(WMA PRO) Error: decode_packet returned %d", res); goto done; } data += res; size -= res; if(outlen) { ci->yield (); outlen /= (wfx.channels); ci->pcmbuf_insert(dec[0], dec[1], outlen ); elapsedtime += outlen*10/(wfx.rate/100); ci->set_elapsed(elapsedtime); ci->yield (); } } } /* Advance to the next logical packet */ ci->advance_buffer(packetlength); } retval = CODEC_OK; done: if (ci->request_next_track()) goto next_track; return retval; }
/* 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) { WavpackContext *wpc; char error [80]; int bps, nchans, sr_100; int retval; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, 28); next_track: if (codec_init()) { retval = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); /* Create a decoder instance */ wpc = WavpackOpenFileInput (read_callback, error); if (!wpc) { retval = CODEC_ERROR; goto done; } ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc)); codec_set_replaygain(ci->id3); bps = WavpackGetBytesPerSample (wpc); nchans = WavpackGetReducedChannels (wpc); ci->configure(DSP_SET_STEREO_MODE, nchans == 2 ? STEREO_INTERLEAVED : STEREO_MONO); sr_100 = ci->id3->frequency / 100; ci->set_elapsed (0); /* The main decoder loop */ while (1) { int32_t nsamples; if (ci->seek_time && ci->taginfo_ready && ci->id3->length) { ci->seek_time--; int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; int n, d, skip; if (ci->seek_time > curpos_ms) { n = ci->seek_time - curpos_ms; d = ci->id3->length - curpos_ms; skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d); ci->seek_buffer (ci->curpos + skip); } else { n = curpos_ms - ci->seek_time; d = curpos_ms; skip = (int)((int64_t) ci->curpos * n / d); ci->seek_buffer (ci->curpos - skip); } wpc = WavpackOpenFileInput (read_callback, error); ci->seek_complete(); if (!wpc) break; ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->yield (); } nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans); if (!nsamples || ci->stop_codec || ci->new_track) break; ci->yield (); if (ci->stop_codec || ci->new_track) break; ci->pcmbuf_insert (temp_buffer, NULL, nsamples); ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->yield (); } retval = CODEC_OK; done: if (ci->request_next_track()) goto next_track; exit: return retval; }
/* 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; }
/* this is the codec entry point */ enum codec_status codec_main(void) { ShortenContext sc; uint32_t samplesdone; uint32_t elapsedtime; int8_t *buf; int consumed, res, nsamples; size_t bytesleft; /* Generic codec initialisation */ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, SHN_OUTPUT_DEPTH-1); next_track: /* Codec initialization */ if (codec_init()) { LOGF("Shorten: codec_init error\n"); return CODEC_ERROR; } while (!*ci->taginfo_ready) ci->yield(); codec_set_replaygain(ci->id3); /* Shorten decoder initialization */ ci->memset(&sc, 0, sizeof(ShortenContext)); /* Skip id3v2 tags */ ci->seek_buffer(ci->id3->first_frame_offset); /* Read the shorten & wave headers */ buf = ci->request_buffer(&bytesleft, MAX_HEADER_SIZE); res = shorten_init(&sc, (unsigned char *)buf, bytesleft); if (res < 0) { LOGF("Shorten: shorten_init error: %d\n", res); return CODEC_ERROR; } ci->id3->frequency = sc.sample_rate; ci->configure(DSP_SWITCH_FREQUENCY, sc.sample_rate); if (sc.sample_rate) { ci->id3->length = (sc.totalsamples / sc.sample_rate) * 1000; } else { ci->id3->length = 0; } if (ci->id3->length) { ci->id3->bitrate = (ci->id3->filesize * 8) / ci->id3->length; } consumed = sc.gb.index/8; ci->advance_buffer(consumed); sc.bitindex = sc.gb.index - 8*consumed; seek_start: /* The main decoding loop */ ci->memset(&decoded0, 0, sizeof(int32_t)*MAX_DECODE_SIZE); ci->memset(&decoded1, 0, sizeof(int32_t)*MAX_DECODE_SIZE); ci->memset(&offset0, 0, sizeof(int32_t)*MAX_OFFSET_SIZE); ci->memset(&offset1, 0, sizeof(int32_t)*MAX_OFFSET_SIZE); samplesdone = 0; buf = ci->request_buffer(&bytesleft, MAX_BUFFER_SIZE); while (bytesleft) { ci->yield(); if (ci->stop_codec || ci->new_track) { break; } /* Seek to start of track */ if (ci->seek_time == 1) { if (ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) { sc.bitindex = sc.header_bits - 8*(sc.header_bits/8); ci->set_elapsed(0); ci->seek_complete(); goto seek_start; } ci->seek_complete(); } /* Decode a frame */ ci->memcpy(ibuf, buf, bytesleft); /* copy buf to iram */ res = shorten_decode_frames(&sc, &nsamples, decoded0, decoded1, offset0, offset1, (unsigned char *)ibuf, bytesleft, ci->yield); if (res == FN_ERROR) { LOGF("Shorten: shorten_decode_frames error (%lu)\n", (unsigned long)samplesdone); break; } else { /* Insert decoded samples in pcmbuf */ if (nsamples) { ci->yield(); ci->pcmbuf_insert(decoded0 + sc.nwrap, decoded1 + sc.nwrap, nsamples); /* Update the elapsed-time indicator */ samplesdone += nsamples; elapsedtime = (samplesdone*10) / (sc.sample_rate/100); ci->set_elapsed(elapsedtime); } /* End of shorten stream...go to next track */ if (res == FN_QUIT) break; } consumed = sc.gb.index/8; ci->advance_buffer(consumed); buf = ci->request_buffer(&bytesleft, MAX_BUFFER_SIZE); sc.bitindex = sc.gb.index - 8*consumed; } if (ci->request_next_track()) goto next_track; return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { int status; uint32_t decodedsamples; size_t n; int bufcount; int endofstream; unsigned char *buf; uint8_t *wavbuf; off_t firstblockposn; /* position of the first block in file */ const struct pcm_codec *codec; uint64_t size; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: status = CODEC_OK; if (codec_init()) { DEBUGF("codec_init() error\n"); status = CODEC_ERROR; goto exit; } if (codec_wait_taginfo() != 0) goto done; codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ bytesdone = ci->id3->offset; /* get RIFF chunk header */ buf = ci->request_buffer(&n, 40); if (n < 40) { DEBUGF("request_buffer error\n"); status = CODEC_ERROR; goto done; } if ((memcmp(buf , WAVE64_GUID_RIFF, 16) != 0) || (memcmp(buf+24, WAVE64_GUID_WAVE, 16) != 0)) { status = CODEC_ERROR; goto done; } /* advance to first WAVE chunk */ ci->advance_buffer(40); firstblockposn = 40; ci->memset(&format, 0, sizeof(struct pcm_format)); format.is_signed = true; format.is_little_endian = true; decodedsamples = 0; codec = 0; /* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */ while (true) { /* get WAVE chunk header */ buf = ci->request_buffer(&n, 1024); if (n < 8) { DEBUGF("data chunk request_buffer error\n"); /* no more chunks, 'data' chunk must not have been found */ status = CODEC_ERROR; goto done; } /* chunkSize */ size = get_uint64_le(buf+16) - 24; if (memcmp(buf, WAVE64_GUID_FMT, 16) == 0) { if (size < 16) { DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%d < 16\n", (int)size); status = CODEC_ERROR; goto done; } /* wFormatTag */ format.formattag=buf[24]|(buf[25]<<8); /* wChannels */ format.channels=buf[26]|(buf[27]<<8); /* skipping dwSamplesPerSec */ /* skipping dwAvgBytesPerSec */ /* wBlockAlign */ format.blockalign=buf[36]|(buf[37]<<8); /* wBitsPerSample */ format.bitspersample=buf[38]|(buf[39]<<8); if (format.formattag != WAVE_FORMAT_PCM) { if (size < 18) { /* this is not a fatal error with some formats, * we'll see later if we can't decode it */ DEBUGF("CODEC_WARNING: non-PCM WAVE (formattag=0x%x) " "doesn't have ext. fmt descr (chunksize=%d<18).\n", (unsigned int)format.formattag, (int)size); } else { if (format.formattag != WAVE_FORMAT_EXTENSIBLE) format.samplesperblock = buf[42]|(buf[43]<<8); else { format.size = buf[40]|(buf[41]<<8); if (format.size < 22) { DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " "missing extension\n"); status = CODEC_ERROR; goto done; } /* wValidBitsPerSample */ format.bitspersample = buf[42]|(buf[43]<<8); /* skipping dwChannelMask (4bytes) */ /* SubFormat (only get the first two bytes) */ format.formattag = buf[48]|(buf[49]<<8); } } } /* msadpcm specific */ if (format.formattag == WAVE_FORMAT_ADPCM) { if (!set_msadpcm_coeffs(buf)) { status = CODEC_ERROR; goto done; } } /* get codec */ codec = get_wave_codec(format.formattag); if (!codec) { DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n", (unsigned int) format.formattag); status = CODEC_ERROR; goto done; } /* riff 8bit linear pcm is unsigned */ if (format.formattag == WAVE_FORMAT_PCM && format.bitspersample == 8) format.is_signed = false; /* check format, and calculate chunk size */ if (!codec->set_format(&format)) { status = CODEC_ERROR; goto done; } } else if (memcmp(buf, WAVE64_GUID_DATA, 16) == 0) { format.numbytes = size; /* advance to start of data */ ci->advance_buffer(24); firstblockposn += 24; break; } else if (memcmp(buf, WAVE64_GUID_FACT, 16) == 0) { /* skip 'fact' chunk */ } else { DEBUGF("unknown Wave64 chunk: " "'%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n", buf[0], buf[1], buf[ 2], buf[ 3], buf[ 4], buf[ 5], buf[ 6], buf[ 7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); } /* go to next chunk (8byte bound) */ size += 24 + ((1 + ~size) & 0x07); ci->advance_buffer(size); firstblockposn += size; } if (!codec) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n"); status = CODEC_ERROR; goto done; } /* common format check */ if (format.channels == 0) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); status = CODEC_ERROR; goto done; } if (format.samplesperblock == 0) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n"); status = CODEC_ERROR; goto done; } if (format.blockalign == 0) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n"); status = CODEC_ERROR; goto done; } if (format.numbytes == 0) { DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); status = CODEC_ERROR; goto done; } /* check chunksize */ if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels > PCM_SAMPLE_SIZE) format.chunksize = (PCM_SAMPLE_SIZE / format.blockalign) * format.blockalign; if (format.chunksize == 0) { DEBUGF("CODEC_ERROR: chunksize is 0\n"); status = CODEC_ERROR; goto done; } ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); if (format.channels == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (format.channels == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); status = CODEC_ERROR; goto done; } /* make sure we're at the correct offset */ if (bytesdone > (uint32_t) firstblockposn) { /* Round down to previous block */ struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, PCM_SEEK_POS, &read_buffer); if (newpos->pos > format.numbytes) goto done; if (ci->seek_buffer(firstblockposn + newpos->pos)) { bytesdone = newpos->pos; decodedsamples = newpos->samples; } ci->seek_complete(); } else { /* already where we need to be */ bytesdone = 0; } /* The main decoder loop */ endofstream = 0; while (!endofstream) { ci->yield(); if (ci->stop_codec || ci->new_track) { break; } if (ci->seek_time) { struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, &read_buffer); if (newpos->pos > format.numbytes) break; if (ci->seek_buffer(firstblockposn + newpos->pos)) { bytesdone = newpos->pos; decodedsamples = newpos->samples; } ci->seek_complete(); } wavbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize); if (n == 0) break; /* End of stream */ if (bytesdone + n > format.numbytes) { n = format.numbytes - bytesdone; endofstream = 1; } status = codec->decode(wavbuf, n, samples, &bufcount); if (status == CODEC_ERROR) { DEBUGF("codec error\n"); goto done; } ci->pcmbuf_insert(samples, NULL, bufcount); ci->advance_buffer(n); bytesdone += n; decodedsamples += bufcount; if (bytesdone >= format.numbytes) endofstream = 1; ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } status = CODEC_OK; done: if (ci->request_next_track()) goto next_track; exit: return status; }
/* this is the codec entry point */ enum codec_status codec_main(void) { uint32_t elapsedtime; int retval; asf_waveformatex_t wfx; size_t resume_offset; int i; int wmares, res; uint8_t* audiobuf; int audiobufsize; int packetlength = 0; int errcount = 0; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, 29); next_track: /* Wait for the metadata to be read */ while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); retval = CODEC_OK; /* Remember the resume position - when the codec is opened, the playback engine will reset it. */ resume_offset = ci->id3->offset; restart_track: if (codec_init()) { LOGF("WMA: Error initialising codec\n"); retval = CODEC_ERROR; goto exit; } /* Copy the format metadata we've stored in the id3 TOC field. This saves us from parsing it again here. */ memcpy(&wfx, ci->id3->toc, sizeof(wfx)); if (wma_decode_init(&wmadec,&wfx) < 0) { LOGF("WMA: Unsupported or corrupt file\n"); retval = CODEC_ERROR; goto exit; } if (resume_offset > ci->id3->first_frame_offset) { /* Get start of current packet */ int packet_offset = (resume_offset - ci->id3->first_frame_offset) % wfx.packet_size; ci->seek_buffer(resume_offset - packet_offset); elapsedtime = asf_get_timestamp(&i); ci->set_elapsed(elapsedtime); } else { /* Now advance the file position to the first frame */ ci->seek_buffer(ci->id3->first_frame_offset); elapsedtime = 0; } resume_offset = 0; ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); codec_set_replaygain(ci->id3); /* The main decoding loop */ res = 1; while (res >= 0) { ci->yield(); if (ci->stop_codec || ci->new_track) { goto done; } /* Deal with any pending seek requests */ if (ci->seek_time){ if (ci->seek_time == 1) { ci->seek_complete(); goto restart_track; /* Pretend you never saw this... */ } elapsedtime = asf_seek(ci->seek_time, &wfx); if (elapsedtime < 1){ ci->seek_complete(); goto next_track; } /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/ ci->set_elapsed(elapsedtime); /*flush the wma decoder state*/ wmadec.last_superframe_len = 0; wmadec.last_bitoffset = 0; ci->seek_complete(); } errcount = 0; new_packet: res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); if (res < 0) { /* We'll try to recover from a parse error a certain number of * times. If we succeed, the error counter will be reset. */ errcount++; DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount); if (errcount > 5) { goto done; } else { ci->advance_buffer(packetlength); goto new_packet; } } else if (res > 0) { wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize); for (i=0; i < wmadec.nb_frames; i++) { wmares = wma_decode_superframe_frame(&wmadec, audiobuf, audiobufsize); ci->yield (); if (wmares < 0) { /* Do the above, but for errors in decode. */ errcount++; DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount); if (errcount > 5) { goto done; } else { ci->advance_buffer(packetlength); goto new_packet; } } else if (wmares > 0) { ci->pcmbuf_insert((*wmadec.frame_out)[0], (*wmadec.frame_out)[1], wmares); elapsedtime += (wmares*10)/(wfx.rate/100); ci->set_elapsed(elapsedtime); } ci->yield(); } } ci->advance_buffer(packetlength); } retval = CODEC_OK; done: /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/ if (ci->request_next_track()) goto next_track; exit: return retval; }
/* this is called for each file to process */ enum codec_status codec_run(void) { /* Note that when dealing with QuickTime/MPEG4 files, terminology is * a bit confusing. Files with sound are split up in chunks, where * each chunk contains one or more samples. Each sample in turn * contains a number of "sound samples" (the kind you refer to with * the sampling frequency). */ size_t n; demux_res_t demux_res; stream_t input_stream; uint32_t sound_samples_done; uint32_t elapsed_time; int file_offset; int framelength; int lead_trim = 0; unsigned int frame_samples; unsigned int i; unsigned char* buffer; NeAACDecFrameInfo frame_info; NeAACDecHandle decoder; int err; uint32_t seek_idx = 0; uint32_t s = 0; uint32_t sbr_fac = 1; unsigned char c = 0; void *ret; intptr_t param; bool empty_first_frame = false; /* Clean and initialize decoder structures */ memset(&demux_res , 0, sizeof(demux_res)); if (codec_init()) { LOGF("FAAD: Codec init error\n"); return CODEC_ERROR; } file_offset = ci->id3->offset; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); stream_create(&input_stream,ci); ci->seek_buffer(ci->id3->first_frame_offset); /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ if (!qtmovie_read(&input_stream, &demux_res)) { LOGF("FAAD: File init error\n"); return CODEC_ERROR; } /* initialise the sound converter */ decoder = NeAACDecOpen(); if (!decoder) { LOGF("FAAD: Decode open error\n"); return CODEC_ERROR; } NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ NeAACDecSetConfiguration(decoder, conf); err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c); if (err) { LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); return CODEC_ERROR; } #ifdef SBR_DEC /* Check for need of special handling for seek/resume and elapsed time. */ if (ci->id3->needs_upsampling_correction) { sbr_fac = 2; } else { sbr_fac = 1; } #endif i = 0; if (file_offset > 0) { /* Resume the desired (byte) position. Important: When resuming SBR * upsampling files the resulting sound_samples_done must be expanded * by a factor of 2. This is done via using sbr_fac. */ if (m4a_seek_raw(&demux_res, &input_stream, file_offset, &sound_samples_done, (int*) &i)) { sound_samples_done *= sbr_fac; } else { sound_samples_done = 0; } NeAACDecPostSeekReset(decoder, i); } else { sound_samples_done = 0; } elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); if (i == 0) { lead_trim = ci->id3->lead_trim; } /* The main decoding loop */ while (i < demux_res.num_sample_byte_sizes) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { /* Seek to the desired time position. Important: When seeking in SBR * upsampling files the seek_time must be divided by 2 when calling * m4a_seek and the resulting sound_samples_done must be expanded * by a factor 2. This is done via using sbr_fac. */ if (m4a_seek(&demux_res, &input_stream, (param/10/sbr_fac)*(ci->id3->frequency/100), &sound_samples_done, (int*) &i)) { sound_samples_done *= sbr_fac; elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); seek_idx = 0; if (i == 0) { lead_trim = ci->id3->lead_trim; } } NeAACDecPostSeekReset(decoder, i); ci->seek_complete(); } /* There can be gaps between chunks, so skip ahead if needed. It * doesn't seem to happen much, but it probably means that a * "proper" file can have chunks out of order. Why one would want * that an good question (but files with gaps do exist, so who * knows?), so we don't support that - for now, at least. */ file_offset = m4a_check_sample_offset(&demux_res, i, &seek_idx); if (file_offset > ci->curpos) { ci->advance_buffer(file_offset - ci->curpos); } else if (file_offset == 0) { LOGF("AAC: get_sample_offset error\n"); return CODEC_ERROR; } /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); /* Decode one block - returned samples will be host-endian */ ret = NeAACDecDecode(decoder, &frame_info, buffer, n); /* NeAACDecDecode may sometimes return NULL without setting error. */ if (ret == NULL || frame_info.error > 0) { LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); return CODEC_ERROR; } /* Advance codec buffer (no need to call set_offset because of this) */ ci->advance_buffer(frame_info.bytesconsumed); /* Output the audio */ ci->yield(); frame_samples = frame_info.samples >> 1; if (empty_first_frame) { /* Remove the first frame from lead_trim, under the assumption * that it had the same size as this frame */ empty_first_frame = false; lead_trim -= frame_samples; if (lead_trim < 0) { lead_trim = 0; } } /* Gather number of samples for the decoded frame. */ framelength = frame_samples - lead_trim; if (i == demux_res.num_sample_byte_sizes - 1) { // Size of the last frame const uint32_t sample_duration = (demux_res.num_time_to_samples > 0) ? demux_res.time_to_sample[demux_res.num_time_to_samples - 1].sample_duration : frame_samples; /* Currently limited to at most one frame of tail_trim. * Seems to be enough. */ if (ci->id3->tail_trim == 0 && sample_duration < frame_samples) { /* Subtract lead_trim just in case we decode a file with only * one audio frame with actual data (lead_trim is usually zero * here). */ framelength = sample_duration - lead_trim; } else { framelength -= ci->id3->tail_trim; } } if (framelength > 0) { ci->pcmbuf_insert(&decoder->time_out[0][lead_trim], &decoder->time_out[1][lead_trim], framelength); sound_samples_done += framelength; /* Update the elapsed-time indicator */ elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); ci->set_elapsed(elapsed_time); } if (lead_trim > 0) { /* frame_info.samples can be 0 for frame 0. We still want to * remove it from lead_trim, so do that during frame 1. */ if (0 == i && 0 == frame_info.samples) { empty_first_frame = true; } lead_trim -= frame_samples; if (lead_trim < 0) { lead_trim = 0; } } ++i; } LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done); return CODEC_OK; }
/* this is called for each file to process */ enum codec_status codec_run(void) { int error = CODEC_ERROR; intptr_t param; ogg_sync_state oy; ogg_page og; ogg_packet op; ogg_stream_state os; int64_t page_granule = 0; int stream_init = 0; int sample_rate = 48000; OpusDecoder *st = NULL; OpusHeader header; int ret; unsigned long strtoffset = ci->id3->offset; int skip = 0; int64_t seek_target; uint64_t granule_pos; ogg_malloc_init(); global_stack = 0; #if defined(CPU_COLDFIRE) /* EMAC rounding is disabled because of MULT16_32_Q15, which will be inaccurate with rounding in its current incarnation */ coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE); #endif /* pre-init the ogg_sync_state buffer, so it won't need many reallocs */ ogg_sync_init(&oy); oy.storage = 64*1024; oy.data = _ogg_malloc(oy.storage); /* allocate output buffer */ uint16_t *output = (uint16_t*) _ogg_malloc(MAX_FRAME_SIZE*sizeof(uint16_t)); ci->seek_buffer(0); ci->set_elapsed(0); while (1) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { if (st != NULL) { /* calculate granule to seek to (including seek rewind) */ seek_target = (48LL * param) + header.preskip; skip = MIN(seek_target, SEEK_REWIND); seek_target -= skip; LOGF("Opus seek page:%lld,%lld,%ld\n", seek_target, page_granule, (long)param); speex_seek_page_granule(seek_target, page_granule, &oy, &os); } ci->set_elapsed(param); ci->seek_complete(); } /*Get the ogg buffer for writing*/ if (get_more_data(&oy) < 1) { goto done; } /* Loop for all complete pages we got (most likely only one) */ while (ogg_sync_pageout(&oy, &og) == 1) { if (stream_init == 0) { ogg_stream_init(&os, ogg_page_serialno(&og)); stream_init = 1; } /* Add page to the bitstream */ ogg_stream_pagein(&os, &og); page_granule = ogg_page_granulepos(&og); granule_pos = page_granule; /* Do this to avoid allocating space for huge comment packets (embedded Album Art) */ if(os.packetno == 1 && ogg_stream_packetpeek(&os, &op) != 1){ ogg_sync_reset(&oy); } while ((ogg_stream_packetout(&os, &op) == 1) && !op.e_o_s) { if (op.packetno == 0){ /* identification header */ if (opus_header_parse(op.packet, op.bytes, &header) == 0) { LOGF("Could not parse header"); goto done; } skip = header.preskip; st = opus_decoder_create(sample_rate, header.channels, &ret); if (ret != OPUS_OK) { LOGF("opus_decoder_create failed %d", ret); goto done; } LOGF("Decoder inited"); codec_set_replaygain(ci->id3); opus_decoder_ctl(st, OPUS_SET_GAIN(header.gain)); ci->configure(DSP_SET_FREQUENCY, sample_rate); ci->configure(DSP_SET_SAMPLE_DEPTH, 16); ci->configure(DSP_SET_STEREO_MODE, (header.channels == 2) ? STEREO_INTERLEAVED : STEREO_MONO); } else if (op.packetno == 1) { /* Comment header */ } else { if (strtoffset) { ci->seek_buffer(strtoffset); ogg_sync_reset(&oy); strtoffset = 0; break;//next page } /* report progress */ ci->set_elapsed((granule_pos - header.preskip) / 48); /* Decode audio packets */ ret = opus_decode(st, op.packet, op.bytes, output, MAX_FRAME_SIZE, 0); if (ret > 0) { if (skip > 0) { if (ret <= skip) { /* entire output buffer is skipped */ skip -= ret; ret = 0; } else { /* part of output buffer is played */ ret -= skip; ci->pcmbuf_insert(&output[skip * header.channels], NULL, ret); skip = 0; } } else { /* entire buffer is played */ ci->pcmbuf_insert(output, NULL, ret); } granule_pos += ret; } else { if (ret < 0) { LOGF("opus_decode failed %d", ret); goto done; } break; } } } } } LOGF("Returned OK"); error = CODEC_OK; done: ogg_malloc_destroy(); return error; }
/* This is the codec entry point. */ enum codec_status codec_main(void) { mpc_int64_t samplesdone; uint32_t frequency; /* 0.1 kHz accuracy */ uint32_t elapsed_time; /* milliseconds */ uint32_t byterate; /* bytes per second */ mpc_status status; mpc_reader reader; mpc_streaminfo info; mpc_frame_info frame; mpc_demux *demux = NULL; int retval = CODEC_OK; frame.buffer = sample_buffer; /* musepack's sample representation is 18.14 * DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */ ci->configure(DSP_SET_SAMPLE_DEPTH, 29); /* Create a decoder instance */ reader.read = read_impl; reader.seek = seek_impl; reader.tell = tell_impl; reader.get_size = get_size_impl; next_track: if (codec_init()) { retval = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); /* Initialize demux/decoder. */ demux = mpc_demux_init(&reader); if (NULL == demux) { retval = CODEC_ERROR; goto done; } /* Read file's streaminfo data. */ mpc_demux_get_info(demux, &info); byterate = (mpc_uint32_t)(info.average_bitrate) / 8; frequency = info.sample_freq / 100; /* 0.1 kHz accuracy */ ci->configure(DSP_SWITCH_FREQUENCY, info.sample_freq); /* Remark: rockbox offset is the file offset in bytes. So, estimate the * sample seek position from the file offset, the sampling frequency and * the bitrate. As the saved position is exactly calculated the reverse way * there is no loss of information except rounding. */ samplesdone = 100 * ((mpc_uint64_t)(ci->id3->offset * frequency) / byterate); /* Set up digital signal processing for correct number of channels */ /* NOTE: current musepack format only allows for stereo files but code is here to handle other configurations anyway */ if (info.channels == 2) ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); else if (info.channels == 1) ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); else { retval = CODEC_ERROR; goto done; } codec_set_replaygain(ci->id3); /* Resume to saved sample offset. */ if (samplesdone > 0) { if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK) { elapsed_time = (samplesdone*10)/frequency; ci->set_elapsed(elapsed_time); } else { samplesdone = 0; } } /* This is the decoding loop. */ do { /* Complete seek handler. */ if (ci->seek_time) { mpc_int64_t new_offset = ((ci->seek_time - 1)/10)*frequency; if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK) { samplesdone = new_offset; ci->set_elapsed(ci->seek_time); } ci->seek_complete(); } /* Stop or skip occured, exit decoding loop. */ if (ci->stop_codec || ci->new_track) break; /* Decode one frame. */ status = mpc_demux_decode(demux, &frame); ci->yield(); if (frame.bits == -1) { /* Decoding error, exit decoding loop. */ retval = (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR; goto done; } else { /* Decoding passed, insert samples to PCM buffer. */ ci->pcmbuf_insert(frame.buffer, frame.buffer + MPC_FRAME_LENGTH, frame.samples); samplesdone += frame.samples; elapsed_time = (samplesdone*10)/frequency; ci->set_elapsed(elapsed_time); /* Remark: rockbox offset is the file offset in bytes. So estimate * this offset from the samples, sampling frequency and bitrate */ ci->set_offset( (samplesdone * byterate)/(frequency*100) ); } } while (true); done: if (ci->request_next_track()) goto next_track; exit: return retval; }
/* this is called for each file to process */ enum codec_status codec_run(void) { size_t n; int32_t bread; unsigned int frame_samples; uint32_t s = 0; unsigned char c = 0; long action = CODEC_ACTION_NULL; intptr_t param; unsigned char* buffer; NeAACDecFrameInfo frame_info; NeAACDecHandle decoder; NeAACDecConfigurationPtr conf; /* Clean and initialize decoder structures */ if (codec_init()) { LOGF("FAAD: Codec init error\n"); return CODEC_ERROR; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); ci->seek_buffer(ci->id3->first_frame_offset); /* initialise the sound converter */ decoder = NeAACDecOpen(); if (!decoder) { LOGF("FAAD: Decode open error\n"); return CODEC_ERROR; } conf = NeAACDecGetCurrentConfiguration(decoder); conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */ NeAACDecSetConfiguration(decoder, conf); buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); bread = NeAACDecInit(decoder, buffer, n, &s, &c); if (bread < 0) { LOGF("FAAD: DecInit: %ld, %d\n", bread, decoder->object_type); return CODEC_ERROR; } ci->advance_buffer(bread); if (ci->id3->offset > ci->id3->first_frame_offset) { /* Resume the desired (byte) position. */ ci->seek_buffer(ci->id3->offset); NeAACDecPostSeekReset(decoder, 0); update_playing_time(); } else if (ci->id3->elapsed) { action = CODEC_ACTION_SEEK_TIME; param = ci->id3->elapsed; } else { ci->set_elapsed(0); ci->set_offset(ci->id3->first_frame_offset); } /* The main decoding loop */ while (1) { if (action == CODEC_ACTION_NULL) action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { /* Seek to the desired time position. */ ci->seek_buffer(ci->id3->first_frame_offset + (uint32_t)((uint64_t)param * ci->id3->bitrate / 8)); ci->set_elapsed((unsigned long)param); NeAACDecPostSeekReset(decoder, 0); ci->seek_complete(); } action = CODEC_ACTION_NULL; /* Request the required number of bytes from the input buffer */ buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE); if (n == 0) /* End of Stream */ break; /* Decode one block - returned samples will be host-endian */ if (NeAACDecDecode(decoder, &frame_info, buffer, n) == NULL || frame_info.error > 0) { LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); return CODEC_ERROR; } /* Advance codec buffer (no need to call set_offset because of this) */ ci->advance_buffer(frame_info.bytesconsumed); /* Output the audio */ ci->yield(); frame_samples = frame_info.samples >> 1; ci->pcmbuf_insert(&decoder->time_out[0][0], &decoder->time_out[1][0], frame_samples); /* Update the elapsed-time indicator */ update_playing_time(); } LOGF("AAC: Decoding complete\n"); return CODEC_OK; }
/* this is called for each file to process */ enum codec_status codec_run(void) { uint32_t decodedsamples; size_t n; int bufcount; int endofstream; unsigned char *buf; uint8_t *wavbuf; off_t firstblockposn; /* position of the first block in file */ const struct pcm_codec *codec; uint32_t size; intptr_t param; if (codec_init()) { DEBUGF("codec_init() error\n"); return CODEC_ERROR; } codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ bytesdone = ci->id3->offset; /* get RIFF chunk header */ ci->seek_buffer(0); buf = ci->request_buffer(&n, 12); if (n < 12) { DEBUGF("request_buffer error\n"); return CODEC_ERROR; } if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { DEBUGF("CODEC_ERROR: missing riff header\n"); return CODEC_ERROR; } /* advance to first WAVE chunk */ ci->advance_buffer(12); firstblockposn = 12; ci->memset(&format, 0, sizeof(struct pcm_format)); format.is_signed = true; format.is_little_endian = true; decodedsamples = 0; codec = 0; /* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */ while (true) { /* get WAVE chunk header */ buf = ci->request_buffer(&n, 1024); if (n < 8) { DEBUGF("data chunk request_buffer error\n"); /* no more chunks, 'data' chunk must not have been found */ return CODEC_ERROR; } /* chunkSize */ size = (buf[4]|(buf[5]<<8)|(buf[6]<<16)|(buf[7]<<24)); if (memcmp(buf, "fmt ", 4) == 0) { if (size < 16) { DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", (unsigned long)size); return CODEC_ERROR; } /* wFormatTag */ format.formattag=buf[8]|(buf[9]<<8); /* wChannels */ format.channels=buf[10]|(buf[11]<<8); /* skipping dwSamplesPerSec */ /* skipping dwAvgBytesPerSec */ /* wBlockAlign */ format.blockalign=buf[20]|(buf[21]<<8); /* wBitsPerSample */ format.bitspersample=buf[22]|(buf[23]<<8); if (format.formattag != WAVE_FORMAT_PCM) { if (size < 18) { /* this is not a fatal error with some formats, * we'll see later if we can't decode it */ DEBUGF("CODEC_WARNING: non-PCM WAVE (formattag=0x%x) " "doesn't have ext. fmt descr (chunksize=%d<18).\n", (unsigned int)format.formattag, (int)size); } else { if (format.formattag != WAVE_FORMAT_EXTENSIBLE) format.samplesperblock = buf[26]|(buf[27]<<8); else { format.size = buf[24]|(buf[25]<<8); if (format.size < 22) { DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " "missing extension\n"); return CODEC_ERROR; } /* wValidBitsPerSample */ format.bitspersample = buf[26]|(buf[27]<<8); /* skipping dwChannelMask (4bytes) */ /* SubFormat (only get the first two bytes) */ format.formattag = buf[32]|(buf[33]<<8); } } } /* msadpcm specific */ if (format.formattag == WAVE_FORMAT_ADPCM) { if (!set_msadpcm_coeffs(buf)) { return CODEC_ERROR; } } /* get codec */ codec = get_wave_codec(format.formattag); if (!codec) { DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n", (unsigned int) format.formattag); return CODEC_ERROR; } /* riff 8bit linear pcm is unsigned */ if (format.formattag == WAVE_FORMAT_PCM && format.bitspersample == 8) format.is_signed = false; /* set format, parse codec specific tag, check format, and calculate chunk size */ if (!codec->set_format(&format)) { return CODEC_ERROR; } } else if (memcmp(buf, "data", 4) == 0) { format.numbytes = size; /* advance to start of data */ ci->advance_buffer(8); firstblockposn += 8; break; } else if (memcmp(buf, "fact", 4) == 0) { /* dwSampleLength */ if (size >= 4) format.totalsamples = (buf[8]|(buf[9]<<8)|(buf[10]<<16)|(buf[11]<<24)); } else { DEBUGF("unknown WAVE chunk: '%c%c%c%c', size=%lu\n", buf[0], buf[1], buf[2], buf[3], (unsigned long)size); } /* go to next chunk (even chunk sizes must be padded) */ size += 8 + (size & 0x01); ci->advance_buffer(size); firstblockposn += size; } if (!codec) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n"); return CODEC_ERROR; } /* common format check */ if (format.channels == 0) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); return CODEC_ERROR; } if (format.samplesperblock == 0) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n"); return CODEC_ERROR; } if (format.blockalign == 0) { DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n"); return CODEC_ERROR; } if (format.numbytes == 0) { DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); return CODEC_ERROR; } /* check chunksize */ if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels > PCM_SAMPLE_SIZE) format.chunksize = (PCM_SAMPLE_SIZE / format.blockalign) * format.blockalign; if (format.chunksize == 0) { DEBUGF("CODEC_ERROR: chunksize is 0\n"); return CODEC_ERROR; } ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); if (format.channels == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (format.channels == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); return CODEC_ERROR; } /* make sure we're at the correct offset */ if (bytesdone > (uint32_t) firstblockposn) { /* Round down to previous block */ struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, PCM_SEEK_POS, &read_buffer); if (newpos->pos > format.numbytes) return CODEC_OK; if (ci->seek_buffer(firstblockposn + newpos->pos)) { bytesdone = newpos->pos; decodedsamples = newpos->samples; } } else { /* already where we need to be */ bytesdone = 0; } /* The main decoder loop */ endofstream = 0; while (!endofstream) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME, &read_buffer); if (newpos->pos > format.numbytes) { ci->set_elapsed(ci->id3->length); ci->seek_complete(); break; } if (ci->seek_buffer(firstblockposn + newpos->pos)) { bytesdone = newpos->pos; decodedsamples = newpos->samples; } ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); ci->seek_complete(); } wavbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize); if (n == 0) break; /* End of stream */ if (bytesdone + n > format.numbytes) { n = format.numbytes - bytesdone; endofstream = 1; } if (codec->decode(wavbuf, n, samples, &bufcount) == CODEC_ERROR) { DEBUGF("codec error\n"); return CODEC_ERROR; } ci->pcmbuf_insert(samples, NULL, bufcount); ci->advance_buffer(n); bytesdone += n; decodedsamples += bufcount; if (bytesdone >= format.numbytes) endofstream = 1; ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { tta_info info; int status; unsigned int decodedsamples; int endofstream; int new_pos = 0; int sample_count; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1); next_track: status = CODEC_OK; if (codec_init()) { DEBUGF("codec_init() error\n"); status = CODEC_ERROR; goto exit; } if (codec_wait_taginfo() != 0) goto done; if (set_tta_info(&info) < 0 || player_init(&info) < 0) { status = CODEC_ERROR; goto exit; } codec_set_replaygain(ci->id3); ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); if (info.NCH == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (info.NCH == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); status = CODEC_ERROR; goto done; } /* The main decoder loop */ decodedsamples = 0; endofstream = 0; if (ci->id3->offset > 0) { /* Need to save offset for later use (cleared indirectly by advance_buffer) */ new_pos = set_position(ci->id3->offset, TTA_SEEK_POS); if (new_pos >= 0) decodedsamples = new_pos; ci->seek_complete(); } while (!endofstream) { ci->yield(); if (ci->stop_codec || ci->new_track) break; if (ci->seek_time) { new_pos = set_position(ci->seek_time / SEEK_STEP, TTA_SEEK_TIME); if (new_pos >= 0) { decodedsamples = new_pos; ci->seek_complete(); } } sample_count = get_samples(samples); if (sample_count < 0) { status = CODEC_ERROR; break; } ci->pcmbuf_insert(samples, NULL, sample_count); decodedsamples += sample_count; if (decodedsamples >= info.DATALENGTH) endofstream = 1; ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH); } done: player_stop(); if (ci->request_next_track()) goto next_track; exit: return status; }
/* this is called for each file to process */ enum codec_status codec_run(void) { uint32_t elapsedtime; asf_waveformatex_t wfx; size_t resume_offset; int i; int wmares; int res = 0; uint8_t* audiobuf; int audiobufsize; int packetlength = 0; int errcount = 0; intptr_t param; /* Proper reset of the decoder context. */ memset(&wmadec, 0, sizeof(wmadec)); /* Remember the resume position - when the codec is opened, the playback engine will reset it. */ resume_offset = ci->id3->offset; restart_track: if (codec_init()) { LOGF("WMA: Error initialising codec\n"); return CODEC_ERROR; } /* Copy the format metadata we've stored in the id3 TOC field. This saves us from parsing it again here. */ memcpy(&wfx, ci->id3->toc, sizeof(wfx)); ci->seek_buffer(ci->id3->first_frame_offset); if (wma_decode_init(&wmadec,&wfx) < 0) { LOGF("WMA: Unsupported or corrupt file\n"); return CODEC_ERROR; } if (resume_offset > ci->id3->first_frame_offset) { /* Get start of current packet */ int packet_offset = (resume_offset - ci->id3->first_frame_offset) % wfx.packet_size; ci->seek_buffer(resume_offset - packet_offset); elapsedtime = asf_get_timestamp(&i); } else { /* Now advance the file position to the first frame */ ci->seek_buffer(ci->id3->first_frame_offset); elapsedtime = 0; } ci->set_elapsed(elapsedtime); resume_offset = 0; ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); codec_set_replaygain(ci->id3); /* The main decoding loop */ while (res >= 0) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; /* Deal with any pending seek requests */ if (action == CODEC_ACTION_SEEK_TIME) { if (param == 0) { ci->set_elapsed(0); ci->seek_complete(); goto restart_track; /* Pretend you never saw this... */ } elapsedtime = asf_seek(param, &wfx); if (elapsedtime < 1){ ci->set_elapsed(0); ci->seek_complete(); break; } /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/ /*flush the wma decoder state*/ wmadec.last_superframe_len = 0; wmadec.last_bitoffset = 0; ci->set_elapsed(elapsedtime); ci->seek_complete(); } errcount = 0; new_packet: res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); if (res < 0) { /* We'll try to recover from a parse error a certain number of * times. If we succeed, the error counter will be reset. */ if (res == ASF_ERROR_EOF) { /* File ended - not an error */ break; } errcount++; DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount); if (errcount > 5) { return CODEC_ERROR; } else { ci->advance_buffer(packetlength); goto new_packet; } } else if (res > 0) { wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize); for (i=0; i < wmadec.nb_frames; i++) { wmares = wma_decode_superframe_frame(&wmadec, audiobuf, audiobufsize); ci->yield (); if (wmares < 0) { /* Do the above, but for errors in decode. */ errcount++; DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount); if (errcount > 5) { return CODEC_ERROR; } else { ci->advance_buffer(packetlength); goto new_packet; } } else if (wmares > 0) { ci->pcmbuf_insert((*wmadec.frame_out)[0], (*wmadec.frame_out)[1], wmares); elapsedtime += (wmares*10)/(wfx.rate/100); ci->set_elapsed(elapsedtime); } } } ci->advance_buffer(packetlength); } /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/ return CODEC_OK; }
/* this is called for each file to process */ enum codec_status codec_run(void) { struct pcm_format format; uint32_t bytesdone, decodedsamples; size_t n; int bufcount; int endofstream; unsigned char *buf; uint8_t *aubuf; off_t firstblockposn; /* position of the first block in file */ const struct pcm_codec *codec; int offset = 0; intptr_t param; if (codec_init()) { DEBUGF("codec_init() error\n"); return CODEC_ERROR; } codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ bytesdone = ci->id3->offset; ci->memset(&format, 0, sizeof(struct pcm_format)); format.is_signed = true; format.is_little_endian = false; /* set format */ ci->seek_buffer(0); buf = ci->request_buffer(&n, 24); if (n < 24 || (memcmp(buf, ".snd", 4) != 0)) { /* * headerless sun audio file * It is decoded under conditions. * format: G.711 mu-law * channel: mono * frequency: 8000 kHz */ offset = 0; format.formattag = AU_FORMAT_MULAW; format.channels = 1; format.bitspersample = 8; format.numbytes = ci->id3->filesize; } else { /* parse header */ /* data offset */ offset = get_be32(buf + 4); if (offset < 24) { DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset); return CODEC_ERROR; } /* data size */ format.numbytes = get_be32(buf + 8); if (format.numbytes == (uint32_t)0xffffffff) format.numbytes = ci->id3->filesize - offset; /* encoding */ format.formattag = convert_au_format(get_be32(buf + 12), &format); if (format.formattag == AU_FORMAT_UNSUPPORT) { DEBUGF("CODEC_ERROR: sun audio unsupport format: %d\n", get_be32(buf + 12)); return CODEC_ERROR; } /* skip sample rate */ format.channels = get_be32(buf + 20); } /* advance to first WAVE chunk */ ci->advance_buffer(offset); firstblockposn = offset; decodedsamples = 0; codec = 0; /* get codec */ codec = get_au_codec(format.formattag); if (!codec) { DEBUGF("CODEC_ERROR: unsupport sun audio format: %x\n", (int)format.formattag); return CODEC_ERROR; } if (!codec->set_format(&format)) { return CODEC_ERROR; } if (format.numbytes == 0) { DEBUGF("CODEC_ERROR: data size is 0\n"); return CODEC_ERROR; } /* check chunksize */ if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels > PCM_SAMPLE_SIZE) format.chunksize = (PCM_SAMPLE_SIZE / format.blockalign) * format.blockalign; if (format.chunksize == 0) { DEBUGF("CODEC_ERROR: chunksize is 0\n"); return CODEC_ERROR; } ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); if (format.channels == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (format.channels == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); return CODEC_ERROR; } /* make sure we're at the correct offset */ if (bytesdone > (uint32_t) firstblockposn) { /* Round down to previous block */ struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, PCM_SEEK_POS, NULL); if (newpos->pos > format.numbytes) goto done; if (ci->seek_buffer(firstblockposn + newpos->pos)) { bytesdone = newpos->pos; decodedsamples = newpos->samples; } } else { /* already where we need to be */ bytesdone = 0; } ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); /* The main decoder loop */ endofstream = 0; while (!endofstream) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { /* 3rd args(read_buffer) is unnecessary in the format which Sun Audio supports. */ struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME, NULL); if (newpos->pos > format.numbytes) { ci->set_elapsed(ci->id3->length); ci->seek_complete(); break; } if (ci->seek_buffer(firstblockposn + newpos->pos)) { bytesdone = newpos->pos; decodedsamples = newpos->samples; } ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); ci->seek_complete(); } aubuf = (uint8_t *)ci->request_buffer(&n, format.chunksize); if (n == 0) break; /* End of stream */ if (bytesdone + n > format.numbytes) { n = format.numbytes - bytesdone; endofstream = 1; } if (codec->decode(aubuf, n, samples, &bufcount) == CODEC_ERROR) { DEBUGF("codec error\n"); return CODEC_ERROR; } ci->pcmbuf_insert(samples, NULL, bufcount); ci->advance_buffer(n); bytesdone += n; decodedsamples += bufcount; if (bytesdone >= format.numbytes) endofstream = 1; ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } done: return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { struct ape_ctx_t ape_ctx; uint32_t samplesdone; uint32_t elapsedtime; size_t bytesleft; int retval; uint32_t currentframe; uint32_t newfilepos; uint32_t samplestoskip; int nblocks; int bytesconsumed; unsigned char* inbuffer; uint32_t blockstodecode; int res; int firstbyte; size_t resume_offset; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1); next_track: retval = CODEC_OK; if (codec_init()) { LOGF("APE: Error initialising codec\n"); retval = CODEC_ERROR; goto exit; } if (codec_wait_taginfo() != 0) goto done; /* Remember the resume position - when the codec is opened, the playback engine will reset it. */ resume_offset = ci->id3->offset; inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); /* Read the file headers to populate the ape_ctx struct */ if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) { LOGF("APE: Error reading header\n"); retval = CODEC_ERROR; goto exit; } /* Initialise the seektable for this file */ ape_ctx.seektable = seektablebuf; ape_ctx.numseekpoints = MIN(MAX_SEEKPOINTS,ape_ctx.numseekpoints); ci->advance_buffer(ape_ctx.seektablefilepos); /* The seektable may be bigger than the guard buffer (32KB), so we do a read() */ ci->read_filebuf(ape_ctx.seektable, ape_ctx.numseekpoints * sizeof(uint32_t)); #ifdef ROCKBOX_BIG_ENDIAN /* Byte-swap the little-endian seekpoints */ { uint32_t i; for(i = 0; i < ape_ctx.numseekpoints; i++) ape_ctx.seektable[i] = swap32(ape_ctx.seektable[i]); } #endif /* Now advance the file position to the first frame */ ci->advance_buffer(ape_ctx.firstframe - (ape_ctx.seektablefilepos + ape_ctx.numseekpoints * sizeof(uint32_t))); ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate); ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ? STEREO_MONO : STEREO_NONINTERLEAVED); codec_set_replaygain(ci->id3); /* The main decoding loop */ if (resume_offset) { /* The resume offset is a value in bytes - we need to turn it into a frame number and samplestoskip value */ ape_resume(&ape_ctx, resume_offset, ¤tframe, &samplesdone, &samplestoskip, &firstbyte); } else { currentframe = 0; samplesdone = 0; samplestoskip = 0; firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ } /* Initialise the buffer */ inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); /* The main decoding loop - we decode the frames a small chunk at a time */ while (currentframe < ape_ctx.totalframes) { frame_start: /* Calculate how many blocks there are in this frame */ if (currentframe == (ape_ctx.totalframes - 1)) nblocks = ape_ctx.finalframeblocks; else nblocks = ape_ctx.blocksperframe; ape_ctx.currentframeblocks = nblocks; /* Initialise the frame decoder */ init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed); ci->advance_buffer(bytesconsumed); inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); /* Decode the frame a chunk at a time */ while (nblocks > 0) { ci->yield(); if (ci->stop_codec || ci->new_track) { goto done; } /* Deal with any pending seek requests */ if (ci->seek_time) { if (ape_calc_seekpos(&ape_ctx, ((ci->seek_time-1)/10) * (ci->id3->frequency/100), ¤tframe, &newfilepos, &samplestoskip)) { samplesdone = currentframe * ape_ctx.blocksperframe; /* APE's bytestream is weird... */ firstbyte = 3 - (newfilepos & 3); newfilepos &= ~3; ci->seek_buffer(newfilepos); inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); ci->seek_complete(); goto frame_start; /* Sorry... */ } ci->seek_complete(); } blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed, decoded0, decoded1, blockstodecode)) < 0) { /* Frame decoding error, abort */ LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res); retval = CODEC_ERROR; goto done; } ci->yield(); if (samplestoskip > 0) { if (samplestoskip < blockstodecode) { ci->pcmbuf_insert(decoded0 + samplestoskip, decoded1 + samplestoskip, blockstodecode - samplestoskip); samplestoskip = 0; } else { samplestoskip -= blockstodecode; } } else { ci->pcmbuf_insert(decoded0, decoded1, blockstodecode); } samplesdone += blockstodecode; if (!samplestoskip) { /* Update the elapsed-time indicator */ elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); ci->set_elapsed(elapsedtime); } ci->advance_buffer(bytesconsumed); inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); /* Decrement the block count */ nblocks -= blockstodecode; } currentframe++; } done: LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone); if (ci->request_next_track()) goto next_track; exit: return retval; }
enum codec_status codec_main(void) { int status = CODEC_OK; struct pcm_format format; uint32_t bytesdone, decodedsamples; uint32_t num_sample_frames = 0; size_t n; int bufcount; int endofstream; unsigned char *buf; uint8_t *aifbuf; uint32_t offset2snd = 0; off_t firstblockposn; /* position of the first block in file */ bool is_aifc = false; const struct pcm_codec *codec; uint32_t size; /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: if (codec_init()) { status = CODEC_ERROR; goto exit; } while (!*ci->taginfo_ready && !ci->stop_codec) ci->sleep(1); codec_set_replaygain(ci->id3); /* Need to save offset for later use (cleared indirectly by advance_buffer) */ bytesdone = ci->id3->offset; /* assume the AIFF header is less than 1024 bytes */ buf = ci->request_buffer(&n, 1024); if (n < 54) { status = CODEC_ERROR; goto done; } if (memcmp(buf, "FORM", 4) != 0) { DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[0]); status = CODEC_ERROR; goto done; } if (memcmp(&buf[8], "AIFF", 4) == 0) is_aifc = false; else if (memcmp(&buf[8], "AIFC", 4) == 0) is_aifc = true; else { DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[8]); status = CODEC_ERROR; goto done; } buf += 12; n -= 12; ci->memset(&format, 0, sizeof(struct pcm_format)); format.is_signed = true; format.is_little_endian = false; decodedsamples = 0; codec = 0; /* read until 'SSND' chunk, which typically is last */ while (format.numbytes == 0 && n >= 8) { /* chunkSize */ size = ((buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7]); if (memcmp(buf, "COMM", 4) == 0) { if ((!is_aifc && size < 18) || (is_aifc && size < 22)) { DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < %d\n", (unsigned long)size, (is_aifc)?22:18); status = CODEC_ERROR; goto done; } /* num_channels */ format.channels = ((buf[8]<<8)|buf[9]); /* num_sample_frames */ num_sample_frames = ((buf[10]<<24)|(buf[11]<<16)|(buf[12]<<8) |buf[13]); /* sample_size */ format.bitspersample = ((buf[14]<<8)|buf[15]); /* sample_rate (don't use last 4 bytes, only integer fs) */ if (buf[16] != 0x40) { DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n"); status = CODEC_ERROR; goto done; } format.samplespersec = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1; format.samplespersec >>= (16 + 14 - buf[17]); /* compressionType (AIFC only) */ if (is_aifc) { format.formattag = (buf[26]<<24)|(buf[27]<<16)|(buf[28]<<8)|buf[29]; /* * aiff's sample_size is uncompressed sound data size. * But format.bitspersample is compressed sound data size. */ if (format.formattag == AIFC_FORMAT_ALAW || format.formattag == AIFC_FORMAT_MULAW) format.bitspersample = 8; else if (format.formattag == AIFC_FORMAT_QT_IMA_ADPCM) format.bitspersample = 4; } else format.formattag = AIFC_FORMAT_PCM; /* calc average bytes per second */ format.avgbytespersec = format.samplespersec*format.channels*format.bitspersample/8; } else if (memcmp(buf, "SSND", 4)==0) { if (format.bitspersample == 0) { DEBUGF("CODEC_ERROR: unsupported chunk order\n"); status = CODEC_ERROR; goto done; } /* offset2snd */ offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11]; /* block_size */ format.blockalign = ((buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15]) >> 3; if (format.blockalign == 0) format.blockalign = format.channels * format.bitspersample >> 3; format.numbytes = size - 8 - offset2snd; size = 8 + offset2snd; /* advance to the beginning of data */ } else if (is_aifc && (memcmp(buf, "FVER", 4)==0)) {
/* this is the codec entry point */ enum codec_status codec_main(void) { uint32_t elapsedtime; int retval; asf_waveformatex_t wfx; /* Holds the stream properties */ size_t resume_offset; int res; /* Return values from asf_read_packet() and decode_packet() */ uint8_t* audiobuf; /* Pointer to the payload of one wma pro packet */ int audiobufsize; /* Payload size */ int packetlength = 0; /* Logical packet size (minus the header size) */ int outlen = 0; /* Number of bytes written to the output buffer */ int pktcnt = 0; /* Count of the packets played */ /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, 31); next_track: retval = CODEC_OK; /* Wait for the metadata to be read */ if (codec_wait_taginfo() != 0) goto done; /* Remember the resume position */ resume_offset = ci->id3->offset; restart_track: retval = CODEC_OK; if (codec_init()) { LOGF("(WMA Voice) Error: Error initialising codec\n"); retval = CODEC_ERROR; goto done; } /* Copy the format metadata we've stored in the id3 TOC field. This saves us from parsing it again here. */ memcpy(&wfx, ci->id3->toc, sizeof(wfx)); memset(&avctx, 0, sizeof(AVCodecContext)); memset(&avpkt, 0, sizeof(AVPacket)); ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate); ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? STEREO_MONO : STEREO_INTERLEAVED); codec_set_replaygain(ci->id3); /* Initialise the AVCodecContext */ init_codec_ctx(&avctx, &wfx); if (wmavoice_decode_init(&avctx) < 0) { LOGF("(WMA Voice) Error: Unsupported or corrupt file\n"); retval = CODEC_ERROR; goto done; } /* Now advance the file position to the first frame */ ci->seek_buffer(ci->id3->first_frame_offset); elapsedtime = 0; resume_offset = 0; /* The main decoding loop */ while (pktcnt < wfx.numpackets) { ci->yield(); if (ci->stop_codec || ci->new_track) { goto done; } /* Deal with any pending seek requests */ if (ci->seek_time){ if (ci->seek_time == 1) { ci->seek_complete(); goto restart_track; /* Pretend you never saw this... */ } elapsedtime = asf_seek(ci->seek_time, &wfx); if (elapsedtime < 1){ ci->seek_complete(); goto next_track; } ci->set_elapsed(elapsedtime); ci->seek_complete(); } new_packet: res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); if (res < 0) { LOGF("(WMA Voice) read_packet error %d\n",res); goto done; } else { avpkt.data = audiobuf; avpkt.size = audiobufsize; pktcnt++; while(avpkt.size > 0) { /* wmavoice_decode_packet checks for the output buffer size to avoid overflows */ outlen = BUFSIZE*sizeof(int32_t); res = wmavoice_decode_packet(&avctx, decoded, &outlen, &avpkt); if(res < 0) { LOGF("(WMA Voice) Error: decode_packet returned %d", res); if(res == ERROR_WMAPRO_IN_WMAVOICE){ /* Just skip this packet */ ci->advance_buffer(packetlength); goto new_packet; } else goto done; } avpkt.data += res; avpkt.size -= res; if(outlen) { ci->yield (); outlen /= sizeof(int32_t); ci->pcmbuf_insert(decoded, NULL, outlen); elapsedtime += outlen*10/(wfx.rate/100); ci->set_elapsed(elapsedtime); ci->yield (); } } } /* Advance to the next logical packet */ ci->advance_buffer(packetlength); } done: if (ci->request_next_track()) goto next_track; return retval; }
/* this is called for each file to process */ enum codec_status codec_run(void) { tta_info info; unsigned int decodedsamples; int endofstream; int new_pos = 0; int sample_count; intptr_t param; if (codec_init()) { DEBUGF("codec_init() error\n"); return CODEC_ERROR; } ci->seek_buffer(0); if (set_tta_info(&info) < 0 || player_init(&info) < 0) return CODEC_ERROR; codec_set_replaygain(ci->id3); ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); if (info.NCH == 2) { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); } else if (info.NCH == 1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); player_stop(); return CODEC_ERROR; } /* The main decoder loop */ decodedsamples = 0; endofstream = 0; if (ci->id3->offset > 0) { /* Need to save offset for later use (cleared indirectly by advance_buffer) */ new_pos = set_position(ci->id3->offset, TTA_SEEK_POS); if (new_pos >= 0) decodedsamples = new_pos; } ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH); while (!endofstream) { enum codec_command_action action = ci->get_command(¶m); if (action == CODEC_ACTION_HALT) break; if (action == CODEC_ACTION_SEEK_TIME) { new_pos = set_position(param / SEEK_STEP, TTA_SEEK_TIME); if (new_pos >= 0) { decodedsamples = new_pos; } ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH); ci->seek_complete(); } sample_count = get_samples(samples); if (sample_count < 0) break; ci->pcmbuf_insert(samples, NULL, sample_count); decodedsamples += sample_count; if (decodedsamples >= info.DATALENGTH) endofstream = 1; ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH); } player_stop(); return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { size_t n; unsigned char *filebuf; int sample_loc; int retval; /* Generic codec initialisation */ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, 28); next_track: retval = CODEC_OK; if (codec_init()) { retval = CODEC_ERROR; goto exit; } if (codec_wait_taginfo() != 0) goto request_next_track; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); /* Intialise the A52 decoder and check for success */ state = a52_init(0); /* The main decoding loop */ if (ci->id3->offset) { if (ci->seek_buffer(ci->id3->offset)) { samplesdone = (ci->id3->offset / ci->id3->bytesperframe) * A52_SAMPLESPERFRAME; ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000)); } } else { samplesdone = 0; } while (1) { if (ci->stop_codec || ci->new_track) break; if (ci->seek_time) { sample_loc = (ci->seek_time - 1)/1000 * ci->id3->frequency; if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) { samplesdone = sample_loc; ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); } ci->seek_complete(); } filebuf = ci->request_buffer(&n, BUFFER_SIZE); if (n == 0) /* End of Stream */ break; a52_decode_data(filebuf, filebuf + n); ci->advance_buffer(n); } request_next_track: if (ci->request_next_track()) goto next_track; exit: a52_free(state); return retval; }
/* this is the codec entry point */ enum codec_status codec_start(struct codec_api* api) { struct codec_api* ci = api; FLAC__SeekableStreamDecoder* flacDecoder; FLAC__uint64 offset; TEST_CODEC_API(ci); #ifndef SIMULATOR ci->memcpy(iramstart, iramcopy, iramend-iramstart); #endif ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*1024)); ci->configure(CODEC_DSP_ENABLE, (bool *)true); ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); next_track: metadata_length = 0; seek_table = NULL; stream_info = NULL; if (codec_init(api)) { return CODEC_ERROR; } while (!ci->taginfo_ready) ci->yield(); ci->configure(DSP_SET_FREQUENCY, (long *)(ci->id3->frequency)); codec_set_replaygain(ci->id3); /* Create a decoder instance */ flacDecoder = FLAC__seekable_stream_decoder_new(); /* Set up the decoder and the callback functions - this must be done before init */ /* The following are required for stream_decoder and higher */ FLAC__seekable_stream_decoder_set_client_data(flacDecoder,ci); FLAC__seekable_stream_decoder_set_write_callback(flacDecoder, flac_write_handler); FLAC__seekable_stream_decoder_set_read_callback(flacDecoder, flac_read_handler); FLAC__seekable_stream_decoder_set_metadata_callback(flacDecoder, flac_metadata_handler); FLAC__seekable_stream_decoder_set_error_callback(flacDecoder, flac_error_handler); FLAC__seekable_stream_decoder_set_metadata_respond_all(flacDecoder); /* The following are only for the seekable_stream_decoder */ FLAC__seekable_stream_decoder_set_seek_callback(flacDecoder, flac_seek_handler); FLAC__seekable_stream_decoder_set_tell_callback(flacDecoder, flac_tell_handler); FLAC__seekable_stream_decoder_set_length_callback(flacDecoder, flac_length_handler); FLAC__seekable_stream_decoder_set_eof_callback(flacDecoder, flac_eof_handler); /* QUESTION: What do we do when the init fails? */ if (FLAC__seekable_stream_decoder_init(flacDecoder)) { return CODEC_ERROR; } /* The first thing to do is to parse the metadata */ FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDecoder); if (ci->id3->offset && stream_info) { FLAC__uint64 sample; sample = find_sample_number(ci, ci->id3->offset - metadata_length); ci->advance_buffer(ci->id3->offset); FLAC__seekable_stream_decoder_seek_absolute(flacDecoder, sample); FLAC__seekable_stream_decoder_get_decode_position(flacDecoder, &offset); ci->set_offset(offset); samplesdone = (uint32_t)sample; ci->set_elapsed(sample/(ci->id3->frequency/1000)); } else { samplesdone = 0; ci->set_elapsed(0); } /* The main decoder loop */ while (FLAC__seekable_stream_decoder_get_state(flacDecoder) != FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) { ci->yield(); if (ci->stop_codec || ci->reload_codec) { break; } if (ci->seek_time) { int sample_loc; sample_loc = ci->seek_time/1000 * ci->id3->frequency; if (FLAC__seekable_stream_decoder_seek_absolute(flacDecoder, sample_loc)) { samplesdone = sample_loc; ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); } ci->seek_time = 0; } FLAC__seekable_stream_decoder_process_single(flacDecoder); FLAC__seekable_stream_decoder_get_decode_position(flacDecoder, &offset); ci->set_offset(offset); } /* Flush the libFLAC buffers */ FLAC__seekable_stream_decoder_finish(flacDecoder); if (ci->request_next_track()) { if (stream_info) { FLAC__metadata_object_delete(stream_info); } if (seek_table) { FLAC__metadata_object_delete(seek_table); } metadata_length = 0; goto next_track; } return CODEC_OK; }
/* this is the codec entry point */ enum codec_status codec_main(void) { int n_bytes; int song; int duration; char* module; int bytesPerSample =2; 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); int bytes_done =0; size_t filesize; ci->seek_buffer(0); module = ci->request_buffer(&filesize, ci->filesize); if (!module || (size_t)filesize < (size_t)ci->filesize) { DEBUGF("loading error\n"); return CODEC_ERROR; } /*Init ASAP */ if (!ASAP_Load(&asap, ci->id3->path, module, filesize)) { DEBUGF("%s: format not supported",ci->id3->path); return CODEC_ERROR; } /* Make use of 44.1khz */ ci->configure(DSP_SET_FREQUENCY, 44100); /* Sample depth is 16 bit little endian */ ci->configure(DSP_SET_SAMPLE_DEPTH, 16); /* Stereo or Mono output ? */ if(asap.module_info.channels ==1) { ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); bytesPerSample = 2; } else { ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); bytesPerSample = 4; } /* reset eleapsed */ ci->set_elapsed(0); song = asap.module_info.default_song; duration = asap.module_info.durations[song]; if (duration < 0) duration = 180 * 1000; /* set id3 length, because metadata parse might not have done it */ ci->id3->length = duration; ASAP_PlaySong(&asap, song, duration); ASAP_MutePokeyChannels(&asap, 0); /* The main decoder loop */ while (1) { ci->yield(); if (ci->stop_codec || ci->new_track) break; if (ci->seek_time) { /* New time is ready in ci->seek_time */ /* seek to pos */ ASAP_Seek(&asap,ci->seek_time); /* update elapsed */ ci->set_elapsed(ci->seek_time); /* update bytes_done */ bytes_done = ci->seek_time*44.1*2; /* seek ready */ ci->seek_complete(); } /* Generate a buffer full of Audio */ #ifdef ROCKBOX_LITTLE_ENDIAN n_bytes = ASAP_Generate(&asap, samples, sizeof(samples), ASAP_FORMAT_S16_LE); #else n_bytes = ASAP_Generate(&asap, samples, sizeof(samples), ASAP_FORMAT_S16_BE); #endif ci->pcmbuf_insert(samples, NULL, n_bytes /bytesPerSample); bytes_done += n_bytes; ci->set_elapsed((bytes_done / 2) / 44.1); if(n_bytes != sizeof(samples)) break; } if (ci->request_next_track()) goto next_track; return CODEC_OK; }
/* 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; }