Ticket #520: PerianWithTrueHD.txt

File PerianWithTrueHD.txt, 9.4 KB (added by Timac2, 4 years ago)

TrueHD support in Perian diff

Line 
1Note: the format enums match the fourcc's used by VLC.
2
3Samples at <http://samples.mplayerhq.hu/A-codecs/TrueHD/>
4
5// svn diff --diff-cmd diff -x -uwbBE /Perian-1.2.1
6
7Index: /Perian-1.2.1/ff_private.c
8===================================================================
9--- /Perian-1.2.1/ff_private.c  (revision 1297)
10+++ /Perian-1.2.1/ff_private.c  (working copy)
11@@ -416,6 +416,12 @@
12                case CODEC_ID_NELLYMOSER:
13                        asbd->mFormatID = kAudioFormatNellymoser;
14                        break;
15+               case CODEC_ID_MLP:
16+                       asbd->mFormatID = kAudioFormatMLP;
17+                       break;
18+               case CODEC_ID_TRUEHD:
19+                       asbd->mFormatID = kAudioFormatTrueHD;
20+                       break;
21                default:
22                        break;
23        }
24Index: /Perian-1.2.1/MatroskaImportPrivate.cpp
25===================================================================
26--- /Perian-1.2.1/MatroskaImportPrivate.cpp     (revision 1297)
27+++ /Perian-1.2.1/MatroskaImportPrivate.cpp     (working copy)
28@@ -468,6 +468,9 @@
29                return invalidTrack;
30        }
31               
32+       mkvTrack.movieTimeScale = GetMovieTimeScale(theMovie);
33+       mkvTrack.mediaTimeScale = mkvTrack.movieTimeScale;
34+               
35        mkvTrack.theTrack = NewMovieTrack(theMovie, width, height, kNoVolume);
36        if (mkvTrack.theTrack == NULL)
37                return GetMoviesError();
38@@ -516,11 +519,14 @@
39        Handle cookieH = NULL;
40        Ptr cookie = NULL;
41       
42+       mkvTrack.movieTimeScale = GetMovieTimeScale(theMovie);
43+       mkvTrack.mediaTimeScale = lround((double) GetChild<KaxAudioSamplingFreq>(GetChild<KaxTrackAudio>(kaxTrack)));
44+       
45        mkvTrack.theTrack = NewMovieTrack(theMovie, 0, 0, kFullVolume);
46        if (mkvTrack.theTrack == NULL)
47                return GetMoviesError();
48       
49-       mkvTrack.theMedia = NewTrackMedia(mkvTrack.theTrack, 'soun', GetMovieTimeScale(theMovie), dataRef, dataRefType);
50+       mkvTrack.theMedia = NewTrackMedia(mkvTrack.theTrack, 'soun', mkvTrack.mediaTimeScale, dataRef, dataRefType);
51        if (mkvTrack.theMedia == NULL) {
52                DisposeMovieTrack(mkvTrack.theTrack);
53                return GetMoviesError();
54@@ -568,7 +574,7 @@
55       
56        mkvTrack.desc = (SampleDescriptionHandle) sndDesc;
57       
58-       err = QTSampleTableCreateMutable(NULL, GetMovieTimeScale(theMovie), NULL, &mkvTrack.sampleTable);
59+       err = QTSampleTableCreateMutable(NULL, mkvTrack.mediaTimeScale, NULL, &mkvTrack.sampleTable);
60        if (err) return err;
61       
62        err = QTSampleTableAddSampleDescription(mkvTrack.sampleTable, mkvTrack.desc, 0, &mkvTrack.qtSampleDesc);
63@@ -985,6 +991,11 @@
64        defaultDuration = 0;
65        usesLacing = true;
66        currentFrame = 0;
67+       
68+       movieTimeScale = 1000;
69+       mediaTimeScale = 1000;
70+       sampleTimeMovie = 0;
71+       sampleTimeMedia = 0;
72 }
73 
74 MatroskaTrack::MatroskaTrack(const MatroskaTrack &copy)
75@@ -1028,6 +1039,11 @@
76        defaultDuration = copy.defaultDuration;
77        usesLacing = copy.usesLacing;
78        currentFrame = copy.currentFrame;
79+       
80+       movieTimeScale = copy.movieTimeScale;
81+       mediaTimeScale = copy.mediaTimeScale;
82+       sampleTimeMovie = copy.sampleTimeMovie;
83+       sampleTimeMedia = copy.sampleTimeMedia;
84 }
85 
86 MatroskaTrack::~MatroskaTrack()
87@@ -1184,15 +1200,25 @@
88                        frame.duration = end - start;
89                } else return;
90        } else if (sampleTable) {
91+               SInt64 nextTimeMedia = (sampleTimeMovie + frame.duration) * (SInt64) mediaTimeScale / (SInt64) movieTimeScale;
92+               SInt64 frameDurationMedia = nextTimeMedia - sampleTimeMedia;
93+               SInt64 displayOffsetMedia = displayOffset * (SInt64) mediaTimeScale / (SInt64) movieTimeScale;
94+               
95+               if (frameDurationMedia <= 0)
96+                       frameDurationMedia = 1;
97+               
98                SInt64 sampleNum;
99               
100-               err = QTSampleTableAddSampleReferences(sampleTable, frame.offset, frame.size, frame.duration,
101-                                                                                  displayOffset, 1, frame.flags, qtSampleDesc, &sampleNum);
102+               err = QTSampleTableAddSampleReferences(sampleTable, frame.offset, frame.size, frameDurationMedia,
103+                                                                                  displayOffsetMedia, 1, frame.flags, qtSampleDesc, &sampleNum);
104                if (err) {
105                        Codecprintf(NULL, "MKV: error adding sample reference to table %d\n", err);
106                        return;
107                }
108               
109+               sampleTimeMovie += frame.duration;
110+               sampleTimeMedia += frameDurationMedia;
111+               
112                if (firstSample == -1)
113                        firstSample = sampleNum;
114                numSamples++;
115@@ -1239,6 +1265,15 @@
116                // nothing to add
117                return;
118       
119+       SInt64 maxLoadedTimeMedia = maxLoadedTime;
120+       SInt64 durationToAddMedia = durationToAdd;
121+       
122+       if (sampleTable)
123+       {
124+               maxLoadedTimeMedia = GetMediaDuration(theMedia);
125+               durationToAddMedia = sampleTimeMedia - maxLoadedTimeMedia;
126+       }
127+       
128        if (sampleTable) {
129                if (firstSample == -1)
130                        return;         // nothing to add
131@@ -1253,7 +1288,7 @@
132                }
133        }
134       
135-       err = InsertMediaIntoTrack(theTrack, -1, maxLoadedTime, durationToAdd, fixed1);
136+       err = InsertMediaIntoTrack(theTrack, -1, maxLoadedTimeMedia, durationToAddMedia, fixed1);
137        if (err)
138                Codecprintf(NULL, "MKV: error inserting media into track %d\n", err);
139       
140Index: /Perian-1.2.1/codecList.m4
141===================================================================
142--- /Perian-1.2.1/codecList.m4  (revision 1297)
143+++ /Perian-1.2.1/codecList.m4  (working copy)
144@@ -60,3 +60,5 @@
145 Codec(kTrueAudioCodecResourceID, CODEC_ID_TTA, "True Audio", "An AudioCodec that decodes True Audio into linear PCM", kAudioFormatTTA)
146 Codec(kDTSCodecResourceID, CODEC_ID_DTS, "DTS Coherent Acoustics", "An AudioCodec that decodes DCA Audio into linear PCM", kAudioFormatDTS)
147 Codec(kNellymoserCodecResourceID, CODEC_ID_NELLYMOSER, "Nellymoser ASAO", "An AudioCodec that decodes Nellymoser ASAO into linear PCM", kAudioFormatNellymoser)
148\ No newline at end of file
149+Codec(kMLPCodecResourceID, CODEC_ID_MLP, "MLP", "An AudioCodec that decodes MLP into linear PCM", kAudioFormatMLP)
150+Codec(kTrueHDCodecResourceID, CODEC_ID_TRUEHD, "TrueHD", "An AudioCodec that decodes TrueHD into linear PCM", kAudioFormatTrueHD)
151Index: /Perian-1.2.1/MatroskaCodecIDs.cpp
152===================================================================
153--- /Perian-1.2.1/MatroskaCodecIDs.cpp  (revision 1297)
154+++ /Perian-1.2.1/MatroskaCodecIDs.cpp  (working copy)
155@@ -847,6 +847,9 @@
156        { kAudioFormatRealLossless, "A_REAL/RALF" },
157        { kAudioFormatRealAtrac3, "A_REAL/ATRC" },
158       
159+       { kAudioFormatMLP, "A_MLP" },
160+       { kAudioFormatTrueHD, "A_TRUEHD" },
161+       
162 #if 0
163        { kBMPCodecType, "S_IMAGE/BMP" },
164 
165Index: /Perian-1.2.1/ff_MovieImport.c
166===================================================================
167--- /Perian-1.2.1/ff_MovieImport.c      (revision 1297)
168+++ /Perian-1.2.1/ff_MovieImport.c      (working copy)
169@@ -150,6 +150,10 @@
170                REGISTER_DECODER(dca);
171                REGISTER_DECODER(nellymoser);
172               
173+               REGISTER_DECODER(mlp);
174+               REGISTER_DECODER(truehd);
175+               REGISTER_PARSER(mlp);
176+               
177                REGISTER_DECODER(dvdsub);
178                REGISTER_DECODER(tscc);
179                REGISTER_DECODER(vp6a);
180Index: /Perian-1.2.1/MatroskaImport.h
181===================================================================
182--- /Perian-1.2.1/MatroskaImport.h      (revision 1297)
183+++ /Perian-1.2.1/MatroskaImport.h      (working copy)
184@@ -121,6 +121,15 @@
185        // for pts -> dts conversion (and laced tracks can't have non-keyframes anyways)
186        bool                                    usesLacing;
187       
188+       // The duration of MLP/TrueHD frames is less than 1 millisecond which is less than what the
189+       // default MKV timescale can accurately represent. The audio media timescale is therefore set to
190+       // the sample rate rather than the default MKV timescale.
191+       
192+       TimeScale                               movieTimeScale;
193+       TimeScale                               mediaTimeScale;
194+       TimeValue64                             sampleTimeMovie;
195+       TimeValue64                             sampleTimeMedia;
196+
197 private:
198        // adds an individual frame from a block group into the sample table if it exists,
199        // the media otherwise, and into the track if the track is a subtitle track.
200Index: /Perian-1.2.1/CodecIDs.h
201===================================================================
202--- /Perian-1.2.1/CodecIDs.h    (revision 1297)
203+++ /Perian-1.2.1/CodecIDs.h    (working copy)
204@@ -96,6 +96,9 @@
205        kAudioFormatRealAtrac3                  = 'ATRC',
206        kAudioFormatNellymoser                                  = 'NELL',
207       
208+       kAudioFormatMLP                                                 = 'mlp ',
209+       kAudioFormatTrueHD                                              = 'trhd',
210+       
211        kSubFormatUTF8                          = 'SRT ',
212        kSubFormatSSA                           = 'SSA ',
213        kSubFormatASS                           = 'ASS ',
214Index: /Perian-1.2.1/FFissionCodec/FFissionDecoder.cpp
215===================================================================
216--- /Perian-1.2.1/FFissionCodec/FFissionDecoder.cpp     (revision 1297)
217+++ /Perian-1.2.1/FFissionCodec/FFissionDecoder.cpp     (working copy)
218@@ -53,6 +53,8 @@
219        { kAudioFormatDTS, CODEC_ID_DTS },
220        { kAudioFormatNellymoser, CODEC_ID_NELLYMOSER },
221        { kAudioFormatTTA, CODEC_ID_TTA},
222+       { kAudioFormatMLP, CODEC_ID_MLP },
223+       { kAudioFormatTrueHD, CODEC_ID_TRUEHD },
224        { 0, CODEC_ID_NONE }
225 };
226 
227@@ -125,7 +127,7 @@
228        else
229                dtsPassthrough = 0;
230       
231-       int initialMap[6] = {0, 1, 2, 3, 4, 5};
232+       int initialMap[8] = {0, 1, 2, 3, 4, 5, 6, 7};
233        memcpy(fullChannelMap, initialMap, sizeof(initialMap));
234       
235        avcodec_get_context_defaults2(avContext, CODEC_TYPE_AUDIO);
236@@ -641,6 +643,17 @@
237                        pkt.data = packet;
238                        pkt.size = packetSize;
239                        len = avcodec_decode_audio3(avContext, (int16_t *)outputBuffer, &outBufUsed, &pkt);
240+                       if (len >= 0 && outBufUsed > 0 && avContext->sample_fmt == SAMPLE_FMT_S32)
241+                       {
242+                               // codec returned int32_t instead of int16_t
243+                               
244+                               int32_t *src = (int32_t *) outputBuffer;
245+                               int16_t *dst = (int16_t *) outputBuffer;
246+                               int numSamples = outBufUsed / 4;
247+                               for (int i = 0; i < numSamples; i++)
248+                                       *dst++ = *src++ >> 16;
249+                               outBufUsed /= 2;
250+                       }
251                }
252               
253                if (len < 0) {
254Index: /Perian-1.2.1/FFissionCodec/FFissionDecoder.h
255===================================================================
256--- /Perian-1.2.1/FFissionCodec/FFissionDecoder.h       (revision 1297)
257+++ /Perian-1.2.1/FFissionCodec/FFissionDecoder.h       (working copy)
258@@ -61,7 +61,7 @@
259        int outBufSize;
260        int outBufUsed;
261        bool dtsPassthrough;
262-       int fullChannelMap[6];
263+       int fullChannelMap[8];
264        AVCodecParserContext *parser;
265 };
266