Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
  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;
  }
Example #6
0
void FormatContext::writeUncodedFrameDirect(AudioSamples &frame, size_t streamIndex, OptionalErrorCode ec)
{
    writeFrame(frame.raw(), streamIndex, ec, av_write_uncoded_frame);
}
Example #7
0
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;
}