Skip to content
Permalink
Browse files

Proxy components for audio/video to handle the stripped header case i…

…n mkv.

git-svn-id: https://svn.perian.org/trunk@1334 621663c8-3916-0410-8f58-edc14a8543d5
  • Loading branch information...
gbooker
gbooker committed Aug 16, 2010
1 parent ce7322c commit 4a1dff5a260d39b170c2d2edb073036a65c368fe
@@ -54,7 +54,8 @@ enum {
// contains a single byte equal to the ContentCompAlgo element in matroska
kMKVCompressionExtension = 'MCmp',
// contains the compression settings equal to ContentCompSettings in matroska
kAC3CompressionSettingsExtension = 'CpSt',
kCompressionSettingsExtension = 'CpSt',
kCompressionAlgorithm = 'CpAl',
};


@@ -104,6 +105,12 @@ enum {
kSubFormatASS = 'ASS ',
kSubFormatUSF = 'USF ',
kSubFormatVobSub = 'SPU ',

kCompressedAVC1 = 'CAVC',
kCompressedMP4V = 'CMP4',
kCompressedAC3 = 'CAC3',
kCompressedMP3 = 'CMP3',
kCompressedDTS = 'CDTS',
};

#ifndef REZ
@@ -0,0 +1,241 @@
/*
* CompressAudioCodec.cpp
* Created by Graham Booker on 8/14/10.
* This file is part of Perian.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "CompressAudioCodec.h"
#include "ACCodecDispatch.h"
#include "CodecIDs.h"
#include "CompressCodecUtils.h"

static const OSType kAllInputFormats[] =
{
kCompressedAC3,
kCompressedMP3,
kCompressedDTS,
0,
};

CompressAudioCodec::CompressAudioCodec(UInt32 inInputBufferByteSize) : FFissionCodec(0)
{
UInt32 kIntPCMOutFormatFlag = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;

for (int i = 0; kAllInputFormats[i] != CODEC_ID_NONE; i++) {
CAStreamBasicDescription theInputFormat(kAudioStreamAnyRate, kAllInputFormats[i], 0, 1, 0, 0, 0, 0);
AddInputFormat(theInputFormat);
}

// libavcodec outputs 16-bit native-endian integer pcm, so why do conversions ourselves?
CAStreamBasicDescription theOutputFormat(kAudioStreamAnyRate, kAudioFormatLinearPCM, 0, 1, 0, 0, 16, kIntPCMOutFormatFlag);
AddOutputFormat(theOutputFormat);
strippedHeader = NULL;
strippedHeaderSize = 0;
innerCookie = NULL;
innerCookieSize = 0;
actualUnit = NULL;
}

CompressAudioCodec::~CompressAudioCodec()
{
if(strippedHeader)
delete[] strippedHeader;
if(innerCookie)
delete[] innerCookie;
if(actualUnit)
CloseComponent(actualUnit);
}

UInt32 CompressAudioCodec::ParseCookieAtom(const uint8_t* inAtom, UInt32 inAtomMaxSize)
{
if(inAtomMaxSize < 8)
//Invalid; atom must be at least 8 bytes.
return inAtomMaxSize;
const UInt32 *atomElements = reinterpret_cast<const UInt32 *>(inAtom);
UInt32 atomSize = EndianU32_BtoN(atomElements[0]);
UInt32 atomType = EndianU32_BtoN(atomElements[1]);

if(atomSize > inAtomMaxSize)
return inAtomMaxSize;

switch (atomType) {
case 'CpSt': {
//Stripped header
UInt32 headerSize = atomSize - 8;
if(headerSize == 0)
break;
strippedHeaderSize = headerSize;
strippedHeader = new Byte[headerSize];
memcpy(strippedHeader, inAtom+8, headerSize);
}
break;
case 'CpCk': {
//Real cookie
UInt32 cookieSize = atomSize - 8;
if(cookieSize == 0)
break;
innerCookieSize = cookieSize;
innerCookie = new Byte[cookieSize];
memcpy(innerCookie, inAtom+8, cookieSize);
}
break;
default:
break;
}

return atomSize;
}

void CompressAudioCodec::ParseCookie(const uint8_t* inMagicCookie, UInt32 inMagicCookieByteSize)
{
UInt32 offset = 0;
while(offset < inMagicCookieByteSize) {
offset += ParseCookieAtom(inMagicCookie + offset, inMagicCookieByteSize - offset);
}
}

void CompressAudioCodec::Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize)
{
if(inInputFormat)
{
OSType original = originalStreamFourCC(inInputFormat->mFormatID);
if(original == 0)
CODEC_THROW(kAudioCodecUnsupportedFormatError);

ComponentDescription desc;
memset(&desc, 0, sizeof(ComponentDescription));
desc.componentType = kAudioDecoderComponentType;
desc.componentSubType = original;
Component component = FindNextComponent(NULL, &desc);
if(component != NULL)
{
ComponentResult err = OpenAComponent(component, &actualUnit);
AudioStreamBasicDescription input = *inInputFormat;
input.mFormatID = original;
err = AudioCodecInitialize(actualUnit, &input, inOutputFormat, innerCookie, innerCookieSize);
}
}
if(inMagicCookie)
SetMagicCookie(inMagicCookie, inMagicCookieByteSize);
FFissionCodec::Initialize(inInputFormat, inOutputFormat, inMagicCookie, inMagicCookieByteSize);
}

void CompressAudioCodec::Uninitialize()
{
FFissionCodec::Uninitialize();
if(actualUnit)
AudioCodecUninitialize(actualUnit);
}

void CompressAudioCodec::Reset()
{
if(actualUnit)
AudioCodecReset(actualUnit);
}

void CompressAudioCodec::GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData)
{
if(actualUnit)
{
AudioCodecGetProperty(actualUnit, inPropertyID, &ioPropertyDataSize, outPropertyData);
switch (inPropertyID) {
case kAudioCodecPropertyCurrentInputFormat:
case kAudioCodecPropertySupportedInputFormats:
case kAudioCodecInputFormatsForOutputFormat:
{
int formatCount = ioPropertyDataSize / sizeof(AudioStreamBasicDescription);
AudioStreamBasicDescription *formats = reinterpret_cast<AudioStreamBasicDescription*>(outPropertyData);
for(int i=0; i<formatCount; i++)
{
formats[i].mFormatID = mInputFormat.mFormatID;
}
}
break;
default:
break;
}
}
else
FFissionCodec::GetProperty(inPropertyID, ioPropertyDataSize, outPropertyData);
}

void CompressAudioCodec::SetMagicCookie(const void* inMagicCookieData, UInt32 inMagicCookieDataByteSize)
{
ParseCookie(static_cast<const uint8_t *> (inMagicCookieData), inMagicCookieDataByteSize);
FFissionCodec::SetMagicCookie(inMagicCookieData, inMagicCookieDataByteSize);
if(actualUnit)
{
OSType original = originalStreamFourCC(mInputFormat.mFormatID);
AudioStreamBasicDescription input = mInputFormat;
input.mFormatID = original;
AudioStreamBasicDescription output = mOutputFormat;
AudioCodecInitialize(actualUnit, &input, &output, innerCookie, innerCookieSize);
}
}

void CompressAudioCodec::SetCurrentInputFormat(const AudioStreamBasicDescription& inInputFormat)
{
FFissionCodec::SetCurrentInputFormat(inInputFormat);
}

void CompressAudioCodec::SetCurrentOutputFormat(const AudioStreamBasicDescription& inOutputFormat)
{
FFissionCodec::SetCurrentOutputFormat(inOutputFormat);
}

void CompressAudioCodec::AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription)
{
if(inPacketDescription && ioNumberPackets && actualUnit)
{
UInt32 totalSize = 0;
for(int i=0; i<ioNumberPackets; i++)
totalSize += inPacketDescription[i].mDataByteSize;

Byte *newInputData = new Byte[totalSize + strippedHeaderSize*ioNumberPackets];
AudioStreamPacketDescription *newPackets = new AudioStreamPacketDescription[ioNumberPackets];
UInt32 offset = 0;
for(int i=0; i<ioNumberPackets; i++)
{
memcpy(newInputData + offset, strippedHeader, strippedHeaderSize);
UInt32 packetSize = inPacketDescription[i].mDataByteSize;
memcpy(newInputData + offset + strippedHeaderSize, static_cast<const Byte *>(inInputData) + inPacketDescription[i].mStartOffset, packetSize);
newPackets[i].mDataByteSize = packetSize + strippedHeaderSize;
newPackets[i].mStartOffset = offset;
newPackets[i].mVariableFramesInPacket = inPacketDescription[i].mVariableFramesInPacket;
offset += packetSize + strippedHeaderSize;
}
AudioCodecAppendInputData(actualUnit, newInputData, &offset, &ioNumberPackets, newPackets);
AudioStreamPacketDescription lastPacket = inPacketDescription[ioNumberPackets-1];
ioInputDataByteSize = lastPacket.mStartOffset + lastPacket.mDataByteSize;
delete[] newInputData;
delete[] newPackets;
}
}

UInt32 CompressAudioCodec::ProduceOutputPackets(void* outOutputData, UInt32& ioOutputDataByteSize, UInt32& ioNumberPackets, AudioStreamPacketDescription* outPacketDescription)
{
UInt32 status = noErr;
if(actualUnit)
AudioCodecProduceOutputPackets(actualUnit, outOutputData, &ioOutputDataByteSize, &ioNumberPackets, outPacketDescription, &status);
return status;
}

extern "C"
ComponentResult CompressAudioDecoderEntry(ComponentParameters* inParameters, CompressAudioCodec* inThis)
{
return ACCodecDispatch(inParameters, inThis);
}
@@ -0,0 +1,58 @@
/*
* CompressAudioCodec.h
* Created by Graham Booker on 8/14/10.
* This file is part of Perian.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef __COMPRESSAUDIOCODEC_H__
#define __COMPRESSAUDIOCODEC_H__

#include "FFissionCodec.h"

class CompressAudioCodec : public FFissionCodec
{
public:
CompressAudioCodec(UInt32 inInputBufferByteSize = 76800);
virtual ~CompressAudioCodec();

virtual void Initialize(const AudioStreamBasicDescription* inInputFormat, const AudioStreamBasicDescription* inOutputFormat, const void* inMagicCookie, UInt32 inMagicCookieByteSize);
virtual void Uninitialize();
virtual void Reset();

virtual void GetProperty(AudioCodecPropertyID inPropertyID, UInt32& ioPropertyDataSize, void* outPropertyData);
virtual void SetMagicCookie(const void* inMagicCookieData, UInt32 inMagicCookieDataByteSize);

virtual void SetCurrentInputFormat(const AudioStreamBasicDescription& inInputFormat);
virtual void SetCurrentOutputFormat(const AudioStreamBasicDescription& inOutputFormat);

virtual void AppendInputData(const void* inInputData, UInt32& ioInputDataByteSize, UInt32& ioNumberPackets, const AudioStreamPacketDescription* inPacketDescription);
virtual UInt32 ProduceOutputPackets(void* outOutputData, UInt32& ioOutputDataByteSize, UInt32& ioNumberPackets, AudioStreamPacketDescription* outPacketDescription);

private:
UInt32 ParseCookieAtom(const uint8_t* inAtom, UInt32 inAtomMaxSize);
void ParseCookie(const uint8_t* inMagicCookie, UInt32 inMagicCookieByteSize);

UInt32 strippedHeaderSize;
Byte *strippedHeader;

UInt32 innerCookieSize;
Byte *innerCookie;

AudioCodec actualUnit;
};

#endif
@@ -0,0 +1,63 @@
/*
* CompressCodecUtils.c
* Created by Graham Booker on 8/14/10.
* This file is part of Perian.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "CompressCodecUtils.h"
#include <QuickTime/QuickTime.h>
#include "CodecIDs.h"

OSType compressStreamFourCC(OSType original)
{
switch (original) {
case kH264CodecType:
return kCompressedAVC1;
case kMPEG4VisualCodecType:
return kCompressedMP4V;
case kAudioFormatMPEGLayer3:
return kCompressedMP3;
case kAudioFormatAC3:
return kCompressedAC3;
case kAudioFormatDTS:
return kCompressedDTS;
default:
break;
}

return 0;
}

OSType originalStreamFourCC(OSType compress)
{
switch (compress) {
case kCompressedAVC1:
return kH264CodecType;
case kCompressedMP4V:
return kMPEG4VisualCodecType;
case kCompressedMP3:
return kAudioFormatMPEGLayer3;
case kCompressedAC3:
return kAudioFormatAC3;
case kCompressedDTS:
return kAudioFormatDTS;
default:
break;
}

return 0;
}
Oops, something went wrong.

0 comments on commit 4a1dff5

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.