--- a/content/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/content/media/fmp4/android/AndroidDecoderModule.cpp
@@ -64,17 +64,17 @@ public:
return InitDecoder(mSurfaceTexture->JavaSurface());
}
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE {
mp4_demuxer::AnnexB::ConvertSample(aSample, mConfig.annex_b);
return MediaCodecDataDecoder::Input(aSample);
}
- virtual nsresult PostOutput(BufferInfo* aInfo, Microseconds aDuration) MOZ_OVERRIDE {
+ virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
VideoInfo videoInfo;
videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
bool isSync = false;
if (MediaCodec::getBUFFER_FLAG_SYNC_FRAME() & aInfo->getFlags()) {
isSync = true;
}
@@ -101,44 +101,39 @@ public:
protected:
layers::ImageContainer* mImageContainer;
const mp4_demuxer::VideoDecoderConfig& mConfig;
nsRefPtr<AndroidSurfaceTexture> mSurfaceTexture;
};
class AudioDataDecoder : public MediaCodecDataDecoder {
public:
- AudioDataDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
- MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
- : MediaCodecDataDecoder(MediaData::Type::AUDIO_SAMPLES, aConfig.mime_type, aFormat, aCallback)
- , mConfig(aConfig)
+ AudioDataDecoder(const char* aMimeType, MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
+ : MediaCodecDataDecoder(MediaData::Type::AUDIO_SAMPLES, aMimeType, aFormat, aCallback)
{
- MOZ_ASSERT(mConfig.bits_per_sample == 16, "We only support 16-bit audio");
}
- nsresult Output(BufferInfo* aInfo, void* aBuffer, Microseconds aDuration) {
+ nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
// The output on Android is always 16-bit signed
- uint32_t numChannels = mConfig.channel_count;
+ uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_STRING("channel-count"));
+ uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"));
uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
mCallback->Output(new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
aDuration,
numFrames,
audio,
numChannels,
- mConfig.samples_per_second));
+ sampleRate));
return NS_OK;
}
-
-protected:
- const mp4_demuxer::AudioDecoderConfig& mConfig;
};
bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
JNIEnv* env = GetJNIForThread();
MediaCodec* decoder = CreateDecoder(env, aMimeType);
bool supports = (decoder != nullptr);
delete decoder;
@@ -176,16 +171,17 @@ AndroidDecoderModule::CreateH264Decoder(
return decoder.forget();
}
already_AddRefed<MediaDataDecoder>
AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
MediaTaskQueue* aAudioTaskQueue,
MediaDataDecoderCallback* aCallback)
{
+ MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!");
nsAutoString mimeType;
mimeType.AssignASCII(aConfig.mime_type);
jobject jFormat = MediaFormat::CreateAudioFormat(mimeType,
aConfig.samples_per_second,
aConfig.channel_count);
@@ -211,17 +207,17 @@ AndroidDecoderModule::CreateAudioDecoder
env->DeleteLocalRef(buffer);
}
if (mimeType.EqualsLiteral("audio/mp4a-latm")) {
format->SetInteger(NS_LITERAL_STRING("is-adts"), 1);
}
nsRefPtr<MediaDataDecoder> decoder =
- new AudioDataDecoder(aConfig, format, aCallback);
+ new AudioDataDecoder(aConfig.mime_type, format, aCallback);
return decoder.forget();
}
nsresult AndroidDecoderModule::Shutdown()
{
@@ -297,16 +293,18 @@ nsresult MediaCodecDataDecoder::InitDeco
void MediaCodecDataDecoder::DecoderLoop()
{
bool outputDone = false;
JNIEnv* env = GetJNIForThread();
mp4_demuxer::MP4Sample* sample = nullptr;
+ nsAutoPtr<MediaFormat> outputFormat;
+
for (;;) {
{
MonitorAutoLock lock(mMonitor);
while (!mStopping && !mDraining && mQueue.empty()) {
if (mQueue.empty()) {
// We could be waiting here forever if we don't signal that we need more input
mCallback->InputExhausted();
}
@@ -365,17 +363,17 @@ void MediaCodecDataDecoder::DecoderLoop(
int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT);
if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) {
// We might want to call mCallback->InputExhausted() here, but there seems to be
// some possible bad interactions here with the threading
} else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) {
ResetOutputBuffers();
} else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) {
- // Don't care, we use SurfaceTexture for video
+ outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread());
} else if (outputStatus < 0) {
printf_stderr("unknown error from decoder! %d\n", outputStatus);
mCallback->Error();
} else {
// We have a valid buffer index >= 0 here
if (bufferInfo.getFlags() & MediaCodec::getBUFFER_FLAG_END_OF_STREAM()) {
outputDone = true;
}
@@ -387,23 +385,23 @@ void MediaCodecDataDecoder::DecoderLoop(
duration = mDurations.front();
mDurations.pop();
}
jobject buffer = env->GetObjectArrayElement(mOutputBuffers, outputStatus);
if (buffer) {
// The buffer will be null on Android L if we are decoding to a Surface
void* directBuffer = env->GetDirectBufferAddress(buffer);
- Output(&bufferInfo, directBuffer, duration);
+ Output(&bufferInfo, directBuffer, outputFormat, duration);
}
// The Surface will be updated at this point (for video)
mDecoder->ReleaseOutputBuffer(outputStatus, true);
- PostOutput(&bufferInfo, duration);
+ PostOutput(&bufferInfo, outputFormat, duration);
if (buffer) {
env->DeleteLocalRef(buffer);
}
}
}
}
--- a/content/media/fmp4/android/AndroidDecoderModule.h
+++ b/content/media/fmp4/android/AndroidDecoderModule.h
@@ -89,18 +89,18 @@ protected:
bool mDraining;
bool mStopping;
SampleQueue mQueue;
std::queue<Microseconds> mDurations;
virtual nsresult InitDecoder(jobject aSurface = nullptr);
- virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, Microseconds aDuration) { return NS_OK; }
- virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, Microseconds aDuration) { return NS_OK; }
+ virtual nsresult Output(mozilla::widget::android::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+ virtual nsresult PostOutput(mozilla::widget::android::BufferInfo* aInfo, mozilla::widget::android::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
void ResetInputBuffers();
void ResetOutputBuffers();
void DecoderLoop();
virtual void ClearQueue();
};