Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 : #if !defined(OggCodecState_h_)
7 : #define OggCodecState_h_
8 :
9 : #include <ogg/ogg.h>
10 : // For MOZ_SAMPLE_TYPE_*
11 : #include "FlacFrameParser.h"
12 : #include "VideoUtils.h"
13 : #include <nsDeque.h>
14 : #include <nsTArray.h>
15 : #include <nsClassHashtable.h>
16 :
17 : #include <theora/theoradec.h>
18 : #ifdef MOZ_TREMOR
19 : #include <tremor/ivorbiscodec.h>
20 : #else
21 : #include <vorbis/codec.h>
22 : #endif
23 :
24 : // Uncomment the following to validate that we're predicting the number
25 : // of Vorbis samples in each packet correctly.
26 : #define VALIDATE_VORBIS_SAMPLE_CALCULATION
27 : #ifdef VALIDATE_VORBIS_SAMPLE_CALCULATION
28 : #include <map>
29 : #endif
30 :
31 : struct OpusMSDecoder;
32 :
33 : namespace mozilla {
34 :
35 : class OpusParser;
36 :
37 : struct OggPacketDeletePolicy
38 : {
39 0 : void operator()(ogg_packet* aPacket) const
40 : {
41 0 : delete [] aPacket->packet;
42 : delete aPacket;
43 0 : }
44 : };
45 :
46 : using OggPacketPtr = UniquePtr<ogg_packet, OggPacketDeletePolicy>;
47 :
48 : // Deallocates a packet, used in OggPacketQueue below.
49 0 : class OggPacketDeallocator : public nsDequeFunctor
50 : {
51 0 : virtual void* operator()(void* aPacket)
52 : {
53 0 : OggPacketDeletePolicy()(static_cast<ogg_packet*>(aPacket));
54 0 : return nullptr;
55 : }
56 : };
57 :
58 : // A queue of ogg_packets. When we read a page, we extract the page's packets
59 : // and buffer them in the owning stream's OggCodecState. This is because
60 : // if we're skipping up to the next keyframe in very large frame sized videos,
61 : // there may be several megabytes of data between keyframes, and the
62 : // ogg_stream_state would end up resizing its buffer every time we added a
63 : // new 4KB page to the bitstream, which kills performance on Windows. This
64 : // also gives us the option to timestamp packets rather than decoded
65 : // frames/samples, reducing the amount of frames/samples we must decode to
66 : // determine start-time at a particular offset, and gives us finer control
67 : // over memory usage.
68 : class OggPacketQueue : private nsDeque
69 : {
70 : public:
71 0 : OggPacketQueue() : nsDeque(new OggPacketDeallocator()) { }
72 0 : ~OggPacketQueue() { Erase(); }
73 0 : bool IsEmpty() { return nsDeque::GetSize() == 0; }
74 : void Append(OggPacketPtr aPacket);
75 0 : OggPacketPtr PopFront()
76 : {
77 0 : return OggPacketPtr(static_cast<ogg_packet*>(nsDeque::PopFront()));
78 : }
79 0 : ogg_packet* PeekFront()
80 : {
81 0 : return static_cast<ogg_packet*>(nsDeque::PeekFront());
82 : }
83 0 : OggPacketPtr Pop()
84 : {
85 0 : return OggPacketPtr(static_cast<ogg_packet*>(nsDeque::Pop()));
86 : }
87 0 : ogg_packet* operator[](size_t aIndex) const
88 : {
89 0 : return static_cast<ogg_packet*>(nsDeque::ObjectAt(aIndex));
90 : }
91 0 : size_t Length() const { return nsDeque::GetSize(); }
92 0 : void PushFront(OggPacketPtr aPacket)
93 : {
94 0 : nsDeque::PushFront(aPacket.release());
95 0 : }
96 0 : void Erase() { nsDeque::Erase(); }
97 : };
98 :
99 : // Encapsulates the data required for decoding an ogg bitstream and for
100 : // converting granulepos to timestamps.
101 : class OggCodecState
102 : {
103 : public:
104 : typedef mozilla::MetadataTags MetadataTags;
105 : // Ogg types we know about
106 : enum CodecType
107 : {
108 : TYPE_VORBIS=0,
109 : TYPE_THEORA,
110 : TYPE_OPUS,
111 : TYPE_SKELETON,
112 : TYPE_FLAC,
113 : TYPE_UNKNOWN
114 : };
115 :
116 : virtual ~OggCodecState();
117 :
118 : // Factory for creating nsCodecStates. Use instead of constructor.
119 : // aPage should be a beginning-of-stream page.
120 : static OggCodecState* Create(ogg_page* aPage);
121 :
122 0 : virtual CodecType GetType() { return TYPE_UNKNOWN; }
123 :
124 : // Reads a header packet. Returns false if an error was encountered
125 : // while reading header packets. Callers should check DoneReadingHeaders()
126 : // to determine if the last header has been read.
127 : // This function takes ownership of the packet and is responsible for
128 : // releasing it or queuing it for later processing.
129 0 : virtual bool DecodeHeader(OggPacketPtr aPacket)
130 : {
131 0 : return (mDoneReadingHeaders = true);
132 : }
133 :
134 : // Build a hash table with tag metadata parsed from the stream.
135 0 : virtual MetadataTags* GetTags()
136 : {
137 0 : return nullptr;
138 : }
139 :
140 : // Returns the end time that a granulepos represents.
141 0 : virtual int64_t Time(int64_t granulepos) { return -1; }
142 :
143 : // Returns the start time that a granulepos represents.
144 0 : virtual int64_t StartTime(int64_t granulepos) { return -1; }
145 :
146 : // Returns the duration of the given packet, if it can be determined.
147 0 : virtual int64_t PacketDuration(ogg_packet* aPacket) { return -1; }
148 :
149 : // Returns the start time of the given packet, if it can be determined.
150 0 : virtual int64_t PacketStartTime(ogg_packet* aPacket)
151 : {
152 0 : if (aPacket->granulepos < 0) {
153 0 : return -1;
154 : }
155 0 : int64_t endTime = Time(aPacket->granulepos);
156 0 : int64_t duration = PacketDuration(aPacket);
157 0 : if (duration > endTime) {
158 : // Audio preskip may eat a whole packet or more.
159 0 : return 0;
160 : } else {
161 0 : return endTime - duration;
162 : }
163 : }
164 :
165 : // Initializes the codec state.
166 0 : virtual bool Init() { return true; }
167 :
168 : // Returns true when this bitstream has finished reading all its
169 : // header packets.
170 0 : bool DoneReadingHeaders() { return mDoneReadingHeaders; }
171 :
172 : // Deactivates the bitstream. Only the primary video and audio bitstreams
173 : // should be active.
174 0 : void Deactivate()
175 : {
176 0 : mActive = false;
177 0 : mDoneReadingHeaders = true;
178 0 : Reset();
179 0 : }
180 :
181 : // Resets decoding state.
182 : virtual nsresult Reset();
183 :
184 : // Returns true if the OggCodecState thinks this packet is a header
185 : // packet. Note this does not verify the validity of the header packet,
186 : // it just guarantees that the packet is marked as a header packet (i.e.
187 : // it is definintely not a data packet). Do not use this to identify
188 : // streams, use it to filter header packets from data packets while
189 : // decoding.
190 0 : virtual bool IsHeader(ogg_packet* aPacket) { return false; }
191 :
192 : // Returns true if the OggCodecState thinks this packet represents a
193 : // keyframe, from which decoding can restart safely.
194 0 : virtual bool IsKeyframe(ogg_packet* aPacket) { return true; }
195 :
196 : // Returns true if there is a packet available for dequeueing in the stream.
197 : bool IsPacketReady();
198 :
199 : // Returns the next raw packet in the stream, or nullptr if there are no more
200 : // packets buffered in the packet queue. More packets can be buffered by
201 : // inserting one or more pages into the stream by calling PageIn().
202 : // The packet will have a valid granulepos.
203 : OggPacketPtr PacketOut();
204 :
205 : // Returns the next raw packet in the stream, or nullptr if there are no more
206 : // packets buffered in the packet queue, without consuming it.
207 : // The packet will have a valid granulepos.
208 : ogg_packet* PacketPeek();
209 :
210 : // Moves all raw packets from aOther to the front of the current packet queue.
211 : void PushFront(OggPacketQueue&& aOther);
212 :
213 : // Returns the next packet in the stream as a MediaRawData, or nullptr
214 : // if there are no more packets buffered in the packet queue. More packets
215 : // can be buffered by inserting one or more pages into the stream by calling
216 : // PageIn(). The packet will have a valid granulepos.
217 : virtual already_AddRefed<MediaRawData> PacketOutAsMediaRawData();
218 :
219 : // Extracts all packets from the page, and inserts them into the packet
220 : // queue. They can be extracted by calling PacketOut(). Packets from an
221 : // inactive stream are not buffered, i.e. this call has no effect for
222 : // inactive streams. Multiple pages may need to be inserted before
223 : // PacketOut() starts to return packets, as granulepos may need to be
224 : // captured.
225 : virtual nsresult PageIn(ogg_page* aPage);
226 :
227 : // Returns the maximum number of microseconds which a keyframe can be offset
228 : // from any given interframe.b
229 0 : virtual int64_t MaxKeyframeOffset() { return 0; }
230 : // Public access for mTheoraInfo.keyframe_granule_shift
231 0 : virtual int32_t KeyFrameGranuleJobs() { return 0; }
232 :
233 : // Number of packets read.
234 : uint64_t mPacketCount;
235 :
236 : // Serial number of the bitstream.
237 : uint32_t mSerial;
238 :
239 : // Ogg specific state.
240 : ogg_stream_state mState;
241 :
242 : // Queue of as yet undecoded packets. Packets are guaranteed to have
243 : // a valid granulepos.
244 : OggPacketQueue mPackets;
245 :
246 : // Is the bitstream active; whether we're decoding and playing this bitstream.
247 : bool mActive;
248 :
249 : // True when all headers packets have been read.
250 : bool mDoneReadingHeaders;
251 :
252 0 : virtual const TrackInfo* GetInfo() const
253 : {
254 0 : MOZ_RELEASE_ASSERT(false, "Can't be called directly");
255 : return nullptr;
256 : }
257 :
258 : // Validation utility for vorbis-style tag names.
259 : static bool IsValidVorbisTagName(nsCString& aName);
260 :
261 : // Utility method to parse and add a vorbis-style comment
262 : // to a metadata hash table. Most Ogg-encapsulated codecs
263 : // use the vorbis comment format for metadata.
264 : static bool AddVorbisComment(MetadataTags* aTags,
265 : const char* aComment,
266 : uint32_t aLength);
267 :
268 : protected:
269 : // Constructs a new OggCodecState. aActive denotes whether the stream is
270 : // active. For streams of unsupported or unknown types, aActive should be
271 : // false.
272 : OggCodecState(ogg_page* aBosPage, bool aActive);
273 :
274 : // Deallocates all packets stored in mUnstamped, and clears the array.
275 : void ClearUnstamped();
276 :
277 : // Extracts packets out of mState until a data packet with a non -1
278 : // granulepos is encountered, or no more packets are readable. Header
279 : // packets are pushed into the packet queue immediately, and data packets
280 : // are buffered in mUnstamped. Once a non -1 granulepos packet is read
281 : // the granulepos of the packets in mUnstamped can be inferred, and they
282 : // can be pushed over to mPackets. Used by PageIn() implementations in
283 : // subclasses.
284 : nsresult PacketOutUntilGranulepos(bool& aFoundGranulepos);
285 :
286 : // Temporary buffer in which to store packets while we're reading packets
287 : // in order to capture granulepos.
288 : nsTArray<OggPacketPtr> mUnstamped;
289 :
290 : bool SetCodecSpecificConfig(MediaByteBuffer* aBuffer,
291 : OggPacketQueue& aHeaders);
292 :
293 : private:
294 : bool InternalInit();
295 : };
296 :
297 : class VorbisState : public OggCodecState
298 : {
299 : public:
300 : explicit VorbisState(ogg_page* aBosPage);
301 : virtual ~VorbisState();
302 :
303 0 : CodecType GetType() override { return TYPE_VORBIS; }
304 : bool DecodeHeader(OggPacketPtr aPacket) override;
305 : int64_t Time(int64_t granulepos) override;
306 : int64_t PacketDuration(ogg_packet* aPacket) override;
307 : bool Init() override;
308 : nsresult Reset() override;
309 : bool IsHeader(ogg_packet* aPacket) override;
310 : nsresult PageIn(ogg_page* aPage) override;
311 0 : const TrackInfo* GetInfo() const override { return &mInfo; }
312 :
313 : // Return a hash table with tag metadata.
314 : MetadataTags* GetTags() override;
315 :
316 : private:
317 : AudioInfo mInfo;
318 : vorbis_info mVorbisInfo;
319 : vorbis_comment mComment;
320 : vorbis_dsp_state mDsp;
321 : vorbis_block mBlock;
322 : OggPacketQueue mHeaders;
323 :
324 : // Returns the end time that a granulepos represents.
325 : static int64_t Time(vorbis_info* aInfo, int64_t aGranulePos);
326 :
327 : // Reconstructs the granulepos of Vorbis packets stored in the mUnstamped
328 : // array.
329 : nsresult ReconstructVorbisGranulepos();
330 :
331 : // The "block size" of the previously decoded Vorbis packet, or 0 if we've
332 : // not yet decoded anything. This is used to calculate the number of samples
333 : // in a Vorbis packet, since each Vorbis packet depends on the previous
334 : // packet while being decoded.
335 : long mPrevVorbisBlockSize;
336 :
337 : // Granulepos (end sample) of the last decoded Vorbis packet. This is used
338 : // to calculate the Vorbis granulepos when we don't find a granulepos to
339 : // back-propagate from.
340 : int64_t mGranulepos;
341 :
342 : #ifdef VALIDATE_VORBIS_SAMPLE_CALCULATION
343 : // When validating that we've correctly predicted Vorbis packets' number
344 : // of samples, we store each packet's predicted number of samples in this
345 : // map, and verify we decode the predicted number of samples.
346 : std::map<ogg_packet*, long> mVorbisPacketSamples;
347 : #endif
348 :
349 : // Records that aPacket is predicted to have aSamples samples.
350 : // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
351 : // is not defined.
352 : void RecordVorbisPacketSamples(ogg_packet* aPacket, long aSamples);
353 :
354 : // Verifies that aPacket has had its number of samples predicted.
355 : // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
356 : // is not defined.
357 : void AssertHasRecordedPacketSamples(ogg_packet* aPacket);
358 :
359 : public:
360 : // Asserts that the number of samples predicted for aPacket is aSamples.
361 : // This function has no effect if VALIDATE_VORBIS_SAMPLE_CALCULATION
362 : // is not defined.
363 : void ValidateVorbisPacketSamples(ogg_packet* aPacket, long aSamples);
364 :
365 : };
366 :
367 : // Returns 1 if the Theora info struct is decoding a media of Theora
368 : // version (maj,min,sub) or later, otherwise returns 0.
369 : int TheoraVersion(th_info* info,
370 : unsigned char maj,
371 : unsigned char min,
372 : unsigned char sub);
373 :
374 : class TheoraState : public OggCodecState
375 : {
376 : public:
377 : explicit TheoraState(ogg_page* aBosPage);
378 : virtual ~TheoraState();
379 :
380 0 : CodecType GetType() override { return TYPE_THEORA; }
381 : bool DecodeHeader(OggPacketPtr aPacket) override;
382 : int64_t Time(int64_t granulepos) override;
383 : int64_t StartTime(int64_t granulepos) override;
384 : int64_t PacketDuration(ogg_packet* aPacket) override;
385 : bool Init() override;
386 : nsresult Reset() override;
387 : bool IsHeader(ogg_packet* aPacket) override;
388 : bool IsKeyframe(ogg_packet* aPacket) override;
389 : nsresult PageIn(ogg_page* aPage) override;
390 0 : const TrackInfo* GetInfo() const override { return &mInfo; }
391 : int64_t MaxKeyframeOffset() override;
392 0 : int32_t KeyFrameGranuleJobs() override
393 : {
394 0 : return mTheoraInfo.keyframe_granule_shift;
395 : }
396 :
397 : private:
398 : // Returns the end time that a granulepos represents.
399 : static int64_t Time(th_info* aInfo, int64_t aGranulePos);
400 :
401 : th_info mTheoraInfo;
402 : th_comment mComment;
403 : th_setup_info* mSetup;
404 : th_dec_ctx* mCtx;
405 :
406 : VideoInfo mInfo;
407 : OggPacketQueue mHeaders;
408 :
409 : // Reconstructs the granulepos of Theora packets stored in the
410 : // mUnstamped array. mUnstamped must be filled with consecutive packets from
411 : // the stream, with the last packet having a known granulepos. Using this
412 : // known granulepos, and the known frame numbers, we recover the granulepos
413 : // of all frames in the array. This enables us to determine their timestamps.
414 : void ReconstructTheoraGranulepos();
415 : };
416 :
417 : class OpusState : public OggCodecState
418 : {
419 : public:
420 : explicit OpusState(ogg_page* aBosPage);
421 : virtual ~OpusState();
422 :
423 0 : CodecType GetType() override { return TYPE_OPUS; }
424 : bool DecodeHeader(OggPacketPtr aPacket) override;
425 : int64_t Time(int64_t aGranulepos) override;
426 : int64_t PacketDuration(ogg_packet* aPacket) override;
427 : bool Init() override;
428 : nsresult Reset() override;
429 : nsresult Reset(bool aStart);
430 : bool IsHeader(ogg_packet* aPacket) override;
431 : nsresult PageIn(ogg_page* aPage) override;
432 : already_AddRefed<MediaRawData> PacketOutAsMediaRawData() override;
433 0 : const TrackInfo* GetInfo() const override { return &mInfo; }
434 :
435 : // Returns the end time that a granulepos represents.
436 : static int64_t Time(int aPreSkip, int64_t aGranulepos);
437 :
438 : // Construct and return a table of tags from the metadata header.
439 : MetadataTags* GetTags() override;
440 :
441 : private:
442 : nsAutoPtr<OpusParser> mParser;
443 : OpusMSDecoder* mDecoder;
444 :
445 : // Granule position (end sample) of the last decoded Opus packet. This is
446 : // used to calculate the amount we should trim from the last packet.
447 : int64_t mPrevPacketGranulepos;
448 :
449 : // Reconstructs the granulepos of Opus packets stored in the
450 : // mUnstamped array. mUnstamped must be filled with consecutive packets from
451 : // the stream, with the last packet having a known granulepos. Using this
452 : // known granulepos, and the known frame numbers, we recover the granulepos
453 : // of all frames in the array. This enables us to determine their timestamps.
454 : bool ReconstructOpusGranulepos();
455 :
456 : // Granule position (end sample) of the last decoded Opus page. This is
457 : // used to calculate the Opus per-packet granule positions on the last page,
458 : // where we may need to trim some samples from the end.
459 : int64_t mPrevPageGranulepos;
460 : AudioInfo mInfo;
461 : OggPacketQueue mHeaders;
462 : };
463 :
464 : // Constructs a 32bit version number out of two 16 bit major,minor
465 : // version numbers.
466 : #define SKELETON_VERSION(major, minor) (((major)<<16)|(minor))
467 :
468 : enum EMsgHeaderType
469 : {
470 : eContentType,
471 : eRole,
472 : eName,
473 : eLanguage,
474 : eTitle,
475 : eDisplayHint,
476 : eAltitude,
477 : eTrackOrder,
478 : eTrackDependencies
479 : };
480 :
481 : typedef struct
482 : {
483 : const char* mPatternToRecognize;
484 : EMsgHeaderType mMsgHeaderType;
485 : } FieldPatternType;
486 :
487 : // Stores the message information for different logical bitstream.
488 : typedef struct
489 : {
490 : nsClassHashtable<nsUint32HashKey, nsCString> mValuesStore;
491 0 : } MessageField;
492 :
493 : class SkeletonState : public OggCodecState
494 : {
495 : public:
496 : explicit SkeletonState(ogg_page* aBosPage);
497 : ~SkeletonState();
498 :
499 : nsClassHashtable<nsUint32HashKey, MessageField> mMsgFieldStore;
500 :
501 0 : CodecType GetType() override { return TYPE_SKELETON; }
502 : bool DecodeHeader(OggPacketPtr aPacket) override;
503 0 : int64_t Time(int64_t granulepos) override { return -1; }
504 0 : bool IsHeader(ogg_packet* aPacket) override { return true; }
505 :
506 : // Return true if the given time (in milliseconds) is within
507 : // the presentation time defined in the skeleton track.
508 : bool IsPresentable(int64_t aTime) { return aTime >= mPresentationTime; }
509 :
510 : // Stores the offset of the page on which a keyframe starts,
511 : // and its presentation time.
512 : class nsKeyPoint
513 : {
514 : public:
515 0 : nsKeyPoint()
516 0 : : mOffset(INT64_MAX)
517 0 : , mTime(INT64_MAX) {}
518 :
519 0 : nsKeyPoint(int64_t aOffset, int64_t aTime)
520 0 : : mOffset(aOffset)
521 0 : ,mTime(aTime) {}
522 :
523 : // Offset from start of segment/link-in-the-chain in bytes.
524 : int64_t mOffset;
525 :
526 : // Presentation time in usecs.
527 : int64_t mTime;
528 :
529 0 : bool IsNull()
530 : {
531 0 : return mOffset == INT64_MAX && mTime == INT64_MAX;
532 : }
533 : };
534 :
535 : // Stores a keyframe's byte-offset, presentation time and the serialno
536 : // of the stream it belongs to.
537 : class nsSeekTarget
538 : {
539 : public:
540 0 : nsSeekTarget() : mSerial(0) { }
541 : nsKeyPoint mKeyPoint;
542 : uint32_t mSerial;
543 0 : bool IsNull()
544 : {
545 0 : return mKeyPoint.IsNull() && mSerial == 0;
546 : }
547 : };
548 :
549 : // Determines from the seek index the keyframe which you must seek back to
550 : // in order to get all keyframes required to render all streams with
551 : // serialnos in aTracks, at time aTarget.
552 : nsresult IndexedSeekTarget(int64_t aTarget,
553 : nsTArray<uint32_t>& aTracks,
554 : nsSeekTarget& aResult);
555 :
556 0 : bool HasIndex() const
557 : {
558 0 : return mIndex.Count() > 0;
559 : }
560 :
561 : // Returns the duration of the active tracks in the media, if we have
562 : // an index. aTracks must be filled with the serialnos of the active tracks.
563 : // The duration is calculated as the greatest end time of all active tracks,
564 : // minus the smalled start time of all the active tracks.
565 : nsresult GetDuration(const nsTArray<uint32_t>& aTracks, int64_t& aDuration);
566 :
567 : private:
568 :
569 : // Decodes an index packet. Returns false on failure.
570 : bool DecodeIndex(ogg_packet* aPacket);
571 : // Decodes an fisbone packet. Returns false on failure.
572 : bool DecodeFisbone(ogg_packet* aPacket);
573 :
574 : // Gets the keypoint you must seek to in order to get the keyframe required
575 : // to render the stream at time aTarget on stream with serial aSerialno.
576 : nsresult IndexedSeekTargetForTrack(uint32_t aSerialno,
577 : int64_t aTarget,
578 : nsKeyPoint& aResult);
579 :
580 : // Version of the decoded skeleton track, as per the SKELETON_VERSION macro.
581 : uint32_t mVersion;
582 :
583 : // Presentation time of the resource in milliseconds
584 : int64_t mPresentationTime;
585 :
586 : // Length of the resource in bytes.
587 : int64_t mLength;
588 :
589 : // Stores the keyframe index and duration information for a particular
590 : // stream.
591 : class nsKeyFrameIndex
592 : {
593 : public:
594 :
595 0 : nsKeyFrameIndex(int64_t aStartTime, int64_t aEndTime)
596 0 : : mStartTime(aStartTime)
597 0 : , mEndTime(aEndTime)
598 : {
599 0 : MOZ_COUNT_CTOR(nsKeyFrameIndex);
600 0 : }
601 :
602 0 : ~nsKeyFrameIndex()
603 0 : {
604 0 : MOZ_COUNT_DTOR(nsKeyFrameIndex);
605 0 : }
606 :
607 0 : void Add(int64_t aOffset, int64_t aTimeMs)
608 : {
609 0 : mKeyPoints.AppendElement(nsKeyPoint(aOffset, aTimeMs));
610 0 : }
611 :
612 0 : const nsKeyPoint& Get(uint32_t aIndex) const
613 : {
614 0 : return mKeyPoints[aIndex];
615 : }
616 :
617 0 : uint32_t Length() const
618 : {
619 0 : return mKeyPoints.Length();
620 : }
621 :
622 : // Presentation time of the first sample in this stream in usecs.
623 : const int64_t mStartTime;
624 :
625 : // End time of the last sample in this stream in usecs.
626 : const int64_t mEndTime;
627 :
628 : private:
629 : nsTArray<nsKeyPoint> mKeyPoints;
630 : };
631 :
632 : // Maps Ogg serialnos to the index-keypoint list.
633 : nsClassHashtable<nsUint32HashKey, nsKeyFrameIndex> mIndex;
634 : };
635 :
636 0 : class FlacState : public OggCodecState
637 : {
638 : public:
639 : explicit FlacState(ogg_page* aBosPage);
640 :
641 0 : CodecType GetType() override { return TYPE_FLAC; }
642 : bool DecodeHeader(OggPacketPtr aPacket) override;
643 : int64_t Time(int64_t granulepos) override;
644 : int64_t PacketDuration(ogg_packet* aPacket) override;
645 : bool IsHeader(ogg_packet* aPacket) override;
646 : nsresult PageIn(ogg_page* aPage) override;
647 :
648 : // Return a hash table with tag metadata.
649 : MetadataTags* GetTags() override;
650 :
651 : const TrackInfo* GetInfo() const override;
652 :
653 : private:
654 : bool ReconstructFlacGranulepos(void);
655 :
656 : FlacFrameParser mParser;
657 : };
658 :
659 : } // namespace mozilla
660 :
661 : #endif
|