void GonkAudioDecoderManager::ProcessFlush() { GADM_LOG("FLUSH<<<"); mAudioQueue.Reset(); GADM_LOG(">>>FLUSH"); GonkDecoderManager::ProcessFlush(); }
void GonkAudioDecoderManager::ResetEOS() { GADM_LOG("ResetEOS(<<<"); mAudioQueue.Reset(); GADM_LOG(">>>ResetEOS("); GonkDecoderManager::ResetEOS(); }
nsresult GonkAudioDecoderManager::Flush() { GADM_LOG("FLUSH<<<"); mAudioQueue.Reset(); GADM_LOG(">>>FLUSH"); return GonkDecoderManager::Flush(); }
nsresult GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) { if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) { GADM_LOG("Audio Buffer is not valid!"); return NS_ERROR_UNEXPECTED; } int64_t timeUs; if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { return NS_ERROR_UNEXPECTED; } if (mAudioBuffer->range_length() == 0) { // Some decoders may return spurious empty buffers that we just want to ignore // quoted from Android's AwesomePlayer.cpp ReleaseAudioBuffer(); return NS_ERROR_NOT_AVAILABLE; } if (mLastDecodedTime > timeUs) { ReleaseAudioBuffer(); GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs); MOZ_ASSERT(false); return NS_ERROR_NOT_AVAILABLE; } mLastDecodedTime = timeUs; const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data()); size_t dataOffset = mAudioBuffer->range_offset(); size_t size = mAudioBuffer->range_length(); nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2]); memcpy(buffer.get(), data+dataOffset, size); uint32_t frames = size / (2 * mAudioChannels); CheckedInt64 duration = FramesToUsecs(frames, mAudioRate); if (!duration.isValid()) { return NS_ERROR_UNEXPECTED; } nsRefPtr<AudioData> audioData = new AudioData(aStreamOffset, timeUs, duration.value(), frames, buffer.forget(), mAudioChannels, mAudioRate); ReleaseAudioBuffer(); audioData.forget(v); return NS_OK; }
nsresult GonkAudioDecoderManager::CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset) { if (!(aBuffer != nullptr && aBuffer->data() != nullptr)) { GADM_LOG("Audio Buffer is not valid!"); return NS_ERROR_UNEXPECTED; } int64_t timeUs; if (!aBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { return NS_ERROR_UNEXPECTED; } if (aBuffer->range_length() == 0) { // Some decoders may return spurious empty buffers that we just want to ignore // quoted from Android's AwesomePlayer.cpp return NS_ERROR_NOT_AVAILABLE; } if (mLastTime > timeUs) { GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs); MOZ_ASSERT(false); return NS_ERROR_NOT_AVAILABLE; } mLastTime = timeUs; const uint8_t *data = static_cast<const uint8_t*>(aBuffer->data()); size_t dataOffset = aBuffer->range_offset(); size_t size = aBuffer->range_length(); uint32_t frames = size / (2 * mAudioChannels); CheckedInt64 duration = FramesToUsecs(frames, mAudioRate); if (!duration.isValid()) { return NS_ERROR_UNEXPECTED; } typedef AudioCompactor::NativeCopy OmxCopy; mAudioCompactor.Push(aStreamOffset, timeUs, mAudioRate, frames, mAudioChannels, OmxCopy(data+dataOffset, size, mAudioChannels)); return NS_OK; }
android::sp<MediaCodecProxy> GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback) { status_t rv = OK; if (mLooper != nullptr) { return nullptr; } // Create ALooper mLooper = new ALooper; mLooper->setName("GonkAudioDecoderManager"); mLooper->start(); mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr); if (!mDecoder.get()) { return nullptr; } if (!mDecoder->AskMediaCodecAndWait()) { mDecoder = nullptr; return nullptr; } sp<AMessage> format = new AMessage; // Fixed values GADM_LOG("Configure audio mime type:%s, chan no:%d, sample-rate:%d, profile:%d", mMimeType.get(), mAudioChannels, mAudioRate, mAudioProfile); format->setString("mime", mMimeType.get()); format->setInt32("channel-count", mAudioChannels); format->setInt32("sample-rate", mAudioRate); format->setInt32("aac-profile", mAudioProfile); status_t err = mDecoder->configure(format, nullptr, nullptr, 0); if (err != OK || !mDecoder->Prepare()) { return nullptr; } if (mMimeType.EqualsLiteral("audio/mp4a-latm")) { rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, android::MediaCodec::BUFFER_FLAG_CODECCONFIG); } if (rv == OK) { return mDecoder; } else { GADM_LOG("Failed to input codec specific data!"); return nullptr; } }
bool GonkAudioDecoderManager::InitMediaCodecProxy() { status_t rv = OK; if (!InitLoopers(MediaData::AUDIO_DATA)) { return false; } mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false); if (!mDecoder.get()) { return false; } if (!mDecoder->AllocateAudioMediaCodec()) { mDecoder = nullptr; return false; } sp<AMessage> format = new AMessage; // Fixed values GADM_LOG("Configure audio mime type:%s, chan no:%d, sample-rate:%d, profile:%d", mMimeType.get(), mAudioChannels, mAudioRate, mAudioProfile); format->setString("mime", mMimeType.get()); format->setInt32("channel-count", mAudioChannels); format->setInt32("sample-rate", mAudioRate); format->setInt32("aac-profile", mAudioProfile); status_t err = mDecoder->configure(format, nullptr, nullptr, 0); if (err != OK || !mDecoder->Prepare()) { return false; } if (mMimeType.EqualsLiteral("audio/mp4a-latm")) { rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, android::MediaCodec::BUFFER_FLAG_CODECCONFIG, CODECCONFIG_TIMEOUT_US); } if (rv == OK) { return true; } else { GADM_LOG("Failed to input codec specific data!"); return false; } }
android::sp<MediaCodecProxy> GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback) { if (mLooper != nullptr) { return nullptr; } // Create ALooper mLooper = new ALooper; mLooper->setName("GonkAudioDecoderManager"); mLooper->start(); mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, false, nullptr); if (!mDecoder.get()) { return nullptr; } sp<AMessage> format = new AMessage; // Fixed values GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate); format->setString("mime", "audio/mp4a-latm"); format->setInt32("channel-count", mAudioChannels); format->setInt32("sample-rate", mAudioRate); format->setInt32("aac-profile", mAudioProfile); format->setInt32("is-adts", true); status_t err = mDecoder->configure(format, nullptr, nullptr, 0); if (err != OK || !mDecoder->Prepare()) { return nullptr; } status_t rv = mDecoder->Input(mUserData.Elements(), mUserData.Length(), 0, android::MediaCodec::BUFFER_FLAG_CODECCONFIG); if (rv == OK) { return mDecoder; } else { GADM_LOG("Failed to input codec specific data!"); return nullptr; } }
bool GonkAudioDecoderManager::PerformFormatSpecificProcess(MediaRawData* aSample) { if (aSample && mUseAdts) { int8_t frequency_index = mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate); bool rv = mp4_demuxer::Adts::ConvertSample(mAudioChannels, frequency_index, mAudioProfile, aSample); if (!rv) { GADM_LOG("Failed to apply ADTS header"); return false; } } return true; }
nsresult GonkAudioDecoderManager::Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutData) { aOutData = nullptr; status_t err; err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US); switch (err) { case OK: { nsRefPtr<AudioData> data; nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data)); if (rv == NS_ERROR_NOT_AVAILABLE) { // Decoder outputs an empty video buffer, try again return NS_ERROR_NOT_AVAILABLE; } else if (rv != NS_OK || data == nullptr) { return NS_ERROR_UNEXPECTED; } aOutData = data; return NS_OK; } case android::INFO_FORMAT_CHANGED: { // If the format changed, update our cached info. GADM_LOG("Decoder format changed"); return Output(aStreamOffset, aOutData); } case android::INFO_OUTPUT_BUFFERS_CHANGED: { GADM_LOG("Info Output Buffers Changed"); if (mDecoder->UpdateOutputBuffers()) { return Output(aStreamOffset, aOutData); } return NS_ERROR_FAILURE; } case -EAGAIN: { return NS_ERROR_NOT_AVAILABLE; } case android::ERROR_END_OF_STREAM: { GADM_LOG("Got EOS frame!"); nsRefPtr<AudioData> data; nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data)); if (rv == NS_ERROR_NOT_AVAILABLE) { // For EOS, no need to do any thing. return NS_ERROR_ABORT; } else if (rv != NS_OK || data == nullptr) { GADM_LOG("Failed to create audio data!"); return NS_ERROR_UNEXPECTED; } aOutData = data; return NS_ERROR_ABORT; } case -ETIMEDOUT: { GADM_LOG("Timeout. can try again next time"); return NS_ERROR_UNEXPECTED; } default: { GADM_LOG("Decoder failed, err=%d", err); return NS_ERROR_UNEXPECTED; } } return NS_OK; }
nsresult GonkAudioDecoderManager::Output(int64_t aStreamOffset, RefPtr<MediaData>& aOutData) { aOutData = nullptr; if (mAudioQueue.GetSize() > 0) { aOutData = mAudioQueue.PopFront(); return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK; } status_t err; MediaBuffer* audioBuffer = nullptr; err = mDecoder->Output(&audioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US); AutoReleaseMediaBuffer a(audioBuffer, mDecoder.get()); switch (err) { case OK: { nsresult rv = CreateAudioData(audioBuffer, aStreamOffset); NS_ENSURE_SUCCESS(rv, rv); break; } case android::INFO_FORMAT_CHANGED: { // If the format changed, update our cached info. GADM_LOG("Decoder format changed"); sp<AMessage> audioCodecFormat; if (mDecoder->getOutputFormat(&audioCodecFormat) != OK || audioCodecFormat == nullptr) { return NS_ERROR_UNEXPECTED; } int32_t codec_channel_count = 0; int32_t codec_sample_rate = 0; if (!audioCodecFormat->findInt32("channel-count", &codec_channel_count) || !audioCodecFormat->findInt32("sample-rate", &codec_sample_rate)) { return NS_ERROR_UNEXPECTED; } // Update AudioInfo mAudioChannels = codec_channel_count; mAudioRate = codec_sample_rate; return Output(aStreamOffset, aOutData); } case android::INFO_OUTPUT_BUFFERS_CHANGED: { GADM_LOG("Info Output Buffers Changed"); if (mDecoder->UpdateOutputBuffers()) { return Output(aStreamOffset, aOutData); } return NS_ERROR_FAILURE; } case -EAGAIN: { return NS_ERROR_NOT_AVAILABLE; } case android::ERROR_END_OF_STREAM: { GADM_LOG("Got EOS frame!"); nsresult rv = CreateAudioData(audioBuffer, aStreamOffset); NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT); MOZ_ASSERT(mAudioQueue.GetSize() > 0); mAudioQueue.Finish(); break; } case -ETIMEDOUT: { GADM_LOG("Timeout. can try again next time"); return NS_ERROR_UNEXPECTED; } default: { GADM_LOG("Decoder failed, err=%d", err); return NS_ERROR_UNEXPECTED; } } if (mAudioQueue.GetSize() > 0) { aOutData = mAudioQueue.PopFront(); // Return NS_ERROR_ABORT at the last sample. return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK; } return NS_ERROR_NOT_AVAILABLE; }