Bug 1248861: P6. Ensure AT decoder channel layout is always in SMPTE order. r=rillian

MozReview-Commit-ID: 9XfzxdiQ3Zu

--HG--
extra : rebase_source : 25931bcbb54d399200e98ca3488ab3ec1810adcd
This commit is contained in:
Jean-Yves Avenard 2016-04-05 08:24:16 +10:00
parent 4b33cb8216
commit e113225273
2 changed files with 152 additions and 4 deletions

View File

@ -276,16 +276,25 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample)
duration.ToSeconds());
#endif
AlignedAudioBuffer data(outputData.Length());
if (!data) {
AudioSampleBuffer data(outputData.Elements(), outputData.Length());
if (!data.Data()) {
return NS_ERROR_OUT_OF_MEMORY;
}
PodCopy(data.get(), &outputData[0], outputData.Length());
if (mChannelLayout && !mAudioConverter) {
AudioConfig in(*mChannelLayout.get(), rate);
AudioConfig out(channels, rate);
mAudioConverter = MakeUnique<AudioConverter>(in, out);
}
if (mAudioConverter) {
MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
mAudioConverter->Process(data);
}
RefPtr<AudioData> audio = new AudioData(aSample->mOffset,
aSample->mTime,
duration.ToMicroseconds(),
numFrames,
Move(data),
data.Forget(),
channels,
rate);
mCallback->Output(audio);
@ -365,6 +374,136 @@ AppleATDecoder::GetInputAudioDescription(AudioStreamBasicDescription& aDesc,
return NS_OK;
}
AudioConfig::Channel
ConvertChannelLabel(AudioChannelLabel id)
{
switch (id) {
case kAudioChannelLabel_Mono:
return AudioConfig::CHANNEL_MONO;
case kAudioChannelLabel_Left:
return AudioConfig::CHANNEL_LEFT;
case kAudioChannelLabel_Right:
return AudioConfig::CHANNEL_RIGHT;
case kAudioChannelLabel_Center:
return AudioConfig::CHANNEL_CENTER;
case kAudioChannelLabel_LFEScreen:
return AudioConfig::CHANNEL_LFE;
case kAudioChannelLabel_LeftSurround:
return AudioConfig::CHANNEL_LS;
case kAudioChannelLabel_RightSurround:
return AudioConfig::CHANNEL_RS;
case kAudioChannelLabel_CenterSurround:
return AudioConfig::CHANNEL_RCENTER;
case kAudioChannelLabel_RearSurroundLeft:
return AudioConfig::CHANNEL_RLS;
case kAudioChannelLabel_RearSurroundRight:
return AudioConfig::CHANNEL_RRS;
default:
return AudioConfig::CHANNEL_INVALID;
}
}
// Will set mChannelLayout if a channel layout could properly be identified
// and is supported.
nsresult
AppleATDecoder::SetupChannelLayout()
{
// Determine the channel layout.
UInt32 propertySize;
UInt32 size;
OSStatus status =
AudioConverterGetPropertyInfo(mConverter,
kAudioConverterOutputChannelLayout,
&propertySize, NULL);
if (status || !propertySize) {
LOG("Couldn't get channel layout property (%s)", FourCC2Str(status));
return NS_ERROR_FAILURE;
}
auto data = MakeUnique<uint8_t[]>(propertySize);
size = propertySize;
status =
AudioConverterGetProperty(mConverter, kAudioConverterInputChannelLayout,
&size, data.get());
if (status || size != propertySize) {
LOG("Couldn't get channel layout property (%s)",
FourCC2Str(status));
return NS_ERROR_FAILURE;
}
AudioChannelLayout* layout =
reinterpret_cast<AudioChannelLayout*>(data.get());
AudioChannelLayoutTag tag = layout->mChannelLayoutTag;
// if tag is kAudioChannelLayoutTag_UseChannelDescriptions then the structure
// directly contains the the channel layout mapping.
// If tag is kAudioChannelLayoutTag_UseChannelBitmap then the layout will
// be defined via the bitmap and can be retrieved using
// kAudioFormatProperty_ChannelLayoutForBitmap property.
// Otherwise the tag itself describes the layout.
if (tag != kAudioChannelLayoutTag_UseChannelDescriptions) {
AudioFormatPropertyID property =
tag == kAudioChannelLayoutTag_UseChannelBitmap
? kAudioFormatProperty_ChannelLayoutForBitmap
: kAudioFormatProperty_ChannelLayoutForTag;
if (property == kAudioFormatProperty_ChannelLayoutForBitmap) {
status =
AudioFormatGetPropertyInfo(property,
sizeof(UInt32), &layout->mChannelBitmap,
&propertySize);
} else {
status =
AudioFormatGetPropertyInfo(property,
sizeof(AudioChannelLayoutTag), &tag,
&propertySize);
}
if (status || !propertySize) {
LOG("Couldn't get channel layout property info (%s:%s)",
FourCC2Str(property), FourCC2Str(status));
return NS_ERROR_FAILURE;
}
data = MakeUnique<uint8_t[]>(propertySize);
layout = reinterpret_cast<AudioChannelLayout*>(data.get());
size = propertySize;
if (property == kAudioFormatProperty_ChannelLayoutForBitmap) {
status = AudioFormatGetProperty(property,
sizeof(UInt32), &layout->mChannelBitmap,
&size, layout);
} else {
status = AudioFormatGetProperty(property,
sizeof(AudioChannelLayoutTag), &tag,
&size, layout);
}
if (status || size != propertySize) {
LOG("Couldn't get channel layout property (%s:%s)",
FourCC2Str(property), FourCC2Str(status));
return NS_ERROR_FAILURE;
}
// We have retrieved the channel layout from the tag or bitmap.
// We can now directly use the channel descriptions.
layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
}
if (layout->mNumberChannelDescriptions > MAX_AUDIO_CHANNELS ||
layout->mNumberChannelDescriptions != mOutputFormat.mChannelsPerFrame) {
LOG("Nonsensical channel layout or not matching the original channel number");
return NS_ERROR_FAILURE;
}
AudioConfig::Channel channels[MAX_AUDIO_CHANNELS];
for (uint32_t i = 0; i < layout->mNumberChannelDescriptions; i++) {
AudioChannelLabel id = layout->mChannelDescriptions[i].mChannelLabel;
AudioConfig::Channel channel = ConvertChannelLabel(id);
channels[i] = channel;
}
mChannelLayout =
MakeUnique<AudioConfig::ChannelLayout>(mOutputFormat.mChannelsPerFrame,
channels);
return NS_OK;
}
nsresult
AppleATDecoder::SetupDecoder(MediaRawData* aSample)
{
@ -419,6 +558,11 @@ AppleATDecoder::SetupDecoder(MediaRawData* aSample)
mConverter = nullptr;
return NS_ERROR_FAILURE;
}
if (NS_FAILED(SetupChannelLayout())) {
NS_WARNING("Couldn't retrieve channel layout, will use default layout");
}
return NS_OK;
}

View File

@ -12,6 +12,7 @@
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Vector.h"
#include "nsIThread.h"
#include "AudioConverter.h"
namespace mozilla {
@ -53,6 +54,8 @@ private:
UInt32 mFormatID;
AudioFileStreamID mStream;
nsTArray<RefPtr<MediaRawData>> mQueuedSamples;
UniquePtr<AudioConfig::ChannelLayout> mChannelLayout;
UniquePtr<AudioConverter> mAudioConverter;
void SubmitSample(MediaRawData* aSample);
nsresult DecodeSample(MediaRawData* aSample);
@ -62,6 +65,7 @@ private:
// Will return NS_ERROR_NOT_INITIALIZED if more data is required.
nsresult SetupDecoder(MediaRawData* aSample);
nsresult GetImplicitAACMagicCookie(const MediaRawData* aSample);
nsresult SetupChannelLayout();
};
} // namespace mozilla