gecko-dev/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp

179 lines
4.2 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mp4_demuxer/mp4_demuxer.h"
#include "GonkMediaDataDecoder.h"
#include "VideoUtils.h"
#include "nsTArray.h"
#include "MediaCodecProxy.h"
#include "prlog.h"
#include <android/log.h>
#define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder(blake)", __VA_ARGS__)
#ifdef PR_LOGGING
PRLogModuleInfo* GetDemuxerLog();
#define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__))
#else
#define LOG(...)
#endif
using namespace android;
namespace mozilla {
GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
MediaTaskQueue* aTaskQueue,
MediaDataDecoderCallback* aCallback)
: mTaskQueue(aTaskQueue)
, mCallback(aCallback)
, mManager(aManager)
, mSignaledEOS(false)
, mDrainComplete(false)
{
MOZ_COUNT_CTOR(GonkMediaDataDecoder);
}
GonkMediaDataDecoder::~GonkMediaDataDecoder()
{
MOZ_COUNT_DTOR(GonkMediaDataDecoder);
}
nsresult
GonkMediaDataDecoder::Init()
{
mDecoder = mManager->Init(mCallback);
mDrainComplete = false;
return mDecoder.get() ? NS_OK : NS_ERROR_UNEXPECTED;
}
nsresult
GonkMediaDataDecoder::Shutdown()
{
mDecoder->stop();
mDecoder = nullptr;
return NS_OK;
}
// Inserts data into the decoder's pipeline.
nsresult
GonkMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
{
mTaskQueue->Dispatch(
NS_NewRunnableMethodWithArg<nsAutoPtr<mp4_demuxer::MP4Sample>>(
this,
&GonkMediaDataDecoder::ProcessDecode,
nsAutoPtr<mp4_demuxer::MP4Sample>(aSample)));
return NS_OK;
}
void
GonkMediaDataDecoder::ProcessDecode(mp4_demuxer::MP4Sample* aSample)
{
nsresult rv = mManager->Input(aSample);
if (rv != NS_OK) {
NS_WARNING("GonkAudioDecoder failed to input data");
GMDD_LOG("Failed to input data err: %d",rv);
mCallback->Error();
return;
}
if (aSample) {
mLastStreamOffset = aSample->byte_offset;
}
ProcessOutput();
}
void
GonkMediaDataDecoder::ProcessOutput()
{
nsRefPtr<MediaData> output;
nsresult rv;
while (true && !mDrainComplete) {
rv = mManager->Output(mLastStreamOffset, output);
if (rv == NS_OK) {
mCallback->Output(output);
continue;
} else if (rv == NS_ERROR_NOT_AVAILABLE && mSignaledEOS) {
// Try to get more frames before getting EOS frame
continue;
}
else {
break;
}
}
if (rv == NS_ERROR_NOT_AVAILABLE) {
mCallback->InputExhausted();
return;
}
if (rv != NS_OK) {
NS_WARNING("GonkMediaDataDecoder failed to output data");
GMDD_LOG("Failed to output data");
// GonkDecoderManangers report NS_ERROR_ABORT when EOS is reached.
if (rv == NS_ERROR_ABORT) {
if (output) {
mCallback->Output(output);
}
mCallback->DrainComplete();
mSignaledEOS = false;
mDrainComplete = true;
return;
}
mCallback->Error();
}
}
nsresult
GonkMediaDataDecoder::Flush()
{
// Flush the input task queue. This cancels all pending Decode() calls.
// Note this blocks until the task queue finishes its current job, if
// it's executing at all. Note the MP4Reader ignores all output while
// flushing.
mTaskQueue->Flush();
return mManager->Flush();
}
void
GonkMediaDataDecoder::ProcessDrain()
{
// Notify decoder input EOS by sending a null data.
ProcessDecode(nullptr);
mSignaledEOS = true;
ProcessOutput();
}
nsresult
GonkMediaDataDecoder::Drain()
{
mTaskQueue->Dispatch(NS_NewRunnableMethod(this, &GonkMediaDataDecoder::ProcessDrain));
return NS_OK;
}
bool
GonkMediaDataDecoder::IsWaitingMediaResources() {
return mDecoder->IsWaitingResources();
}
bool
GonkMediaDataDecoder::IsDormantNeeded() {
return mDecoder.get() ? true : false;
}
void
GonkMediaDataDecoder::AllocateMediaResources()
{
mManager->AllocateMediaResources();
}
void
GonkMediaDataDecoder::ReleaseMediaResources() {
mManager->ReleaseMediaResources();
}
} // namespace mozilla