ssize_t ad_read_sndfile(WfDecoder* d, float* out, size_t len) { SndfileDecoder* priv = (SndfileDecoder*)d->d; if (!priv) return -1; switch(d->info.bit_depth){ case 32: return sf_read_float (priv->sffile, out, len); case 16: { short* d16 = g_malloc0(len * sizeof(short)); ssize_t r = sf_read_short (priv->sffile, d16, len); int16_to_float(out, d16, d->info.channels, len / d->info.channels, 0); g_free(d16); return r; } #ifdef DEBUG default: gwarn("unhandled bit depth: %i", d->info.bit_depth); #endif } return -1; }
ssize_t ad_read_ffmpeg(void *sf, float* d, size_t len) { ffmpeg_audio_decoder *priv = (ffmpeg_audio_decoder*) sf; if (!priv) return -1; size_t frames = len / priv->channels; int written = 0; int ret = 0; while (ret >= 0 && written < frames) { dbg(3, "loop: %i/%i (bl:%lu)",written, frames, priv->m_tmpBufferLen ); if (priv->seek_frame == 0 && priv->m_tmpBufferLen > 0 ) { int s = MIN(priv->m_tmpBufferLen / priv->channels, frames - written ); int16_to_float(priv->m_tmpBufferStart, d, priv->channels, s , written); written += s; priv->output_clock+=s; s = s * priv->channels; priv->m_tmpBufferStart += s; priv->m_tmpBufferLen -= s; ret = 0; } else { priv->m_tmpBufferStart = priv->m_tmpBuffer; priv->m_tmpBufferLen = 0; if (!priv->pkt_ptr || priv->pkt_len < 1) { if (priv->packet.data) av_free_packet(&priv->packet); ret = av_read_frame(priv->formatContext, &priv->packet); if (ret < 0) { dbg(2, "reached end of file."); break; } priv->pkt_len = priv->packet.size; priv->pkt_ptr = priv->packet.data; } if (priv->packet.stream_index != priv->audioStream) { priv->pkt_ptr = NULL; continue; } /* decode all chunks in packet */ int data_size= AVCODEC_MAX_AUDIO_FRAME_SIZE; #if 0 // TODO ffcompat.h -- this works but is not optimal (channels may not be planar/interleaved) AVFrame avf; // TODO statically allocate memset(&avf, 0, sizeof(AVFrame)); // not sure if that is needed int got_frame = 0; ret = avcodec_decode_audio4(priv->codecContext, &avf, &got_frame, &priv->packet); data_size = avf.linesize[0]; memcpy(priv->m_tmpBuffer, avf.data[0], avf.linesize[0] * sizeof(uint8_t)); #else // this was deprecated in LIBAVCODEC_VERSION_MAJOR 53 ret = avcodec_decode_audio3(priv->codecContext, priv->m_tmpBuffer, &data_size, &priv->packet); #endif if (ret < 0 || ret > priv->pkt_len) { #if 0 dbg(0, "audio decode error"); return -1; #endif priv->pkt_len = 0; ret = 0; continue; } priv->pkt_len -= ret; priv->pkt_ptr += ret; /* sample exact alignment */ if (priv->packet.pts != AV_NOPTS_VALUE) { priv->decoder_clock = priv->samplerate * av_q2d(priv->formatContext->streams[priv->audioStream]->time_base) * priv->packet.pts; } else { dbg(0, "!!! NO PTS timestamp in file"); priv->decoder_clock += (data_size>>1) / priv->channels; } if (data_size > 0) { priv->m_tmpBufferLen+= (data_size>>1); // 2 bytes per sample } /* align buffer after seek. */ if (priv->seek_frame > 0) { const int diff = priv->output_clock-priv->decoder_clock; if (diff < 0) { /* seek ended up past the wanted sample */ gwarn("audio seek failed."); return -1; } else if (priv->m_tmpBufferLen < (diff*priv->channels)) { /* wanted sample not in current buffer - keep going */ dbg(2, " !!! seeked sample was not in decoded buffer. frames-to-go: %li", diff); priv->m_tmpBufferLen = 0; } else if (diff!=0 && data_size > 0) { /* wanted sample is in current buffer but not at the beginnning */ dbg(2, " !!! sync buffer to seek. (diff:%i)", diff); priv->m_tmpBufferStart+= diff*priv->codecContext->channels; priv->m_tmpBufferLen -= diff*priv->codecContext->channels; #if 1 memmove(priv->m_tmpBuffer, priv->m_tmpBufferStart, priv->m_tmpBufferLen); priv->m_tmpBufferStart = priv->m_tmpBuffer; #endif priv->seek_frame = 0; priv->decoder_clock += diff; } else if (data_size > 0) { dbg(2, "Audio exact sync-seek (%"PRIi64" == %"PRIi64")", priv->decoder_clock, priv->seek_frame); priv->seek_frame = 0; } else { dbg(0, "Error: no audio data in packet"); } } //dbg(0, "PTS: decoder:%"PRIi64". - want: %"PRIi64, priv->decoder_clock, priv->output_clock); //dbg(0, "CLK: frame: %"PRIi64" T:%.3fs",priv->decoder_clock, (float) priv->decoder_clock/priv->samplerate); } }