source: trunk/MatroskaCodecIDs.cpp @ 1379

Revision 1379, 24.3 KB checked in by astrange, 3 years ago (diff)

Enable fftheora video decoder to fix Theora-in-MKV

This is easier than figuring out why XiphQT doesn't work.

As a side effect, delete half of MatroskaCodecIDs.cpp.
FFusionCodecPreflight() is approaching needing refactoring too.

Fixes #499

Line 
1/*
2 *  MatroskaCodecIDs.h
3 *
4 *    MatroskaCodecIDs.h - Codec description extension conversion utilities between MKV and QT
5 *
6 *
7 *  Copyright (c) 2006  David Conrad
8 *
9 *  This program is free software; you can redistribute it and/or
10 *  modify it under the terms of the GNU Lesser General Public
11 *  License as published by the Free Software Foundation;
12 *  version 2.1 of the License.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 *  Lesser General Public License for more details.
18 *
19 *  You should have received a copy of the GNU Lesser General Public
20 *  License along with this program; if not, write to the Free Software
21 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 */
24
25#include <QuickTime/QuickTime.h>
26#include <AudioToolbox/AudioToolbox.h>
27#include <matroska/KaxTracks.h>
28#include <matroska/KaxTrackEntryData.h>
29#include <matroska/KaxTrackAudio.h>
30#include <matroska/KaxContentEncoding.h>
31#include <string>
32#include "CommonUtils.h"
33#include "Codecprintf.h"
34#include "MatroskaCodecIDs.h"
35
36using namespace std;
37using namespace libmatroska;
38
39/*
40 * Used for codecs whose extradata can be copied straight into a sample description extension.
41 * fallbackType is for formats with lots of invalid files (avi-style H264 or MPEG4) which we have
42 * an extradataless-equivalent fourcc for.
43 */
44ComponentResult DescExt_Default(KaxTrackEntry *tr_entry, SampleDescriptionHandle desc, DescExtDirection dir, OSType extType, OSType fallbackType)
45{
46        if (!tr_entry || !desc) return paramErr;
47        ImageDescriptionHandle imgDesc = (ImageDescriptionHandle) desc;
48       
49        if (dir == kToSampleDescription) {
50                KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
51                if (codecPrivate == NULL) {
52                        if (fallbackType) {
53                                (*desc)->dataFormat = fallbackType;
54                                return noErr;
55                        } else {
56                                Codecprintf(NULL, "Missing extradata in track\n");
57                                return invalidAtomErr;
58                        }
59                }
60               
61                Handle imgDescExt;
62                PtrToHand(codecPrivate->GetBuffer(), &imgDescExt, codecPrivate->GetSize());
63               
64                AddImageDescriptionExtension(imgDesc, imgDescExt, extType);
65               
66                DisposeHandle(imgDescExt);
67        }
68        return noErr;
69}
70
71// xiph-qt expects these this sound extension to have been created from first 3 packets
72// which are stored in CodecPrivate in Matroska
73ComponentResult DescExt_XiphVorbis(KaxTrackEntry *tr_entry, Handle *cookie, DescExtDirection dir)
74{
75        if (!tr_entry || !cookie) return paramErr;
76       
77        if (dir == kToSampleDescription) {
78                Handle sndDescExt;
79                unsigned char *privateBuf;
80                size_t privateSize;
81                uint8_t numPackets;
82                int offset = 1, i;
83                UInt32 uid = 0;
84               
85                KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
86                if (codecPrivate == NULL)
87                        return invalidAtomErr;
88               
89                KaxTrackUID *trackUID = FindChild<KaxTrackUID>(*tr_entry);
90                if (trackUID != NULL)
91                        uid = uint32(*trackUID);
92               
93                privateSize = codecPrivate->GetSize();
94                privateBuf = (unsigned char *) codecPrivate->GetBuffer();
95                numPackets = privateBuf[0] + 1;
96               
97                if (numPackets != 3) {
98                        return invalidAtomErr;
99                }
100               
101                int packetSizes[3] = {0};
102               
103                // get the sizes of the packets
104                packetSizes[numPackets - 1] = privateSize - 1;
105                int packetNum = 0;
106                for (i = 1; packetNum < numPackets - 1; i++) {
107                        packetSizes[packetNum] += privateBuf[i];
108                        if (privateBuf[i] < 255) {
109                                packetSizes[numPackets - 1] -= packetSizes[packetNum];
110                                packetNum++;
111                        }
112                        offset++;
113                }
114                packetSizes[numPackets - 1] -= offset - 1;
115               
116                if (offset+packetSizes[0]+packetSizes[1]+packetSizes[2] > privateSize) {
117                        return invalidAtomErr;
118                }
119
120                // first packet
121                uint32_t serial_header_atoms[3+2] = { EndianU32_NtoB(3*4), 
122                        EndianU32_NtoB(kCookieTypeOggSerialNo), 
123                        EndianU32_NtoB(uid),
124                        EndianU32_NtoB(packetSizes[0] + 2*4), 
125                        EndianU32_NtoB(kCookieTypeVorbisHeader) };
126               
127                PtrToHand(serial_header_atoms, &sndDescExt, sizeof(serial_header_atoms));
128                PtrAndHand(&privateBuf[offset], sndDescExt, packetSizes[0]);
129               
130                // second packet
131                uint32_t atomhead2[2] = { EndianU32_NtoB(packetSizes[1] + sizeof(atomhead2)), 
132                        EndianU32_NtoB(kCookieTypeVorbisComments) };
133                PtrAndHand(atomhead2, sndDescExt, sizeof(atomhead2));
134                PtrAndHand(&privateBuf[offset + packetSizes[0]], sndDescExt, packetSizes[1]);
135               
136                // third packet
137                uint32_t atomhead3[2] = { EndianU32_NtoB(packetSizes[2] + sizeof(atomhead3)), 
138                        EndianU32_NtoB(kCookieTypeVorbisCodebooks) };
139                PtrAndHand(atomhead3, sndDescExt, sizeof(atomhead3));
140                PtrAndHand(&privateBuf[offset + packetSizes[1] + packetSizes[0]], sndDescExt, packetSizes[2]);
141
142                *cookie = sndDescExt;
143        }
144        return noErr;
145}
146
147// xiph-qt expects these this sound extension to have been created in this way
148// from the packets which are stored in the CodecPrivate element in Matroska
149ComponentResult DescExt_XiphFLAC(KaxTrackEntry *tr_entry, Handle *cookie, DescExtDirection dir)
150{
151        if (!tr_entry || !cookie) return paramErr;
152       
153        if (dir == kToSampleDescription) {
154                Handle sndDescExt;
155                UInt32 uid = 0;
156               
157                KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
158                if (codecPrivate == NULL)
159                        return invalidAtomErr;
160               
161                KaxTrackUID *trackUID = FindChild<KaxTrackUID>(*tr_entry);
162                if (trackUID != NULL)
163                        uid = uint32(*trackUID);
164               
165                size_t privateSize = codecPrivate->GetSize();
166                UInt8 *privateBuf = (unsigned char *) codecPrivate->GetBuffer(), *privateEnd = privateBuf + privateSize;
167               
168                unsigned long serialnoatom[3] = { EndianU32_NtoB(sizeof(serialnoatom)), 
169                        EndianU32_NtoB(kCookieTypeOggSerialNo), 
170                        EndianU32_NtoB(uid) };
171               
172                PtrToHand(serialnoatom, (Handle*)&sndDescExt, sizeof(serialnoatom));
173               
174                privateBuf += 4; // skip 'fLaC'
175               
176                while ((privateEnd - privateBuf) > 4) {
177                        uint32_t packetHeader = EndianU32_BtoN(*(uint32_t*)privateBuf);
178                        int lastPacket = packetHeader >> 31, blockType = (packetHeader >> 24) & 0x7F;
179                        uint32_t packetSize = (packetHeader & 0xFFFFFF) + 4;
180                        uint32_t xiphHeader[2] = {EndianU32_NtoB(packetSize + sizeof(xiphHeader)),
181                                EndianU32_NtoB(blockType ? kCookieTypeFLACMetadata : kCookieTypeFLACStreaminfo)};
182                                               
183                        if ((privateEnd - privateBuf) < packetSize)
184                                break;
185                       
186                        PtrAndHand(xiphHeader, sndDescExt, sizeof(xiphHeader));
187                        PtrAndHand(privateBuf, sndDescExt, packetSize);
188                       
189                        privateBuf += packetSize;
190                       
191                        if (lastPacket)
192                                break;
193                }
194               
195                *cookie = sndDescExt;   
196        }
197        return noErr;
198}
199
200// c.f. http://wiki.multimedia.cx/index.php?title=Understanding_AAC
201
202struct MatroskaQT_AACProfileName
203{
204        const char *name;
205        char profile;
206};
207
208static const MatroskaQT_AACProfileName kMatroskaAACProfiles[] = {
209        {"A_AAC/MPEG2/MAIN", 1},
210        {"A_AAC/MPEG2/LC", 2},
211        {"A_AAC/MPEG2/LC/SBR", 2},
212        {"A_AAC/MPEG2/SSR", 3},
213        {"A_AAC/MPEG4/MAIN", 1},
214        {"A_AAC/MPEG4/LC", 2},
215        {"A_AAC/MPEG4/LC/SBR", 2},
216        {"A_AAC/MPEG4/SSR", 3},
217        {"A_AAC/MPEG4/LTP", 4}
218};
219
220static const unsigned kAACFrequencyIndexes[] = {
221        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000,
222        11025, 8000, 7350
223};
224
225static bool ShouldWriteSBRExt(unsigned output_freq_index)
226{
227        if (output_freq_index < 3)
228                return ShouldPlayHighFreqSBR();
229       
230        return true;
231}
232
233static int FindAACFreqIndex(double freq)
234{
235        unsigned ifreq = freq;
236       
237        for (int i = 0; i < sizeof(kAACFrequencyIndexes)/sizeof(unsigned); i++) {
238                if (kAACFrequencyIndexes[i] == ifreq) return i;
239        }
240       
241        return 15;
242}
243
244static void RecreateAACVOS(KaxTrackEntry *tr_entry, uint8_t *vosBuf, size_t *vosLen)
245{
246        KaxCodecID *tr_codec = FindChild<KaxCodecID>(*tr_entry);
247        KaxTrackAudio & audioTrack = GetChild<KaxTrackAudio>(*tr_entry);
248        KaxAudioSamplingFreq & sampleFreq = GetChild<KaxAudioSamplingFreq>(audioTrack);
249        KaxAudioChannels & numChannels = GetChild<KaxAudioChannels>(audioTrack);
250        KaxAudioOutputSamplingFreq * outputFreq = FindChild<KaxAudioOutputSamplingFreq>(audioTrack);
251        unsigned channels = unsigned(numChannels);
252        unsigned profile = 2, freq_index = FindAACFreqIndex(sampleFreq);
253        uint8_t *vosStart = vosBuf;
254        string codecString(*tr_codec);
255
256        for (int i = 0; i < sizeof(kMatroskaAACProfiles)/sizeof(MatroskaQT_AACProfileName); i++) {
257                const MatroskaQT_AACProfileName *prof = &kMatroskaAACProfiles[i];
258                if (codecString == prof->name) {profile = prof->profile; break;}
259        }
260       
261        *vosBuf++ = (profile << 3) | (freq_index >> 1);
262        *vosBuf++ = (freq_index << 7) | (channels << 3);
263       
264        if (freq_index == 15)
265                Codecprintf(NULL, "unrecognized AAC frequency not supported\n");
266       
267        if (outputFreq) {
268                unsigned output_freq_index = FindAACFreqIndex(*outputFreq);
269                               
270                if (ShouldWriteSBRExt(output_freq_index)) {
271                        *vosBuf++ = 0x56;
272                        *vosBuf++ = 0xE5;
273                        *vosBuf++ = 0x80 | (output_freq_index << 3);
274                }
275        }
276       
277        *vosLen = vosBuf - vosStart;
278}
279
280// the esds atom creation is based off of the routines for it in ffmpeg's movenc.c
281static unsigned int descrLength(unsigned int len)
282{
283    int i;
284    for(i=1; len>>(7*i); i++);
285    return len + 1 + i;
286}
287
288static uint8_t* putDescr(uint8_t *buffer, int tag, unsigned int size)
289{
290    int i= descrLength(size) - size - 2;
291    *buffer++ = tag;
292    for(; i>0; i--)
293       *buffer++ = (size>>(7*i)) | 0x80;
294    *buffer++ = size & 0x7F;
295        return buffer;
296}
297
298// ESDS layout:
299//  + version             (4 bytes)
300//  + ES descriptor
301//   + Track ID            (2 bytes)
302//   + Flags               (1 byte)
303//   + DecoderConfig descriptor
304//    + Object Type         (1 byte)
305//    + Stream Type         (1 byte)
306//    + Buffersize DB       (3 bytes)
307//    + Max bitrate         (4 bytes)
308//    + VBR/Avg bitrate     (4 bytes)
309//    + DecoderSpecific info descriptor
310//     + codecPrivate        (codecPrivate->GetSize())
311//   + SL descriptor
312//    + dunno               (1 byte)
313
314uint8_t *CreateEsdsFromSetupData(uint8_t *codecPrivate, size_t vosLen, size_t *esdsLen, int trackID, bool audio, bool write_version)
315{
316        int decoderSpecificInfoLen = vosLen ? descrLength(vosLen) : 0;
317        int versionLen = write_version ? 4 : 0;
318       
319        *esdsLen = versionLen + descrLength(3 + descrLength(13 + decoderSpecificInfoLen) + descrLength(1));
320        uint8_t *esds = (uint8_t*)malloc(*esdsLen);
321        UInt8 *pos = (UInt8 *) esds;
322       
323        // esds atom version (only needed for ImageDescription extension)
324        if (write_version)
325                pos = write_int32(pos, 0);
326       
327        // ES Descriptor
328        pos = putDescr(pos, 0x03, 3 + descrLength(13 + decoderSpecificInfoLen) + descrLength(1));
329        pos = write_int16(pos, EndianS16_NtoB(trackID));
330        *pos++ = 0;             // no flags
331       
332        // DecoderConfig descriptor
333        pos = putDescr(pos, 0x04, 13 + decoderSpecificInfoLen);
334       
335        // Object type indication, see http://gpac.sourceforge.net/tutorial/mediatypes.htm
336        if (audio)
337                *pos++ = 0x40;          // aac
338        else
339                *pos++ = 0x20;          // mpeg4 part 2
340       
341        // streamtype
342        if (audio)
343                *pos++ = 0x15;
344        else
345                *pos++ = 0x11;
346       
347        // 3 bytes: buffersize DB (not sure how to get easily)
348        *pos++ = 0;
349        pos = write_int16(pos, 0);
350       
351        // max bitrate, not sure how to get easily
352        pos = write_int32(pos, 0);
353       
354        // vbr
355        pos = write_int32(pos, 0);
356       
357        if (vosLen) {
358                pos = putDescr(pos, 0x05, vosLen);
359                pos = write_data(pos, codecPrivate, vosLen);
360        }
361       
362        // SL descriptor
363        pos = putDescr(pos, 0x06, 1);
364        *pos++ = 0x02;
365       
366        return esds;
367}
368
369static Handle CreateEsdsExt(KaxTrackEntry *tr_entry, bool audio)
370{
371        KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
372        KaxTrackNumber *trackNum = FindChild<KaxTrackNumber>(*tr_entry);
373       
374        size_t vosLen = codecPrivate ? codecPrivate->GetSize() : 0;
375        int trackID = trackNum ? uint16(*trackNum) : 1;
376        uint8_t aacBuf[5] = {0};
377        uint8_t *vosBuf = codecPrivate ? codecPrivate->GetBuffer() : NULL;
378        size_t esdsLen;
379       
380        // vosLen > 2 means SBR; some of those must be rewritten to avoid QT bugs(?)
381        // FIXME: remove when QT works with them
382        if (audio && (!vosBuf || vosLen > 2)) {
383                RecreateAACVOS(tr_entry, aacBuf, &vosLen);
384                vosBuf = aacBuf;
385        } else if (!audio && !vosBuf)
386                return NULL;
387       
388        uint8_t *esds = CreateEsdsFromSetupData(vosBuf, vosLen, &esdsLen, trackID, audio, !audio);
389       
390        Handle esdsExt;
391        PtrToHand(esds, &esdsExt, esdsLen);
392        free(esds);
393       
394        return esdsExt;
395}
396
397ComponentResult DescExt_aac(KaxTrackEntry *tr_entry, Handle *cookie, DescExtDirection dir)
398{
399        if (!tr_entry || !cookie) return paramErr;
400       
401        if (dir == kToSampleDescription) {
402                *cookie = CreateEsdsExt(tr_entry, true);
403        }
404       
405        return noErr;
406}
407
408ComponentResult ASBDExt_LPCM(KaxTrackEntry *tr_entry, AudioStreamBasicDescription *asbd)
409{
410        if (!tr_entry || !asbd) return paramErr;
411       
412        KaxCodecID *tr_codec = FindChild<KaxCodecID>(*tr_entry);
413        if (!tr_codec) return paramErr;
414        string codecid(*tr_codec);
415        bool isFloat = codecid == MKV_A_PCM_FLOAT;
416       
417        asbd->mFormatFlags = CalculateLPCMFlags(asbd->mBitsPerChannel, asbd->mBitsPerChannel, isFloat, isFloat ? false : (codecid == MKV_A_PCM_BIG), false);
418        if (asbd->mBitsPerChannel == 8)
419                asbd->mFormatFlags &= ~kLinearPCMFormatFlagIsSignedInteger;
420       
421        return noErr;
422}
423
424ComponentResult ASBDExt_AAC(KaxTrackEntry *tr_entry, Handle cookie, AudioStreamBasicDescription *asbd, AudioChannelLayout *acl)
425{
426        if (!tr_entry || !asbd) return paramErr;
427        ByteCount cookieSize = GetHandleSize(cookie), aclSize = sizeof(*acl);
428        OSStatus err = noErr;
429
430        err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutFromESDS,
431                                                                 cookieSize,
432                                                                 *cookie,
433                                                                 &aclSize,
434                                                                 acl);
435        if (err != noErr) 
436                FourCCprintf("MatroskaQT: Error creating ACL from AAC esds ", err);
437       
438        return err;
439}
440
441
442
443ComponentResult MkvFinishSampleDescription(KaxTrackEntry *tr_entry, SampleDescriptionHandle desc, DescExtDirection dir)
444{
445        KaxCodecID & tr_codec = GetChild<KaxCodecID>(*tr_entry);
446       
447        string codecString(tr_codec);
448       
449        if (codecString == MKV_V_MS) {
450                // BITMAPINFOHEADER is stored in the private data, and some codecs (WMV)
451                // need it to decode
452                KaxCodecPrivate & codecPrivate = GetChild<KaxCodecPrivate>(*tr_entry);
453               
454                Handle imgDescExt;
455                PtrToHand(codecPrivate.GetBuffer(), &imgDescExt, codecPrivate.GetSize());
456               
457                AddImageDescriptionExtension((ImageDescriptionHandle) desc, imgDescExt, 'strf');
458               
459        } else if (codecString == MKV_V_QT) {
460                // This seems to work fine, but there's something it's missing to get the
461                // image description to match perfectly (last 2 bytes are different)
462                // Figure it out later...
463                KaxCodecPrivate & codecPrivate = GetChild<KaxCodecPrivate>(*tr_entry);
464                if (codecPrivate.GetSize() < sizeof(ImageDescription)) {
465                        Codecprintf(NULL, "MatroskaQT: QuickTime track %hu doesn't have needed stsd data\n", 
466                                                uint16(tr_entry->TrackNumber()));
467                        return -1;
468                }
469               
470                ImageDescriptionHandle imgDesc = (ImageDescriptionHandle) desc;
471                SetHandleSize((Handle) imgDesc, codecPrivate.GetSize());
472                memcpy(&(*imgDesc)->cType, codecPrivate.GetBuffer(), codecPrivate.GetSize());
473                // it's stored in big endian, so flip endian to native
474                // I think we have to do this, need to check on Intel without them
475                (*imgDesc)->idSize = codecPrivate.GetSize();
476                (*imgDesc)->cType = EndianU32_BtoN((*imgDesc)->cType);
477                (*imgDesc)->resvd1 = EndianS32_BtoN((*imgDesc)->resvd1);
478                (*imgDesc)->resvd2 = EndianS16_BtoN((*imgDesc)->resvd2);
479                (*imgDesc)->dataRefIndex = EndianS16_BtoN((*imgDesc)->dataRefIndex);
480                (*imgDesc)->version = EndianS16_BtoN((*imgDesc)->version);
481                (*imgDesc)->revisionLevel = EndianS16_BtoN((*imgDesc)->revisionLevel);
482                (*imgDesc)->vendor = EndianS32_BtoN((*imgDesc)->vendor);
483                (*imgDesc)->temporalQuality = EndianU32_BtoN((*imgDesc)->temporalQuality);
484                (*imgDesc)->spatialQuality = EndianU32_BtoN((*imgDesc)->spatialQuality);
485                (*imgDesc)->width = EndianS16_BtoN((*imgDesc)->width);
486                (*imgDesc)->height = EndianS16_BtoN((*imgDesc)->height);
487                (*imgDesc)->vRes = EndianS32_BtoN((*imgDesc)->vRes);
488                (*imgDesc)->hRes = EndianS32_BtoN((*imgDesc)->hRes);
489                (*imgDesc)->dataSize = EndianS32_BtoN((*imgDesc)->dataSize);
490                (*imgDesc)->frameCount = EndianS16_BtoN((*imgDesc)->frameCount);
491                (*imgDesc)->depth = EndianS16_BtoN((*imgDesc)->depth);
492                (*imgDesc)->clutID = EndianS16_BtoN((*imgDesc)->clutID);
493
494        } else {
495                OSType extType = 0, fallbackType = 0;
496                switch ((*desc)->dataFormat) {
497                        case kH264CodecType:
498                                extType = 'avcC';
499                                fallbackType = 'H264';
500                                break;
501
502                        case kSubFormatVobSub:
503                                // VobSub stores the .idx file in the codec private, pass it as an .IDX extension
504                                extType = kVobSubIdxExtension;
505                                break;
506                               
507                        case kVideoFormatReal5:
508                        case kVideoFormatRealG2:
509                        case kVideoFormatReal8:
510                        case kVideoFormatReal9:
511                                extType = kRealVideoExtension;
512                                break;
513                               
514                        case kMPEG4VisualCodecType:
515                                extType = 'esds';
516                                fallbackType = 'XVID';
517                                break;
518                               
519                        case kVideoFormatTheora:
520                        case kSubFormatSSA:
521                                extType = (*desc)->dataFormat;
522                }
523               
524                if (extType)
525                        return DescExt_Default(tr_entry, desc, dir, extType, fallbackType);
526        }
527        return noErr;
528}
529
530// some default channel layouts for 3 to 8 channels
531// vorbis, flac and aac should be correct unless extradata specifices something else for aac
532static const AudioChannelLayout vorbisChannelLayouts[6] = {
533        { kAudioChannelLayoutTag_UseChannelBitmap, kAudioChannelBit_Left | kAudioChannelBit_Right | kAudioChannelBit_CenterSurround },
534        { kAudioChannelLayoutTag_Quadraphonic },                // L R Ls Rs
535        { kAudioChannelLayoutTag_MPEG_5_0_C },                  // L C R Ls Rs
536        { kAudioChannelLayoutTag_MPEG_5_1_C },                  // L C R Ls Rs LFE
537};
538
539// these should be the default for the number of channels; esds can specify other mappings
540static const AudioChannelLayout aacChannelLayouts[6] = {
541        { kAudioChannelLayoutTag_MPEG_3_0_B },                  // C L R according to wiki.multimedia.cx
542        { kAudioChannelLayoutTag_AAC_4_0 },                             // C L R Cs
543        { kAudioChannelLayoutTag_AAC_5_0 },                             // C L R Ls Rs
544        { kAudioChannelLayoutTag_AAC_5_1 },                             // C L R Ls Rs Lfe
545        { kAudioChannelLayoutTag_AAC_6_1 },                             // C L R Ls Rs Cs Lfe
546        { kAudioChannelLayoutTag_AAC_7_1 },                             // C Lc Rc L R Ls Rs Lfe
547};
548
549static const AudioChannelLayout ac3ChannelLayouts[6] = {
550        { kAudioChannelLayoutTag_ITU_3_0 },                             // L R C
551        { kAudioChannelLayoutTag_ITU_3_1 },                             // L R C Cs
552        { kAudioChannelLayoutTag_ITU_3_2 },                             // L R C Ls Rs
553        { kAudioChannelLayoutTag_ITU_3_2_1 },                   // L R C LFE Ls Rs
554};
555
556static const AudioChannelLayout flacChannelLayouts[6] = {
557        { kAudioChannelLayoutTag_ITU_3_0 },                             // L R C
558        { kAudioChannelLayoutTag_Quadraphonic },                // L R Ls Rs
559        { kAudioChannelLayoutTag_ITU_3_2 },                             // L R C Ls Rs
560        { kAudioChannelLayoutTag_ITU_3_2_1 },                   // L R C LFE Ls Rs
561        { kAudioChannelLayoutTag_MPEG_6_1_A },                  // L R C LFE Ls Rs Cs
562        { kAudioChannelLayoutTag_MPEG_7_1_C },                  // L R C LFE Ls Rs Rls Rrs
563};
564
565// 5.1 is tested, the others are just guesses
566static const AudioChannelLayout dtsChannelLayouts[6] = {
567        { kAudioChannelLayoutTag_MPEG_3_0_B },                  // C L R
568        { kAudioChannelLayoutTag_MPEG_4_0_B },                  // C L R Cs
569        { kAudioChannelLayoutTag_MPEG_5_0_D },                  // C L R Ls Rs
570        { kAudioChannelLayoutTag_MPEG_5_1_D },                  // C L R Ls Rs Lfe
571};
572
573AudioChannelLayout GetDefaultChannelLayout(AudioStreamBasicDescription *asbd)
574{
575        AudioChannelLayout acl = {0};
576        int channelIndex = asbd->mChannelsPerFrame - 3;
577       
578        if (channelIndex >= 0 && channelIndex < 6) {
579                switch (asbd->mFormatID) {
580                        case kAudioFormatXiphVorbis:
581                                acl = vorbisChannelLayouts[channelIndex];
582                                break;
583                               
584                        case kAudioFormatXiphFLAC:
585                                acl = flacChannelLayouts[channelIndex];
586                                break;
587                               
588                        case kAudioFormatMPEG4AAC:
589                                // TODO: use extradata to make ACL
590                                acl = aacChannelLayouts[channelIndex];
591                                break;
592                               
593                        case kAudioFormatAC3:
594                        case kAudioFormatAC3MS:
595                                acl = ac3ChannelLayouts[channelIndex];
596                                break;
597                               
598                        case kAudioFormatDTS:
599                                acl = dtsChannelLayouts[channelIndex];
600                                break;
601                }
602        }
603       
604        return acl;
605}
606
607
608ComponentResult MkvFinishAudioDescription(KaxTrackEntry *tr_entry, Handle *cookie, AudioStreamBasicDescription *asbd, AudioChannelLayout *acl)
609{
610        KaxCodecID & tr_codec = GetChild<KaxCodecID>(*tr_entry);
611        KaxCodecPrivate & codecPrivate = GetChild<KaxCodecPrivate>(*tr_entry);
612        string codecString(tr_codec);
613       
614        if (codecString == MKV_A_MS) {
615                PtrToHand(codecPrivate.GetBuffer(), cookie, codecPrivate.GetSize());
616        }
617       
618        switch (asbd->mFormatID) {
619                case kAudioFormatXiphVorbis:
620                        DescExt_XiphVorbis(tr_entry, cookie, kToSampleDescription);
621                        break;
622                       
623                case kAudioFormatXiphFLAC:
624                        DescExt_XiphFLAC(tr_entry, cookie, kToSampleDescription);
625                        break;
626                       
627                case kAudioFormatMPEG4AAC:
628                case kMPEG4AudioFormat:
629                        DescExt_aac(tr_entry, cookie, kToSampleDescription);
630                        break;
631        }
632       
633        switch (asbd->mFormatID) {
634                case kAudioFormatMPEG4AAC:
635                        ASBDExt_AAC(tr_entry, *cookie, asbd, acl);
636                        break;
637                       
638                case kAudioFormatLinearPCM:
639                        ASBDExt_LPCM(tr_entry, asbd);
640                        break;
641        }
642        return noErr;
643}
644
645typedef struct {
646        OSType cType;
647        int twocc;
648} WavCodec;
649
650static const WavCodec kWavCodecIDs[] = {
651        { kAudioFormatMPEGLayer2, 0x50 },
652        { kAudioFormatMPEGLayer3, 0x55 },
653        { kAudioFormatAC3, 0x2000 },
654        { kAudioFormatDTS, 0x2001 },
655        { kAudioFormatMPEG4AAC, 0xff },
656        { kAudioFormatXiphFLAC, 0xf1ac },
657        { 0, 0 }
658};
659
660typedef struct {
661        OSType cType;
662        const char *mkvID;
663} MatroskaQT_Codec;
664
665// the first matching pair is used for conversion
666static const MatroskaQT_Codec kMatroskaCodecIDs[] = {
667        { kRawCodecType, "V_UNCOMPRESSED" },
668        { kMPEG4VisualCodecType, "V_MPEG4/ISO/ASP" },
669        { kMPEG4VisualCodecType, "V_MPEG4/ISO/SP" },
670        { kMPEG4VisualCodecType, "V_MPEG4/ISO/AP" },
671        { kH264CodecType, "V_MPEG4/ISO/AVC" },
672        { kVideoFormatMSMPEG4v3, "V_MPEG4/MS/V3" },
673        { kMPEG1VisualCodecType, "V_MPEG1" },
674        { kMPEG2VisualCodecType, "V_MPEG2" },
675        { kVideoFormatReal5, "V_REAL/RV10" },
676        { kVideoFormatRealG2, "V_REAL/RV20" },
677        { kVideoFormatReal8, "V_REAL/RV30" },
678        { kVideoFormatReal9, "V_REAL/RV40" },
679        { kVideoFormatTheora, "V_THEORA" },
680        { kVideoFormatSnow, "V_SNOW" },
681        { kVideoFormatVP8, "V_VP8" },
682       
683        { kAudioFormatMPEG4AAC, "A_AAC" },
684        { kAudioFormatMPEG4AAC, "A_AAC/MPEG4/LC" },
685        { kAudioFormatMPEG4AAC, "A_AAC/MPEG4/MAIN" },
686        { kAudioFormatMPEG4AAC, "A_AAC/MPEG4/LC/SBR" },
687        { kAudioFormatMPEG4AAC, "A_AAC/MPEG4/SSR" },
688        { kAudioFormatMPEG4AAC, "A_AAC/MPEG4/LTP" },
689        { kAudioFormatMPEG4AAC, "A_AAC/MPEG2/LC" },
690        { kAudioFormatMPEG4AAC, "A_AAC/MPEG2/MAIN" },
691        { kAudioFormatMPEG4AAC, "A_AAC/MPEG2/LC/SBR" },
692        { kAudioFormatMPEG4AAC, "A_AAC/MPEG2/SSR" },
693        { kAudioFormatMPEGLayer1, "A_MPEG/L1" },
694        { kAudioFormatMPEGLayer2, "A_MPEG/L2" },
695        { kAudioFormatMPEGLayer3, "A_MPEG/L3" },
696        { kAudioFormatAC3, "A_AC3" },
697        { kAudioFormatAC3MS, "A_AC3" },
698        // anything special for these two?
699        { kAudioFormatAC3, "A_AC3/BSID9" },
700        { kAudioFormatAC3, "A_AC3/BSID10" },
701        { kAudioFormatXiphVorbis, "A_VORBIS" },
702        { kAudioFormatXiphFLAC, "A_FLAC" },
703        { kAudioFormatLinearPCM, "A_PCM/INT/LIT" },
704        { kAudioFormatLinearPCM, "A_PCM/INT/BIG" },
705        { kAudioFormatLinearPCM, "A_PCM/FLOAT/IEEE" },
706        { kAudioFormatDTS, "A_DTS" },
707        { kAudioFormatTTA, "A_TTA1" },
708        { kAudioFormatWavepack, "A_WAVPACK4" },
709        { kAudioFormatReal1, "A_REAL/14_4" },
710        { kAudioFormatReal2, "A_REAL/28_8" },
711        { kAudioFormatRealCook, "A_REAL/COOK" },
712        { kAudioFormatRealSipro, "A_REAL/SIPR" },
713        { kAudioFormatRealLossless, "A_REAL/RALF" },
714        { kAudioFormatRealAtrac3, "A_REAL/ATRC" },
715       
716#if 0
717        { kBMPCodecType, "S_IMAGE/BMP" },
718
719        { kSubFormatUSF, "S_TEXT/USF" },
720#endif
721        { kSubFormatSSA, "S_TEXT/SSA" },
722    { kSubFormatSSA, "S_SSA" },
723        { kSubFormatASS, "S_TEXT/ASS" },
724        { kSubFormatASS, "S_ASS" },
725        { kSubFormatUTF8, "S_TEXT/UTF8" },
726        { kSubFormatUTF8, "S_TEXT/ASCII" },
727        { kSubFormatVobSub, "S_VOBSUB" },
728};
729
730
731FourCharCode MkvGetFourCC(KaxTrackEntry *tr_entry)
732{
733        KaxCodecID *tr_codec = FindChild<KaxCodecID>(*tr_entry);
734        if (tr_codec == NULL)
735                return 0;
736       
737        string codecString(*tr_codec);
738       
739        if (codecString == MKV_V_MS) {
740                // avi compatibility mode, 4cc is in private info
741                KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
742                if (codecPrivate == NULL)
743                        return 0;
744               
745                // offset to biCompression in BITMAPINFO
746                unsigned char *p = (unsigned char *) codecPrivate->GetBuffer() + 16;
747                return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
748               
749        } else if (codecString == MKV_A_MS) {
750                // acm compatibility mode, twocc is in private info
751                KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
752                if (codecPrivate == NULL)
753                        return 0;
754               
755                unsigned char *p = (unsigned char *) codecPrivate->GetBuffer();
756                int twocc = p[0] | (p[1] << 8);
757               
758                for (int i = 0; kWavCodecIDs[i].cType; i++) {
759                        if (kWavCodecIDs[i].twocc == twocc)
760                                return kWavCodecIDs[i].cType;
761                }
762                return 'ms\0\0' | twocc;
763               
764        } else if (codecString == MKV_V_QT) {
765                // QT compatibility mode, private info is the ImageDescription structure, big endian
766                KaxCodecPrivate *codecPrivate = FindChild<KaxCodecPrivate>(*tr_entry);
767                if (codecPrivate == NULL)
768                        return 0;
769               
770                // starts at the 4CC
771                unsigned char *p = (unsigned char *) codecPrivate->GetBuffer();
772                return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
773               
774        } else {
775                for (int i = 0; i < sizeof(kMatroskaCodecIDs) / sizeof(MatroskaQT_Codec); i++) {
776                        if (codecString == kMatroskaCodecIDs[i].mkvID)
777                                return kMatroskaCodecIDs[i].cType;
778                }
779        }
780        return 0;
781}
Note: See TracBrowser for help on using the repository browser.