content/media/ogg/OggCodecState.h

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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

mercurial