source: branches/perian-1.1/MatroskaImport.h @ 887

Revision 887, 10.6 KB checked in by astrange, 6 years ago (diff)

Merge trunk to 1.1 branch.

Line 
1/*
2 *  MatroskaImport.h
3 *
4 *    MatroskaImport.h - QuickTime importer interface for opening a Matroska file.
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#ifndef __MATROSKAIMPORT_H__
26#define __MATROSKAIMPORT_H__
27
28#include <vector>
29#include <list>
30#include <map>
31
32#include <QuickTime/QuickTime.h>
33#include "DataHandlerCallback.h"
34#include "SubImport.h"
35
36#include <ebml/EbmlStream.h>
37#include <matroska/KaxSeekHead.h>
38#include <matroska/KaxInfo.h>
39#include <matroska/KaxTracks.h>
40#include <matroska/KaxChapters.h>
41#include <matroska/KaxBlock.h>
42#include <matroska/KaxAttachments.h>
43#include <matroska/KaxContentEncoding.h>
44
45using namespace libmatroska;
46using namespace std;
47
48// the maximum number of frames that have to be decoded between decoding
49// any single frame and displaying it, used to cap the maximum size of the
50// pts -> dts reorder buffer. Set to 4 since that's what it is in FFmpeg;
51// shouldn't be more than 2 with current codecs
52#define MAX_DECODE_DELAY 4
53
54struct MatroskaFrame {
55        TimeValue64             dts;                    // decode timestamp
56        TimeValue64             pts;                    // presentation/display timestamp
57        TimeValue               duration;
58        SInt64                  offset;
59        SInt64                  size;
60        short                   flags;
61        DataBuffer         *buffer;
62};
63
64struct MatroskaSeekContext {
65        EbmlElement             *el_l1;
66        uint64_t                position;
67};
68
69// a list of level one elements and their offsets in the segment
70class MatroskaSeek {
71public:
72        EbmlId GetID() const { return EbmlId(ebmlID, idLength); }
73        bool operator<(const MatroskaSeek &rhs) const { return segmentPos < rhs.segmentPos; }
74        bool operator>(const MatroskaSeek &rhs) const { return segmentPos > rhs.segmentPos; }
75       
76        MatroskaSeekContext GetSeekContext(uint64_t segmentOffset = 0) const {
77                return (MatroskaSeekContext){ NULL, segmentPos + segmentOffset };
78        }
79       
80        uint32_t                ebmlID;
81        uint8_t                 idLength;
82        uint64_t                segmentPos;
83};
84
85class MatroskaTrack {
86public:
87        MatroskaTrack();
88       
89        // retains the sampleTable if it exists, allocates a new SampleDescriptionHandle
90        // and copies it if necessary
91        MatroskaTrack(const MatroskaTrack &copy);
92       
93        // releases the sampleTable and sample description
94        ~MatroskaTrack();
95       
96        // adds the all the frames in the block group to the sample table if it exists,
97        // the media otherwise. If this track type is subtitle, also inserts it into the track.
98        void AddBlock(KaxInternalBlock &block, uint32 duration, short flags);
99       
100        // this adds all the samples added through AddBlock() to the track that aren't already
101        // added, e.g. from a previous call to AddSamplesToTrack()
102        void AddSamplesToTrack();
103       
104        void FinishTrack();
105       
106        UInt16                                  number;
107        UInt8                                   type, is_vobsub;
108        Track                                   theTrack;
109        Media                                   theMedia;
110        SampleDescriptionHandle desc;
111        QTMutableSampleTableRef sampleTable;
112        QTSampleDescriptionID   qtSampleDesc;
113        SInt64                                  timecodeScale;
114        TimeValue64                             maxLoadedTime;
115        CXXSubSerializer                *subtitleSerializer;
116        Handle                                  subDataRefHandler;
117        uint8                                   isEnabled;
118        uint32_t                                defaultDuration;
119       
120        // laced tracks can have multiple frames per block, it's easier to ignore them
121        // for pts -> dts conversion (and laced tracks can't have non-keyframes anyways)
122        bool                                    usesLacing;
123       
124private:
125        // adds an individual frame from a block group into the sample table if it exists,
126        // the media otherwise, and into the track if the track is a subtitle track.
127        void AddFrame(MatroskaFrame &frame);
128       
129        // parses the first frame of a supported data format to determine codec parameters,
130        // which can be more correct than the codec headers.
131        void ParseFirstBlock(KaxInternalBlock &block);
132       
133        // Since the duration in Matroska files is generally rather unreliable, rely only on
134        // the difference in timestamps between two frames. Thus, AddBlock() buffers frames
135        // from one block group until the next block group is found to set the duration of the
136        // previous ones to be the difference in timestamps.
137        vector<MatroskaFrame>   lastFrames;
138        int currentFrame;                                               // the frame we're currently determining the dts for
139       
140        // insert pts values, sort, then smallest value is current dts if size > decode delay
141        list<TimeValue64>               ptsReorder;
142       
143        // We calculate the duration at a given dts, and have to save it until we find a
144        // frame with the same pts. This makes it such that we are actually calculating
145        // the duration between display timestamps instead of decode timestamps.
146        map<TimeValue64, TimeValue> durationForPTS;
147       
148        bool                                    seenFirstBlock;
149       
150        // When using a sample table, these store the range of samples that are in the
151        // sample table but not yet added to the media.
152        SInt64                                  firstSample;            // -1 means it's not set
153        SInt64                                  numSamples;
154       
155        // the amount of the media that needs to be added to the track
156        TimeValue64                             durationToAdd;
157       
158        // We don't want to add regions with frames that are displayed after the region.
159        // Assume that when the sum of the display offsets is zero, this is true, and
160        // update durationToAdd by adding durationSinceZeroSum.
161        int                                             displayOffsetSum;
162        SInt64                                  durationSinceZeroSum;
163};
164
165
166class MatroskaImport {
167public:
168        // public interface functions, simply called from the C equivalents defined
169        // by ComponentDispatchHelper.c and implemented in MatroskaImport.cpp
170       
171        // MatroskaImportOpen()
172        MatroskaImport(ComponentInstance self);
173       
174        // MatrosakImportClose()
175        ~MatroskaImport();
176       
177        // MatroskaImportDataRef()
178        ComponentResult ImportDataRef(Handle dataRef, OSType dataRefType, Movie theMovie,
179                                                                  Track targetTrack, Track *usedTrack,
180                                                                  TimeValue atTime, TimeValue *durationAdded,
181                                                                  long inFlags, long *outFlags);
182       
183        // MatroskaImportValidateDataRef()
184        ComponentResult ValidateDataRef(Handle dataRef, OSType dataRefType, UInt8 *valid);
185       
186        // MatroskaImportIdle()
187        ComponentResult Idle(long inFlags, long *outFlags);
188       
189        // MatroskaImportSetIdleManager()
190        ComponentResult SetIdleManager(IdleManager im);
191       
192        // MatroskaImportGetMaxLoadedTime()
193        ComponentResult GetMaxLoadedTime(TimeValue *time);
194       
195        // MatroskaImportGetLoadState()
196        ComponentResult GetLoadState(long *importerLoadState);
197       
198        // we need to get our component instance to get our mime type resource
199        ComponentInstance Component() { return self; }
200       
201private:
202        // open the ioHandler and EBML stream, and read the EBML head to verify it's a matroska file
203        // returns true if it's a valid file and false otherwise
204        bool OpenFile();
205       
206        // create all the tracks and their sample descriptions as described by the file header
207        // also create chapters if any. Leaves el_l1 pointing to the first cluster, unread.
208        ComponentResult SetupMovie();
209       
210        // This finds the next level 1 element and both replaces the el_l1 variable with it and
211        // returns it. Does not read the data.
212        EbmlElement *NextLevel1Element();
213       
214        // reads the current level 1 element and calls Read<...> based on its ebml id
215        ComponentResult ProcessLevel1Element();
216       
217        // sets up timescale & file name metadata
218        ComponentResult ReadSegmentInfo(KaxInfo &segmentInfo);
219       
220        // sets up all the movie tracks and media
221        ComponentResult ReadTracks(KaxTracks &trackEntries);
222       
223        // Creates a chapter track, but doesn't actually add the chapter reference to the other
224        // enabled tracks in case some weird file has this element before the Tracks element
225        ComponentResult ReadChapters(KaxChapters &chapterEntries);
226       
227        // Activates any attached fonts, ignores other attachment types for now
228        ComponentResult ReadAttachments(KaxAttachments &attachments);
229       
230        // Fills the levelOneElements vector with the positions of the elements in the seek head
231        ComponentResult ReadMetaSeek(KaxSeekHead &seekHead);
232       
233        // Adds a sample description extension if the content is compressed
234        // should only be the case for VobSub data.
235        ComponentResult ReadContentEncodings(KaxContentEncodings &encodings, MatroskaTrack &mkvTrack);
236       
237        // These three are called from ReadTracks to set up a track of the specific type,
238        // modifying the MatroskaTrack structure to reflect the newly create track.
239        // They return an error if the track couldn't be created or noErr on success.
240        ComponentResult AddVideoTrack(KaxTrackEntry &kaxTrack, MatroskaTrack &mkvTrack);
241        ComponentResult AddAudioTrack(KaxTrackEntry &kaxTrack, MatroskaTrack &mkvTrack);
242        ComponentResult AddSubtitleTrack(KaxTrackEntry &kaxTrack, MatroskaTrack &mkvTrack);
243       
244        // this is called recursively to add only the leaves on the chapter tree to
245        // chapter track, since QT doesn't support chapter nesting.
246        void AddChapterAtom(KaxChapterAtom *atom, Track chapterTrack);
247       
248        // assumes cluster has been read already, and cycles through the contained blocks and
249        // adds the frames to the media/sample table, and to the track if addToTrack is true
250        void ImportCluster(KaxCluster &cluster, bool addToTrack);
251       
252        // we need to save a bit of context when seeking if we're going to seek back
253        // This function saves el_l1 and the current file position to the returned context
254        // and clears el_l1 to null in preparation for a seek.
255        MatroskaSeekContext SaveContext();
256       
257        // This function restores el_l1 to what is saved in the context, deleting the current
258        // value if not null, and seeks to the specified point in the file.
259        void SetContext(MatroskaSeekContext context);
260       
261        // After the fonts are loaded, preplay the subtitle tracks to avoid an annoying pause
262        // from unavoidably lazy rendering APIs looking them up for the first time.
263        void PrerollSubtitleTracks();
264               
265        ComponentInstance               self;
266        Handle                                  dataRef;
267        OSType                                  dataRefType;
268       
269        Movie                                   theMovie;
270        Track                                   chapterTrack;
271        Track                                   baseTrack;              // fake track created to set the duration
272                                                                                        // of a movie while idle importing
273        SInt64                                  timecodeScale;
274        TimeValue64                             movieDuration;  // in the timescale of timecodeScale
275       
276        IdleManager                             idleManager;
277        long                                    loadState;
278        TimeValue                               lastIdleTime;   // the playback time of the movie when last idled
279        int                                             idlesSinceLastAdd;      // number of idles since the last time
280                                                                                                // samples were added to the tracks
281       
282        DataHandlerCallback             *ioHandler;
283        EbmlStream                              *aStream;
284       
285        EbmlElement                             *el_l0;
286        EbmlElement                             *el_l1;
287        uint64_t                                segmentOffset;
288       
289        vector<MatroskaTrack>   tracks;
290        vector<MatroskaSeek>    levelOneElements;
291       
292        bool                                    seenInfo;
293        bool                                    seenTracks;
294        bool                                    seenChapters;
295};
296
297#endif
Note: See TracBrowser for help on using the repository browser.