uint32_t AudioSink::DrainConverter(uint32_t aMaxFrames) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); if (!mConverter || !mLastProcessedPacket || !aMaxFrames) { // nothing to drain. return 0; } RefPtr<AudioData> lastPacket = mLastProcessedPacket.ref(); mLastProcessedPacket.reset(); // To drain we simply provide an empty packet to the audio converter. AlignedAudioBuffer convertedData = mConverter->Process(AudioSampleBuffer(AlignedAudioBuffer())).Forget(); uint32_t frames = convertedData.Length() / mOutputChannels; if (!convertedData.SetLength(std::min(frames, aMaxFrames) * mOutputChannels)) { // This can never happen as we were reducing the length of convertData. mErrored = true; return 0; } RefPtr<AudioData> data = CreateAudioFromBuffer(Move(convertedData), lastPacket); if (!data) { return 0; } mProcessedQueue.Push(data); return data->mFrames; }
int VorbisDataDecoder::DoDecode(MediaRawData* aSample) { const unsigned char* aData = aSample->Data(); size_t aLength = aSample->Size(); int64_t aOffset = aSample->mOffset; uint64_t aTstampUsecs = aSample->mTime; int64_t aTotalFrames = 0; MOZ_ASSERT(mPacketCount >= 3); if (!mLastFrameTime || mLastFrameTime.ref() != aSample->mTime) { // We are starting a new block. mFrames = 0; mLastFrameTime = Some(aSample->mTime); } ogg_packet pkt = InitVorbisPacket(aData, aLength, false, false, -1, mPacketCount++); bool first_packet = mPacketCount == 4; if (vorbis_synthesis(&mVorbisBlock, &pkt) != 0) { return -1; } if (vorbis_synthesis_blockin(&mVorbisDsp, &mVorbisBlock) != 0) { return -1; } VorbisPCMValue** pcm = 0; int32_t frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm); // If the first packet of audio in the media produces no data, we // still need to produce an AudioData for it so that the correct media // start time is calculated. Otherwise we'd end up with a media start // time derived from the timecode of the first packet that produced // data. if (frames == 0 && first_packet) { mCallback->Output(new AudioData(aOffset, aTstampUsecs, 0, 0, AlignedAudioBuffer(), mVorbisDsp.vi->channels, mVorbisDsp.vi->rate)); } while (frames > 0) { uint32_t channels = mVorbisDsp.vi->channels; uint32_t rate = mVorbisDsp.vi->rate; AlignedAudioBuffer buffer(frames*channels); if (!buffer) { return -1; } for (uint32_t j = 0; j < channels; ++j) { VorbisPCMValue* channel = pcm[j]; for (uint32_t i = 0; i < uint32_t(frames); ++i) { buffer[i*channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]); } } CheckedInt64 duration = FramesToUsecs(frames, rate); if (!duration.isValid()) { NS_WARNING("Int overflow converting WebM audio duration"); return -1; } CheckedInt64 total_duration = FramesToUsecs(mFrames, rate); if (!total_duration.isValid()) { NS_WARNING("Int overflow converting WebM audio total_duration"); return -1; } CheckedInt64 time = total_duration + aTstampUsecs; if (!time.isValid()) { NS_WARNING("Int overflow adding total_duration and aTstampUsecs"); return -1; }; if (!mAudioConverter) { AudioConfig in(AudioConfig::ChannelLayout(channels, VorbisLayout(channels)), rate); AudioConfig out(channels, rate); mAudioConverter = MakeUnique<AudioConverter>(in, out); } MOZ_ASSERT(mAudioConverter->CanWorkInPlace()); AudioSampleBuffer data(Move(buffer)); data = mAudioConverter->Process(Move(data)); aTotalFrames += frames; mCallback->Output(new AudioData(aOffset, time.value(), duration.value(), frames, data.Forget(), channels, rate)); mFrames += frames; if (vorbis_synthesis_read(&mVorbisDsp, frames) != 0) { return -1; } frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm); } return aTotalFrames > 0 ? 1 : 0; }