bool BufferSinkFilterContext::getAudioSamples(AudioSamples &samples, size_t samplesCount, OptionalErrorCode ec) { if (m_type != FilterMediaType::Audio) { throws_if(ec, Errors::IncorrectBufferSinkMediaType); return false; } return getSamples(samples.raw(), samplesCount, ec); }
bool BufferSinkFilterContext::getAudioFrame(AudioSamples &samples, int flags, OptionalErrorCode ec) { if (m_type != FilterMediaType::Audio) { throws_if(ec, Errors::IncorrectBufferSinkMediaType); return false; } return getFrame(samples.raw(), flags, ec); }
void AudioResampler::push(const AudioSamples &src, error_code &ec) { if (!m_raw) { fflog(AV_LOG_ERROR, "SwrContext does not inited\n"); throws_if(ec, Errors::ResamplerNotInited); return; } // Null samples is allowed if (src) { if (src.sampleRate() != srcSampleRate() || src.sampleFormat() != srcSampleFormat() || src.channelsCount() != srcChannels() || src.channelsLayout() != srcChannelLayout()) { throws_if(ec, Errors::ResamplerInputChanges); return; } } auto sts = swr_convert_frame(m_raw, nullptr, src.raw()); if (sts < 0) { fflog(AV_LOG_DEBUG, "Src is null: %d, payload: %p\n", src.isNull(), src.data()); throws_if(ec, sts, ffmpeg_category()); return; } // TODO: need protection if we still work in scheme: One Resampler Per Channel m_streamIndex = src.streamIndex(); // Need to restore PTS in output frames if (m_prevPts > src.pts()) // Reset case m_nextPts = Timestamp(); m_prevPts = src.pts(); //auto result = swr_get_delay(m_raw, m_dstRate); //clog << " delay [push]: " << result << endl; }
AudioSamples AudioDecoderContext::decode(const Packet &inPacket, size_t offset, OptionalErrorCode ec) { clear_if(ec); AudioSamples outSamples; int gotFrame = 0; auto st = decodeCommon(outSamples, inPacket, offset, gotFrame, avcodec_decode_audio_legacy); if (get<1>(st)) { throws_if(ec, get<0>(st), *get<1>(st)); return AudioSamples(); } if (!gotFrame) { outSamples.setComplete(false); } // Fix channels layout if (outSamples.channelsCount() && !outSamples.channelsLayout()) av_frame_set_channel_layout(outSamples.raw(), av_get_default_channel_layout(outSamples.channelsCount())); return outSamples; }
int AudioResampler :: resample(IAudioSamples * pOutSamples, IAudioSamples* pInSamples, unsigned int numSamples) { int retval = -1; AudioSamples* outSamples = dynamic_cast<AudioSamples*>(pOutSamples); AudioSamples* inSamples = dynamic_cast<AudioSamples*>(pInSamples); unsigned int sampleSize=0; try { if (!outSamples) throw std::invalid_argument("no output samples"); if (outSamples == inSamples) throw std::invalid_argument("resampling into the same IAudioSamples is not allowed"); // null out the output samples. outSamples->setComplete(false, 0, mOSampleRate, mOChannels, mOFmt, Global::NO_PTS); if (inSamples) { if (!inSamples->isComplete()) throw std::invalid_argument("input samples are not complete"); if (inSamples->getSampleRate() != mISampleRate) throw std::invalid_argument("unexpected input sample rate"); if (inSamples->getChannels() != mIChannels) throw std::invalid_argument("unexpected # of input channels"); if (inSamples->getFormat() != mIFmt) throw std::invalid_argument("unexpected sample format"); if (numSamples == 0) numSamples = inSamples->getNumSamples(); else numSamples = FFMIN(numSamples, inSamples->getNumSamples()); sampleSize = inSamples->getSampleBitDepth()/8; } else { numSamples = 0; sampleSize = IAudioSamples::findSampleBitDepth(mIFmt)/8; } int32_t neededSamples = getMinimumNumSamplesRequiredInOutputSamples(numSamples); int32_t bytesPerOutputSample = mOChannels*IAudioSamples::findSampleBitDepth(mOFmt)/8; int32_t neededBytes = neededSamples * bytesPerOutputSample; // This causes a buffer resize to occur if needed if (outSamples->ensureCapacity(neededBytes) < 0) throw std::runtime_error("attempted to resize output buffer but failed"); uint32_t outBufSize = outSamples->getMaxBufferSize(); int32_t gap = (neededSamples*bytesPerOutputSample)-outBufSize; if (gap > 0) { // VS_LOG_ERROR("maxBufferSize: %d; neededSampleRoom: %d; sampleSize: %d; numSamples: %d; conversionRatio: %f;", // (int32_t)outSamples->getMaxBufferSize(), // neededSampleRoom, // sampleSize, // numSamples, // conversionRatio); (void) sampleSize; // to avoid a -Werror error throw std::invalid_argument("not enough room in output buffer"); } short * inBuf = inSamples ? inSamples->getRawSamples(0) : 0; short *outBuf = outSamples->getRawSamples(0); if (!outBuf) throw std::invalid_argument("could not get output bytes"); VS_ASSERT(mContext, "Should have been set at initialization"); if (!mContext) throw std::invalid_argument("programmer error"); // Now we should be far enough along that we can safely try a resample. retval = audio_resample(mContext, outBuf, inBuf, numSamples); #if 0 if (retval >0){ char string[2048*16+1]; unsigned int i=0; for (i = 0; i < sizeof(string)-1; i++) string[i] = 'X'; bool allZero = true; for (i=0; i< FFMIN(numSamples, 2000);i++) { snprintf(string+(5*i), sizeof(string)-5*i, "%04hX.", inBuf[i]); if (inBuf[i] != 0) allZero = false; } VS_LOG_DEBUG("Input Buffer (%d): %s", numSamples, string); for (i=0; i< FFMIN((unsigned int)retval, 2000);i++) { snprintf(string+(9*i), sizeof(string)-9*i, "%04hX%04hX.", outBuf[2*i], outBuf[2*i+1]); if (outBuf[2*i] != 0 || outBuf[2*i+1] != 0) allZero = false; } VS_LOG_DEBUG("Output Buffer (%d): %s", retval, string); if (!allZero) VS_LOG_DEBUG("Got an audio buffer with content"); } #endif // 0 if (retval >= 0) { // copy the Pts int64_t pts = Global::NO_PTS; if (inSamples) { pts = inSamples->getPts(); mNextPts = pts + IAudioSamples::samplesToDefaultPts(retval, mOSampleRate); } else { pts = mNextPts; } if (pts != Global::NO_PTS) pts += mPtsOffset; outSamples->setComplete(true, retval, mOSampleRate, mOChannels, mOFmt, pts); int expectedSamples = 0; if (inSamples) { double top = mOSampleRate; double bottom = mISampleRate; double sampleOnlyConverstionRatio = top / bottom; expectedSamples = (int)(numSamples * sampleOnlyConverstionRatio); } else { VS_LOG_TRACE("Got null samples; outputted all cached and set pts offset from %lld to 0", mPtsOffset); expectedSamples = retval; // and reset the offset mPtsOffset = 0; } if (retval != expectedSamples) { // we got a different number of samples than expected; we need to update // our pts offset int sampleDelta = retval - expectedSamples; int64_t ptsDelta = IAudioSamples::samplesToDefaultPts(sampleDelta, mOSampleRate); mPtsOffset += ptsDelta; } } } catch (std::invalid_argument & e) { VS_LOG_DEBUG("invalid argument: %s", e.what()); retval = -1; } return retval; }
void FormatContext::writeUncodedFrameDirect(AudioSamples &frame, size_t streamIndex, OptionalErrorCode ec) { writeFrame(frame.raw(), streamIndex, ec, av_write_uncoded_frame); }
bool AudioResampler::pop(AudioSamples &dst, bool getall, error_code &ec) { clear_if(ec); if (!m_raw) { fflog(AV_LOG_ERROR, "SwrContext does not inited\n"); throws_if(ec, Errors::ResamplerNotInited); return false; } if (dst.sampleRate() != dstSampleRate() || dst.sampleFormat() != dstSampleFormat() || dst.channelsCount() != dstChannels() || dst.channelsLayout() != dstChannelLayout()) { throws_if(ec, Errors::ResamplerOutputChanges); return false; } auto result = swr_get_delay(m_raw, m_dstRate); //clog << " delay [pop]: " << result << endl; // Need more data if (result < dst.samplesCount() && getall == false) { return false; } auto sts = swr_convert_frame(m_raw, dst.raw(), nullptr); if (sts < 0) { throws_if(ec, sts, ffmpeg_category()); return false; } dst.setTimeBase(Rational(1, m_dstRate)); dst.setStreamIndex(m_streamIndex); dst.setComplete(true); // Ugly PTS handling. More clean one can be done by user code if (!m_nextPts.isValid()) { m_nextPts = Timestamp(0, dst.timeBase()); } dst.setPts(m_nextPts); m_nextPts = dst.pts() + Timestamp{dst.samplesCount(), dst.timeBase()}; //result = swr_get_delay(m_raw, m_dstRate); //clog << " delay [pop]: " << result << endl; // When no data, samples count sets to zero return dst.samplesCount() ? true : false; }