1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webm/WebMReader.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,244 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 +#if !defined(WebMReader_h_) 1.10 +#define WebMReader_h_ 1.11 + 1.12 +#include <stdint.h> 1.13 + 1.14 +#include "nsDeque.h" 1.15 +#include "MediaDecoderReader.h" 1.16 +#include "nsAutoRef.h" 1.17 +#include "nestegg/nestegg.h" 1.18 + 1.19 +#define VPX_DONT_DEFINE_STDINT_TYPES 1.20 +#include "vpx/vpx_codec.h" 1.21 + 1.22 +#ifdef MOZ_TREMOR 1.23 +#include "tremor/ivorbiscodec.h" 1.24 +#else 1.25 +#include "vorbis/codec.h" 1.26 +#endif 1.27 + 1.28 +#ifdef MOZ_OPUS 1.29 +#include "OpusParser.h" 1.30 +#endif 1.31 + 1.32 +namespace mozilla { 1.33 + 1.34 +class WebMBufferedState; 1.35 + 1.36 +// Holds a nestegg_packet, and its file offset. This is needed so we 1.37 +// know the offset in the file we've played up to, in order to calculate 1.38 +// whether it's likely we can play through to the end without needing 1.39 +// to stop to buffer, given the current download rate. 1.40 +class NesteggPacketHolder { 1.41 +public: 1.42 + NesteggPacketHolder(nestegg_packet* aPacket, int64_t aOffset) 1.43 + : mPacket(aPacket), mOffset(aOffset) 1.44 + { 1.45 + MOZ_COUNT_CTOR(NesteggPacketHolder); 1.46 + } 1.47 + ~NesteggPacketHolder() { 1.48 + MOZ_COUNT_DTOR(NesteggPacketHolder); 1.49 + nestegg_free_packet(mPacket); 1.50 + } 1.51 + nestegg_packet* mPacket; 1.52 + // Offset in bytes. This is the offset of the end of the Block 1.53 + // which contains the packet. 1.54 + int64_t mOffset; 1.55 +private: 1.56 + // Copy constructor and assignment operator not implemented. Don't use them! 1.57 + NesteggPacketHolder(const NesteggPacketHolder &aOther); 1.58 + NesteggPacketHolder& operator= (NesteggPacketHolder const& aOther); 1.59 +}; 1.60 + 1.61 +// Thread and type safe wrapper around nsDeque. 1.62 +class PacketQueueDeallocator : public nsDequeFunctor { 1.63 + virtual void* operator() (void* anObject) { 1.64 + delete static_cast<NesteggPacketHolder*>(anObject); 1.65 + return nullptr; 1.66 + } 1.67 +}; 1.68 + 1.69 +// Typesafe queue for holding nestegg packets. It has 1.70 +// ownership of the items in the queue and will free them 1.71 +// when destroyed. 1.72 +class WebMPacketQueue : private nsDeque { 1.73 + public: 1.74 + WebMPacketQueue() 1.75 + : nsDeque(new PacketQueueDeallocator()) 1.76 + {} 1.77 + 1.78 + ~WebMPacketQueue() { 1.79 + Reset(); 1.80 + } 1.81 + 1.82 + inline int32_t GetSize() { 1.83 + return nsDeque::GetSize(); 1.84 + } 1.85 + 1.86 + inline void Push(NesteggPacketHolder* aItem) { 1.87 + NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue"); 1.88 + nsDeque::Push(aItem); 1.89 + } 1.90 + 1.91 + inline void PushFront(NesteggPacketHolder* aItem) { 1.92 + NS_ASSERTION(aItem, "NULL pushed to WebMPacketQueue"); 1.93 + nsDeque::PushFront(aItem); 1.94 + } 1.95 + 1.96 + inline NesteggPacketHolder* PopFront() { 1.97 + return static_cast<NesteggPacketHolder*>(nsDeque::PopFront()); 1.98 + } 1.99 + 1.100 + void Reset() { 1.101 + while (GetSize() > 0) { 1.102 + delete PopFront(); 1.103 + } 1.104 + } 1.105 +}; 1.106 + 1.107 +class WebMReader : public MediaDecoderReader 1.108 +{ 1.109 +public: 1.110 + WebMReader(AbstractMediaDecoder* aDecoder); 1.111 + ~WebMReader(); 1.112 + 1.113 + virtual nsresult Init(MediaDecoderReader* aCloneDonor); 1.114 + virtual nsresult ResetDecode(); 1.115 + virtual bool DecodeAudioData(); 1.116 + 1.117 + // If the Theora granulepos has not been captured, it may read several packets 1.118 + // until one with a granulepos has been captured, to ensure that all packets 1.119 + // read have valid time info. 1.120 + virtual bool DecodeVideoFrame(bool &aKeyframeSkip, 1.121 + int64_t aTimeThreshold); 1.122 + 1.123 + virtual bool HasAudio() 1.124 + { 1.125 + NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); 1.126 + return mHasAudio; 1.127 + } 1.128 + 1.129 + virtual bool HasVideo() 1.130 + { 1.131 + NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); 1.132 + return mHasVideo; 1.133 + } 1.134 + 1.135 + virtual nsresult ReadMetadata(MediaInfo* aInfo, 1.136 + MetadataTags** aTags); 1.137 + virtual nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime); 1.138 + virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime); 1.139 + virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset); 1.140 + 1.141 +protected: 1.142 + // Value passed to NextPacket to determine if we are reading a video or an 1.143 + // audio packet. 1.144 + enum TrackType { 1.145 + VIDEO = 0, 1.146 + AUDIO = 1 1.147 + }; 1.148 + 1.149 + // Read a packet from the nestegg file. Returns nullptr if all packets for 1.150 + // the particular track have been read. Pass VIDEO or AUDIO to indicate the 1.151 + // type of the packet we want to read. 1.152 + nsReturnRef<NesteggPacketHolder> NextPacket(TrackType aTrackType); 1.153 + 1.154 + // Pushes a packet to the front of the video packet queue. 1.155 + virtual void PushVideoPacket(NesteggPacketHolder* aItem); 1.156 + 1.157 + // Returns an initialized ogg packet with data obtained from the WebM container. 1.158 + ogg_packet InitOggPacket(unsigned char* aData, 1.159 + size_t aLength, 1.160 + bool aBOS, 1.161 + bool aEOS, 1.162 + int64_t aGranulepos); 1.163 + 1.164 +#ifdef MOZ_OPUS 1.165 + // Setup opus decoder 1.166 + bool InitOpusDecoder(); 1.167 +#endif 1.168 + 1.169 + // Decode a nestegg packet of audio data. Push the audio data on the 1.170 + // audio queue. Returns true when there's more audio to decode, 1.171 + // false if the audio is finished, end of file has been reached, 1.172 + // or an un-recoverable read error has occured. The reader's monitor 1.173 + // must be held during this call. The caller is responsible for freeing 1.174 + // aPacket. 1.175 + bool DecodeAudioPacket(nestegg_packet* aPacket, int64_t aOffset); 1.176 + 1.177 + // Release context and set to null. Called when an error occurs during 1.178 + // reading metadata or destruction of the reader itself. 1.179 + void Cleanup(); 1.180 + 1.181 +private: 1.182 + // libnestegg context for webm container. Access on state machine thread 1.183 + // or decoder thread only. 1.184 + nestegg* mContext; 1.185 + 1.186 + // VP8 decoder state 1.187 + vpx_codec_ctx_t mVPX; 1.188 + 1.189 + // Vorbis decoder state 1.190 + vorbis_info mVorbisInfo; 1.191 + vorbis_comment mVorbisComment; 1.192 + vorbis_dsp_state mVorbisDsp; 1.193 + vorbis_block mVorbisBlock; 1.194 + uint32_t mPacketCount; 1.195 + uint32_t mChannels; 1.196 + 1.197 + 1.198 +#ifdef MOZ_OPUS 1.199 + // Opus decoder state 1.200 + nsAutoPtr<OpusParser> mOpusParser; 1.201 + OpusMSDecoder *mOpusDecoder; 1.202 + int mSkip; // Number of samples left to trim before playback. 1.203 + uint64_t mSeekPreroll; // Number of nanoseconds that must be discarded after seeking. 1.204 +#endif 1.205 + 1.206 + // Queue of video and audio packets that have been read but not decoded. These 1.207 + // must only be accessed from the state machine thread. 1.208 + WebMPacketQueue mVideoPackets; 1.209 + WebMPacketQueue mAudioPackets; 1.210 + 1.211 + // Index of video and audio track to play 1.212 + uint32_t mVideoTrack; 1.213 + uint32_t mAudioTrack; 1.214 + 1.215 + // Time in microseconds of the start of the first audio frame we've decoded. 1.216 + int64_t mAudioStartUsec; 1.217 + 1.218 + // Number of audio frames we've decoded since decoding began at mAudioStartMs. 1.219 + uint64_t mAudioFrames; 1.220 + 1.221 + // Number of microseconds that must be discarded from the start of the Stream. 1.222 + uint64_t mCodecDelay; 1.223 + 1.224 + // Parser state and computed offset-time mappings. Shared by multiple 1.225 + // readers when decoder has been cloned. Main thread only. 1.226 + nsRefPtr<WebMBufferedState> mBufferedState; 1.227 + 1.228 + // Size of the frame initially present in the stream. The picture region 1.229 + // is defined as a ratio relative to this. 1.230 + nsIntSize mInitialFrame; 1.231 + 1.232 + // Picture region, as relative to the initial frame size. 1.233 + nsIntRect mPicture; 1.234 + 1.235 + // Codec ID of audio track 1.236 + int mAudioCodec; 1.237 + // Codec ID of video track 1.238 + int mVideoCodec; 1.239 + 1.240 + // Booleans to indicate if we have audio and/or video data 1.241 + bool mHasVideo; 1.242 + bool mHasAudio; 1.243 +}; 1.244 + 1.245 +} // namespace mozilla 1.246 + 1.247 +#endif