зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
4b33cb8216
Коммит
e113225273
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче