static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { size_t frames = frame->header.blocksize; unsigned bits_per_sample = frame->header.bits_per_sample; unsigned channels = frame->header.channels; FLAC__int32 *lptr = (FLAC__int32 *)buffer[0]; FLAC__int32 *rptr = (FLAC__int32 *)buffer[channels > 1 ? 1 : 0]; if (decode.new_stream) { LOCK_O; LOG_INFO("setting track_start"); output.track_start = outputbuf->writep; decode.new_stream = false; #if DSD if (output.has_dop && bits_per_sample == 24 && is_flac_dop((u32_t *)lptr, (u32_t *)rptr, frames)) { LOG_INFO("file contains DOP"); output.next_dop = true; output.next_sample_rate = frame->header.sample_rate; output.fade = FADE_INACTIVE; } else { output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates); output.next_dop = false; if (output.fade_mode) _checkfade(true); } #else output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.supported_rates); if (output.fade_mode) _checkfade(true); #endif UNLOCK_O; } LOCK_O_direct; while (frames > 0) { frames_t f; frames_t count; s32_t *optr; IF_DIRECT( optr = (s32_t *)outputbuf->writep; f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; ); IF_PROCESS( optr = (s32_t *)process.inbuf; f = process.max_in_frames; );
static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) { size_t frames = frame->header.blocksize; unsigned bits_per_sample = frame->header.bits_per_sample; unsigned channels = frame->header.channels; FLAC__int32 *lptr = (FLAC__int32 *)buffer[0]; FLAC__int32 *rptr = (FLAC__int32 *)buffer[channels > 1 ? 1 : 0]; if (decode.new_stream) { LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(frame->header.sample_rate, output.max_sample_rate); output.track_start = outputbuf->writep; if (output.fade_mode) _checkfade(true); decode.new_stream = false; UNLOCK_O; } LOCK_O_direct; while (frames > 0) { frames_t f; frames_t count; s32_t *optr; IF_DIRECT( optr = (s32_t *)outputbuf->writep; f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; ); IF_PROCESS( optr = (s32_t *)process.inbuf; f = process.max_in_frames; );
static decode_state faad_decode(void) { size_t bytes_total; size_t bytes_wrap; NeAACDecFrameInfo info; s32_t *iptr; bool endstream; frames_t frames; LOCK_S; bytes_total = _buf_used(streambuf); bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); if (stream.state <= DISCONNECT && !bytes_total) { UNLOCK_S; return DECODE_COMPLETE; } if (a->consume) { u32_t consume = min(a->consume, bytes_wrap); LOG_DEBUG("consume: %u of %u", consume, a->consume); _buf_inc_readp(streambuf, consume); a->pos += consume; a->consume -= consume; UNLOCK_S; return DECODE_RUNNING; } if (decode.new_stream) { int found = 0; static unsigned char channels; static unsigned long samplerate; if (a->type == '2') { // adts stream - seek for header while (bytes_wrap >= 2 && (*(streambuf->readp) != 0xFF || (*(streambuf->readp + 1) & 0xF6) != 0xF0)) { _buf_inc_readp(streambuf, 1); bytes_total--; bytes_wrap--; } if (bytes_wrap >= 2) { long n = NEAAC(a, Init, a->hAac, streambuf->readp, bytes_wrap, &samplerate, &channels); if (n < 0) { found = -1; } else { _buf_inc_readp(streambuf, n); found = 1; } } } else { // mp4 - read header found = read_mp4_header(&samplerate, &channels); } if (found == 1) { LOG_INFO("samplerate: %u channels: %u", samplerate, channels); bytes_total = _buf_used(streambuf); bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(samplerate, output.supported_rates); IF_DSD( output.next_dop = false; )
static decode_state faad_decode(void) { size_t bytes_total; size_t bytes_wrap; NeAACDecFrameInfo info; s32_t *iptr; bool endstream; frames_t frames; LOCK_S; bytes_total = _buf_used(streambuf); bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); if (stream.state <= DISCONNECT && !bytes_total) { UNLOCK_S; return DECODE_COMPLETE; } if (a->consume) { u32_t consume = min(a->consume, bytes_wrap); LOG_DEBUG("consume: %u of %u", consume, a->consume); _buf_inc_readp(streambuf, consume); a->pos += consume; a->consume -= consume; UNLOCK_S; return DECODE_RUNNING; } if (decode.new_stream) { int found = 0; static unsigned char channels; static unsigned long samplerate; if (a->type == '2') { // adts stream - seek for header while (bytes_wrap >= 2 && (*(streambuf->readp) != 0xFF || (*(streambuf->readp + 1) & 0xF6) != 0xF0)) { _buf_inc_readp(streambuf, 1); bytes_total--; bytes_wrap--; } if (bytes_wrap >= 2) { long n = NEAAC(a, Init, a->hAac, streambuf->readp, bytes_wrap, &samplerate, &channels); if (n < 0) { found = -1; } else { _buf_inc_readp(streambuf, n); found = 1; } } } else { // mp4 - read header found = read_mp4_header(&samplerate, &channels); } if (found == 1) { LOG_INFO("samplerate: %u channels: %u", samplerate, channels); bytes_total = _buf_used(streambuf); bytes_wrap = min(bytes_total, _buf_cont_read(streambuf)); LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(samplerate, output.max_sample_rate); output.track_start = outputbuf->writep; if (output.fade_mode) _checkfade(true); decode.new_stream = false; UNLOCK_O; } else if (found == -1) { LOG_WARN("error reading stream header"); UNLOCK_S; return DECODE_ERROR; } else { // not finished header parsing come back next time UNLOCK_S; return DECODE_RUNNING; } } if (bytes_wrap < WRAPBUF_LEN && bytes_total > WRAPBUF_LEN) { // make a local copy of frames which may have wrapped round the end of streambuf u8_t buf[WRAPBUF_LEN]; memcpy(buf, streambuf->readp, bytes_wrap); memcpy(buf + bytes_wrap, streambuf->buf, WRAPBUF_LEN - bytes_wrap); iptr = NEAAC(a, Decode, a->hAac, &info, buf, WRAPBUF_LEN); } else { iptr = NEAAC(a, Decode, a->hAac, &info, streambuf->readp, bytes_wrap); } if (info.error) { LOG_WARN("error: %u %s", info.error, NEAAC(a, GetErrorMessage, info.error)); } endstream = false; // mp4 end of chunk - skip to next offset if (a->chunkinfo && a->chunkinfo[a->nextchunk].offset && a->sample++ == a->chunkinfo[a->nextchunk].sample) { if (a->chunkinfo[a->nextchunk].offset > a->pos) { u32_t skip = a->chunkinfo[a->nextchunk].offset - a->pos; if (skip != info.bytesconsumed) { LOG_DEBUG("skipping to next chunk pos: %u consumed: %u != skip: %u", a->pos, info.bytesconsumed, skip); } if (bytes_total >= skip) { _buf_inc_readp(streambuf, skip); a->pos += skip; } else { a->consume = skip; } a->nextchunk++; } else { LOG_ERROR("error: need to skip backwards!"); endstream = true; } // adts and mp4 when not at end of chunk } else if (info.bytesconsumed != 0) { _buf_inc_readp(streambuf, info.bytesconsumed); a->pos += info.bytesconsumed; // error which doesn't advance streambuf - end } else { endstream = true; } UNLOCK_S; if (endstream) { LOG_WARN("unable to decode further"); return DECODE_ERROR; } if (!info.samples) { a->empty = true; return DECODE_RUNNING; } frames = info.samples / info.channels; if (a->skip) { u32_t skip; if (a->empty) { a->empty = false; a->skip -= frames; LOG_DEBUG("gapless: first frame empty, skipped %u frames at start", frames); } skip = min(frames, a->skip); LOG_DEBUG("gapless: skipping %u frames at start", skip); frames -= skip; a->skip -= skip; iptr += skip * info.channels; } if (a->samples) { if (a->samples < frames) { LOG_DEBUG("gapless: trimming %u frames from end", frames - a->samples); frames = (frames_t)a->samples; } a->samples -= frames; } LOG_SDEBUG("write %u frames", frames); LOCK_O_direct; while (frames > 0) { frames_t f; frames_t count; s32_t *optr; IF_DIRECT( f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME; optr = (s32_t *)outputbuf->writep; ); IF_PROCESS( f = process.max_in_frames; optr = (s32_t *)process.inbuf; );
static decode_state ff_decode(void) { int r, len, got_frame; AVPacket pkt_c; s32_t *optr = NULL; if (decode.new_stream) { AVIOContext *avio; AVStream *av_stream; AVCodec *codec; int o; int audio_stream = -1; ff->mmsh_bytes_left = ff->mmsh_bytes_pad = ff->mmsh_packet_len = 0; if (!ff->readbuf) { ff->readbuf = AV(ff, malloc, READ_SIZE + FF_INPUT_BUFFER_PADDING_SIZE); } avio = AVIO(ff, alloc_context, ff->readbuf, READ_SIZE, 0, NULL, _read_data, NULL, NULL); avio->seekable = 0; ff->formatC = AVFORMAT(ff, alloc_context); if (ff->formatC == NULL) { LOG_ERROR("null context"); return DECODE_ERROR; } ff->formatC->pb = avio; ff->formatC->flags |= AVFMT_FLAG_CUSTOM_IO | AVFMT_FLAG_NOPARSE; o = AVFORMAT(ff, open_input, &ff->formatC, "", ff->input_format, NULL); if (o < 0) { LOG_WARN("avformat_open_input: %d %s", o, av__err2str(o)); return DECODE_ERROR; } LOG_INFO("format: name:%s lname:%s", ff->formatC->iformat->name, ff->formatC->iformat->long_name); o = AVFORMAT(ff, find_stream_info, ff->formatC, NULL); if (o < 0) { LOG_WARN("avformat_find_stream_info: %d %s", o, av__err2str(o)); return DECODE_ERROR; } if (ff->wma && ff->wma_playstream < ff->formatC->nb_streams) { if (ff->formatC->streams[ff->wma_playstream]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { LOG_INFO("using wma stream sent from server: %i", ff->wma_playstream); audio_stream = ff->wma_playstream; } } if (audio_stream == -1) { int i; for (i = 0; i < ff->formatC->nb_streams; ++i) { if (ff->formatC->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { audio_stream = i; LOG_INFO("found stream: %i", i); break; } } } if (audio_stream == -1) { LOG_WARN("no audio stream found"); return DECODE_ERROR; } av_stream = ff->formatC->streams[audio_stream]; ff->codecC = av_stream->codec; codec = AVCODEC(ff, find_decoder, ff->codecC->codec_id); AVCODEC(ff, open2, ff->codecC, codec, NULL); ff->frame = AVCODEC(ff, alloc_frame); ff->avpkt = AV(ff, malloc, sizeof(AVPacket)); if (ff->avpkt == NULL) { LOG_ERROR("can't allocate avpkt"); return DECODE_ERROR; } AV(ff, init_packet, ff->avpkt); ff->avpkt->data = NULL; ff->avpkt->size = 0; LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(ff->codecC->sample_rate, output.max_sample_rate); output.track_start = outputbuf->writep; if (output.fade_mode) _checkfade(true); decode.new_stream = false; UNLOCK_O; } got_frame = 0; if ((r = AV(ff, read_frame, ff->formatC, ff->avpkt)) < 0) { if (r == AVERROR_EOF) { if (ff->end_of_stream) { LOG_INFO("decode complete"); return DECODE_COMPLETE; } else { LOG_INFO("codec end of file"); } } else { LOG_ERROR("av_read_frame error: %i %s", r, av__err2str(r)); } return DECODE_RUNNING; } // clone packet as we are adjusting it pkt_c = *ff->avpkt; IF_PROCESS( optr = (s32_t *)process.inbuf; process.in_frames = 0; );