void MediaDecoder::writeToRingBuffer(const AudioFrame& decodedFrame, RingBuffer& rb, const AudioFormat outFormat) { const auto libav_frame = decodedFrame.pointer(); decBuff_.setFormat(AudioFormat{ (unsigned) libav_frame->sample_rate, (unsigned) decoderCtx_->channels }); decBuff_.resize(libav_frame->nb_samples); if ( decoderCtx_->sample_fmt == AV_SAMPLE_FMT_FLTP ) { decBuff_.convertFloatPlanarToSigned16(libav_frame->extended_data, libav_frame->nb_samples, decoderCtx_->channels); } else if ( decoderCtx_->sample_fmt == AV_SAMPLE_FMT_S16 ) { decBuff_.deinterleave(reinterpret_cast<const AudioSample*>(libav_frame->data[0]), libav_frame->nb_samples, decoderCtx_->channels); } if ((unsigned)libav_frame->sample_rate != outFormat.sample_rate) { if (!resampler_) { RING_DBG("Creating audio resampler"); resampler_.reset(new Resampler(outFormat)); } resamplingBuff_.setFormat({(unsigned) outFormat.sample_rate, (unsigned) decoderCtx_->channels}); resamplingBuff_.resize(libav_frame->nb_samples); resampler_->resample(decBuff_, resamplingBuff_); rb.put(resamplingBuff_); } else { rb.put(decBuff_); } }
MediaDecoder::Status MediaDecoder::decode(const AudioFrame& decodedFrame) { const auto frame = decodedFrame.pointer(); AVPacket inpacket; av_init_packet(&inpacket); int ret = av_read_frame(inputCtx_, &inpacket); if (ret == AVERROR(EAGAIN)) { return Status::Success; } else if (ret == AVERROR_EOF) { return Status::EOFError; } else if (ret < 0) { char errbuf[64]; av_strerror(ret, errbuf, sizeof(errbuf)); RING_ERR("Couldn't read frame: %s\n", errbuf); return Status::ReadError; } // is this a packet from the audio stream? if (inpacket.stream_index != streamIndex_) { av_packet_unref(&inpacket); return Status::Success; } int frameFinished = 0; int len = avcodec_decode_audio4(decoderCtx_, frame, &frameFinished, &inpacket); av_packet_unref(&inpacket); if (len <= 0) { return Status::DecodeError; } if (frameFinished) { if (emulateRate_ and frame->pkt_pts != AV_NOPTS_VALUE) { auto frame_time = getTimeBase()*(frame->pkt_pts - avStream_->start_time); auto target = startTime_ + static_cast<std::int64_t>(frame_time.real() * 1e6); auto now = av_gettime(); if (target > now) { std::this_thread::sleep_for(std::chrono::microseconds(target - now)); } } return Status::FrameFinished; } return Status::Success; }