int main(void) { const unsigned int FrameLen = 36; unsigned char *macframe = malloc(FrameLen); // alloc MAC header until frame body // fill header with junk, to make this more interesting for (unsigned int i = 0; i < FrameLen; i++) { macframe[i] = 0xde; } set_proto_version(macframe, 0); set_type(macframe, 1); set_subtype(macframe, 1); set_to_ds(macframe, 1); set_from_ds(macframe, 0); set_retry(macframe, 0); set_more_data(macframe, 0); print_header(macframe); printf("Protocol version: %d\n", get_proto_version(macframe)); printf("Type: %d\n", get_type(macframe)); printf("Subtype: %d\n", get_subtype(macframe)); printf("Flags: To DS: %d From DS: %d Retry: %d More Data: %d\n", get_to_ds(macframe) != 0, get_from_ds(macframe) != 0, get_retry(macframe) != 0, get_more_data(macframe) != 0); free(macframe); }
static int setup_readahead(ES_p es) { int err; es->read_ahead_len = 0; es->read_ahead_posn = 0; es->data = NULL; es->data_end = NULL; es->data_ptr = NULL; es->last_packet_posn = 0; es->last_packet_es_data_len = 0; // Try to get the first chunk of data from the file err = get_more_data(es); if (err) return err; if (es->reading_ES) { if (es->read_ahead_len < 3) { fprintf(stderr,"### File only contains %d byte%s\n", es->read_ahead_len,(es->read_ahead_len==1?"":"s")); return 1; } } else { if (es->reader->packet->es_data_len < 3) { fprintf(stderr,"### File PES packet only contains %d byte%s\n", es->reader->packet->es_data_len, (es->reader->packet->es_data_len==1?"":"s")); return 1; } } if (DEBUG) printf("File starts %02x %02x %02x\n",es->data[0],es->data[1],es->data[2]); // Despite (maybe) reporting the above, we haven't actually read anything // yet es->prev2_byte = es->prev1_byte = es->cur_byte = 0xFF; es->posn_of_next_byte.infile = 0; es->posn_of_next_byte.inpacket = 0; return 0; }
static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og, spx_int64_t boundary) { spx_int64_t localoffset = ci->curpos; long more; long ret; if (boundary > 0) boundary += ci->curpos; while (1) { more = spx_ogg_sync_pageseek(oy,og); if (more < 0) { /* skipped n bytes */ localoffset-=more; } else { if (more == 0) { /* send more paramedics */ if(!boundary)return(-1); { ret = get_more_data(oy); if (ret == 0) return(-2); if (ret < 0) return(-3); } } else { /* got a page. Return the offset at the page beginning, advance the internal offset past the page end */ spx_int64_t ret=localoffset; return(ret); } } } }
static int count_time (struct spx_data *data) { ogg_int64_t last_granulepos = 0; /* Seek to somewhere near the last page */ if (io_file_size(data->stream) > 10000) { debug ("Seeking near the end"); if (io_seek(data->stream, -10000, SEEK_END) == -1) logit ("Seeking failed, scanning whole file"); ogg_sync_reset (&data->oy); } /* Read granulepos from the last packet */ while (!io_eof(data->stream)) { /* Sync to page and read it */ while (!io_eof(data->stream)) { if (ogg_sync_pageout(&data->oy, &data->og) == 1) { debug ("Sync"); break; } if (!io_eof(data->stream)) { debug ("Need more data"); get_more_data (data); } } /* We have last packet */ if (io_eof(data->stream)) break; last_granulepos = ogg_page_granulepos (&data->og); } return last_granulepos / data->rate; }
/* 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) { 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; }
static int spx_decode (void *prv_data, char *sound_buf, int nbytes, struct sound_params *sound_params) { struct spx_data *data = (struct spx_data *)prv_data; int bytes_requested = nbytes; int16_t *out = (int16_t *)sound_buf; sound_params->channels = data->nchannels; sound_params->rate = data->rate; sound_params->fmt = SFMT_S16 | SFMT_NE; while (nbytes) { int j; /* First see if there is anything left in the output buffer and * empty it out */ if (data->output_left > 0) { int to_copy = nbytes / sizeof(int16_t); to_copy = MIN(data->output_left, to_copy); memcpy (out, data->output + data->output_start, to_copy * sizeof(int16_t)); out += to_copy; data->output_start += to_copy; data->output_left -= to_copy; nbytes -= to_copy * sizeof(int16_t); } else if (ogg_stream_packetout (&data->os, &data->op) == 1) { int16_t *temp_output = data->output; /* Decode some more samples */ /* Copy Ogg packet to Speex bitstream */ speex_bits_read_from (&data->bits, (char*)data->op.packet, data->op.bytes); for (j = 0; j < data->frames_per_packet; j++) { /* Decode frame */ speex_decode_int (data->st, &data->bits, temp_output); if (data->nchannels == 2) speex_decode_stereo_int (temp_output, data->frame_size, &data->stereo); speex_decoder_ctl (data->st, SPEEX_GET_BITRATE, &data->bitrate); /*data->samples_decoded += data->frame_size;*/ temp_output += data->frame_size * data->nchannels; } /*logit ("Read %d bytes from page", data->frame_size * data->nchannels * data->frames_per_packet);*/ data->output_start = 0; data->output_left = data->frame_size * data->nchannels * data->frames_per_packet; } else if (ogg_sync_pageout(&data->oy, &data->og) == 1) { /* Read in another ogg page */ ogg_stream_pagein (&data->os, &data->og); debug ("Granulepos: %"PRId64, ogg_page_granulepos(&data->og)); } else if (!io_eof(data->stream)) { /* Finally, pull in some more data and try again on the next pass */ get_more_data (data); } else break; } return bytes_requested - nbytes; }
static int spx_seek (void *prv_data, int sec) { struct spx_data *data = (struct spx_data *)prv_data; off_t begin = 0, end, old_pos; assert (sec >= 0); end = io_file_size (data->stream); if (end == -1) return -1; old_pos = io_tell (data->stream); debug ("Seek request to %ds", sec); while (1) { off_t middle = (end + begin) / 2; ogg_int64_t granule_pos; int position_seconds; debug ("Seek to %"PRId64, middle); if (io_seek(data->stream, middle, SEEK_SET) == -1) { io_seek (data->stream, old_pos, SEEK_SET); ogg_stream_reset (&data->os); ogg_sync_reset (&data->oy); return -1; } debug ("Syncing..."); /* Sync to page and read it */ ogg_sync_reset (&data->oy); while (!io_eof(data->stream)) { if (ogg_sync_pageout(&data->oy, &data->og) == 1) { debug ("Sync"); break; } if (!io_eof(data->stream)) { debug ("Need more data"); get_more_data (data); } } if (io_eof(data->stream)) { debug ("EOF when syncing"); return -1; } granule_pos = ogg_page_granulepos(&data->og); position_seconds = granule_pos / data->rate; debug ("We are at %ds", position_seconds); if (position_seconds == sec) { ogg_stream_pagein (&data->os, &data->og); debug ("We have it at granulepos %"PRId64, granule_pos); break; } else if (sec < position_seconds) { end = middle; debug ("going back"); } else { begin = middle; debug ("going forward"); } debug ("begin - end %"PRId64" - %"PRId64, begin, end); if (end - begin <= 200) { /* Can't find the exact position. */ sec = position_seconds; break; } } ogg_sync_reset (&data->oy); ogg_stream_reset (&data->os); return sec; }