michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef TrackEncoder_h_ michael@0: #define TrackEncoder_h_ michael@0: michael@0: #include "mozilla/ReentrantMonitor.h" michael@0: michael@0: #include "AudioSegment.h" michael@0: #include "EncodedFrameContainer.h" michael@0: #include "StreamBuffer.h" michael@0: #include "TrackMetadataBase.h" michael@0: #include "VideoSegment.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: class MediaStreamGraph; michael@0: michael@0: /** michael@0: * Base class of AudioTrackEncoder and VideoTrackEncoder. Lifetimes managed by michael@0: * MediaEncoder. Most methods can only be called on the MediaEncoder's thread, michael@0: * but some subclass methods can be called on other threads when noted. michael@0: * michael@0: * NotifyQueuedTrackChanges is called on subclasses of this class from the michael@0: * MediaStreamGraph thread, and AppendAudioSegment/AppendVideoSegment is then michael@0: * called to store media data in the TrackEncoder. Later on, GetEncodedTrack is michael@0: * called on MediaEncoder's thread to encode and retrieve the encoded data. michael@0: */ michael@0: class TrackEncoder michael@0: { michael@0: public: michael@0: TrackEncoder(); michael@0: michael@0: virtual ~TrackEncoder() {} michael@0: michael@0: /** michael@0: * Notified by the same callbcak of MediaEncoder when it has received a track michael@0: * change from MediaStreamGraph. Called on the MediaStreamGraph thread. michael@0: */ michael@0: virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, michael@0: TrackRate aTrackRate, michael@0: TrackTicks aTrackOffset, michael@0: uint32_t aTrackEvents, michael@0: const MediaSegment& aQueuedMedia) = 0; michael@0: michael@0: /** michael@0: * Notified by the same callback of MediaEncoder when it has been removed from michael@0: * MediaStreamGraph. Called on the MediaStreamGraph thread. michael@0: */ michael@0: void NotifyRemoved(MediaStreamGraph* aGraph) { NotifyEndOfStream(); } michael@0: michael@0: /** michael@0: * Creates and sets up meta data for a specific codec, called on the worker michael@0: * thread. michael@0: */ michael@0: virtual already_AddRefed GetMetadata() = 0; michael@0: michael@0: /** michael@0: * Encodes raw segments. Result data is returned in aData, and called on the michael@0: * worker thread. michael@0: */ michael@0: virtual nsresult GetEncodedTrack(EncodedFrameContainer& aData) = 0; michael@0: michael@0: /** michael@0: * True if the track encoder has encoded all source segments coming from michael@0: * MediaStreamGraph. Call on the worker thread. michael@0: */ michael@0: bool IsEncodingComplete() { return mEncodingComplete; } michael@0: michael@0: /** michael@0: * Notifies from MediaEncoder to cancel the encoding, and wakes up michael@0: * mReentrantMonitor if encoder is waiting on it. michael@0: */ michael@0: void NotifyCancel() michael@0: { michael@0: ReentrantMonitorAutoEnter mon(mReentrantMonitor); michael@0: mCanceled = true; michael@0: mReentrantMonitor.NotifyAll(); michael@0: } michael@0: michael@0: protected: michael@0: /** michael@0: * Notifies track encoder that we have reached the end of source stream, and michael@0: * wakes up mReentrantMonitor if encoder is waiting for any source data. michael@0: */ michael@0: virtual void NotifyEndOfStream() = 0; michael@0: michael@0: /** michael@0: * A ReentrantMonitor to protect the pushing and pulling of mRawSegment which michael@0: * is declared in its subclasses, and the following flags: mInitialized, michael@0: * EndOfStream and mCanceled. The control of protection is managed by its michael@0: * subclasses. michael@0: */ michael@0: ReentrantMonitor mReentrantMonitor; michael@0: michael@0: /** michael@0: * True if the track encoder has encoded all source data. michael@0: */ michael@0: bool mEncodingComplete; michael@0: michael@0: /** michael@0: * True if flag of EOS or any form of indicating EOS has set in the codec- michael@0: * encoder. michael@0: */ michael@0: bool mEosSetInEncoder; michael@0: michael@0: /** michael@0: * True if the track encoder has initialized successfully, protected by michael@0: * mReentrantMonitor. michael@0: */ michael@0: bool mInitialized; michael@0: michael@0: /** michael@0: * True if the TrackEncoder has received an event of TRACK_EVENT_ENDED from michael@0: * MediaStreamGraph, or the MediaEncoder is removed from its source stream, michael@0: * protected by mReentrantMonitor. michael@0: */ michael@0: bool mEndOfStream; michael@0: michael@0: /** michael@0: * True if a cancellation of encoding is sent from MediaEncoder, protected by michael@0: * mReentrantMonitor. michael@0: */ michael@0: bool mCanceled; michael@0: michael@0: #ifdef PR_LOGGING michael@0: // How many times we have tried to initialize the encoder. michael@0: uint32_t mAudioInitCounter; michael@0: uint32_t mVideoInitCounter; michael@0: #endif michael@0: }; michael@0: michael@0: class AudioTrackEncoder : public TrackEncoder michael@0: { michael@0: public: michael@0: AudioTrackEncoder() michael@0: : TrackEncoder() michael@0: , mChannels(0) michael@0: , mSamplingRate(0) michael@0: {} michael@0: michael@0: void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, michael@0: TrackRate aTrackRate, michael@0: TrackTicks aTrackOffset, michael@0: uint32_t aTrackEvents, michael@0: const MediaSegment& aQueuedMedia) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Interleaves the track data and stores the result into aOutput. Might need michael@0: * to up-mix or down-mix the channel data if the channels number of this chunk michael@0: * is different from aOutputChannels. The channel data from aChunk might be michael@0: * modified by up-mixing. michael@0: */ michael@0: static void InterleaveTrackData(AudioChunk& aChunk, int32_t aDuration, michael@0: uint32_t aOutputChannels, michael@0: AudioDataValue* aOutput); michael@0: michael@0: /** michael@0: * De-interleaves the aInput data and stores the result into aOutput. michael@0: * No up-mix or down-mix operations inside. michael@0: */ michael@0: static void DeInterleaveTrackData(AudioDataValue* aInput, int32_t aDuration, michael@0: int32_t aChannels, AudioDataValue* aOutput); michael@0: michael@0: protected: michael@0: /** michael@0: * Number of samples per channel in a pcm buffer. This is also the value of michael@0: * frame size required by audio encoder, and mReentrantMonitor will be michael@0: * notified when at least this much data has been added to mRawSegment. michael@0: */ michael@0: virtual int GetPacketDuration() { return 0; } michael@0: michael@0: /** michael@0: * Initializes the audio encoder. The call of this method is delayed until we michael@0: * have received the first valid track from MediaStreamGraph, and the michael@0: * mReentrantMonitor will be notified if other methods is waiting for encoder michael@0: * to be completely initialized. This method is called on the MediaStreamGraph michael@0: * thread. michael@0: */ michael@0: virtual nsresult Init(int aChannels, int aSamplingRate) = 0; michael@0: michael@0: /** michael@0: * Appends and consumes track data from aSegment, this method is called on michael@0: * the MediaStreamGraph thread. mReentrantMonitor will be notified when at michael@0: * least GetPacketDuration() data has been added to mRawSegment, wake up other michael@0: * method which is waiting for more data from mRawSegment. michael@0: */ michael@0: nsresult AppendAudioSegment(const AudioSegment& aSegment); michael@0: michael@0: /** michael@0: * Notifies the audio encoder that we have reached the end of source stream, michael@0: * and wakes up mReentrantMonitor if encoder is waiting for more track data. michael@0: */ michael@0: virtual void NotifyEndOfStream() MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * The number of channels are used for processing PCM data in the audio encoder. michael@0: * This value comes from the first valid audio chunk. If encoder can't support michael@0: * the channels in the chunk, downmix PCM stream can be performed. michael@0: * This value also be used to initialize the audio encoder. michael@0: */ michael@0: int mChannels; michael@0: michael@0: /** michael@0: * The sampling rate of source audio data. michael@0: */ michael@0: int mSamplingRate; michael@0: michael@0: /** michael@0: * A segment queue of audio track data, protected by mReentrantMonitor. michael@0: */ michael@0: AudioSegment mRawSegment; michael@0: }; michael@0: michael@0: class VideoTrackEncoder : public TrackEncoder michael@0: { michael@0: public: michael@0: VideoTrackEncoder() michael@0: : TrackEncoder() michael@0: , mFrameWidth(0) michael@0: , mFrameHeight(0) michael@0: , mDisplayWidth(0) michael@0: , mDisplayHeight(0) michael@0: , mTrackRate(0) michael@0: , mTotalFrameDuration(0) michael@0: {} michael@0: michael@0: /** michael@0: * Notified by the same callbcak of MediaEncoder when it has received a track michael@0: * change from MediaStreamGraph. Called on the MediaStreamGraph thread. michael@0: */ michael@0: void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, michael@0: TrackRate aTrackRate, michael@0: TrackTicks aTrackOffset, michael@0: uint32_t aTrackEvents, michael@0: const MediaSegment& aQueuedMedia) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: /** michael@0: * Initialized the video encoder. In order to collect the value of width and michael@0: * height of source frames, this initialization is delayed until we have michael@0: * received the first valid video frame from MediaStreamGraph; michael@0: * mReentrantMonitor will be notified after it has successfully initialized, michael@0: * and this method is called on the MediaStramGraph thread. michael@0: */ michael@0: virtual nsresult Init(int aWidth, int aHeight, int aDisplayWidth, michael@0: int aDisplayHeight, TrackRate aTrackRate) = 0; michael@0: michael@0: /** michael@0: * Appends source video frames to mRawSegment. We only append the source chunk michael@0: * if it is unique to mLastChunk. Called on the MediaStreamGraph thread. michael@0: */ michael@0: nsresult AppendVideoSegment(const VideoSegment& aSegment); michael@0: michael@0: /** michael@0: * Tells the video track encoder that we've reached the end of source stream, michael@0: * and wakes up mReentrantMonitor if encoder is waiting for more track data. michael@0: * Called on the MediaStreamGraph thread. michael@0: */ michael@0: virtual void NotifyEndOfStream() MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Create a buffer of black image in format of YUV:420. Called on the worker michael@0: * thread. michael@0: */ michael@0: void CreateMutedFrame(nsTArray* aOutputBuffer); michael@0: michael@0: /** michael@0: * The width of source video frame, ceiled if the source width is odd. michael@0: */ michael@0: int mFrameWidth; michael@0: michael@0: /** michael@0: * The height of source video frame, ceiled if the source height is odd. michael@0: */ michael@0: int mFrameHeight; michael@0: michael@0: /** michael@0: * The display width of source video frame. michael@0: */ michael@0: int mDisplayWidth; michael@0: michael@0: /** michael@0: * The display height of source video frame. michael@0: */ michael@0: int mDisplayHeight; michael@0: michael@0: /** michael@0: * The track rate of source video. michael@0: */ michael@0: TrackRate mTrackRate; michael@0: michael@0: /** michael@0: * The total duration of frames in encoded video in TrackTicks, kept track of michael@0: * in subclasses. michael@0: */ michael@0: TrackTicks mTotalFrameDuration; michael@0: michael@0: /** michael@0: * The last unique frame we've sent to track encoder, kept track of in michael@0: * subclasses. michael@0: */ michael@0: VideoFrame mLastFrame; michael@0: michael@0: /** michael@0: * A segment queue of audio track data, protected by mReentrantMonitor. michael@0: */ michael@0: VideoSegment mRawSegment; michael@0: }; michael@0: michael@0: } michael@0: #endif