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 MediaEncoder_h_ michael@0: #define MediaEncoder_h_ michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: #include "TrackEncoder.h" michael@0: #include "ContainerWriter.h" michael@0: #include "MediaStreamGraph.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * MediaEncoder is the framework of encoding module, it controls and manages michael@0: * procedures between ContainerWriter and TrackEncoder. ContainerWriter packs michael@0: * the encoded track data with a specific container (e.g. ogg, mp4). michael@0: * AudioTrackEncoder and VideoTrackEncoder are subclasses of TrackEncoder, and michael@0: * are responsible for encoding raw data coming from MediaStreamGraph. michael@0: * michael@0: * Also, MediaEncoder is a type of MediaStreamListener, it starts to receive raw michael@0: * segments after itself is added to the source stream. In the mean time, michael@0: * encoded track data is pulled by its owner periodically on a worker thread. A michael@0: * reentrant monitor is used to protect the push and pull of resource. michael@0: * michael@0: * MediaEncoder is designed to be a passive component, neither it owns nor in michael@0: * charge of managing threads. However, a monitor is used in function michael@0: * TrackEncoder::GetEncodedTrack() for the purpose of thread safety (e.g. michael@0: * between callbacks of MediaStreamListener and others), a call to this function michael@0: * might block. Therefore, MediaEncoder should not run on threads that forbid michael@0: * blocking, such as main thread or I/O thread. michael@0: * michael@0: * For example, an usage from MediaRecorder of this component would be: michael@0: * 1) Create an encoder with a valid MIME type. michael@0: * => encoder = MediaEncoder::CreateEncoder(aMIMEType); michael@0: * It then generate a ContainerWriter according to the MIME type, and an michael@0: * AudioTrackEncoder (or a VideoTrackEncoder too) associated with the media michael@0: * type. michael@0: * michael@0: * 2) Dispatch the task GetEncodedData() to a worker thread. michael@0: * michael@0: * 3) To start encoding, add this component to its source stream. michael@0: * => sourceStream->AddListener(encoder); michael@0: * michael@0: * 4) To stop encoding, remove this component from its source stream. michael@0: * => sourceStream->RemoveListener(encoder); michael@0: */ michael@0: class MediaEncoder : public MediaStreamListener michael@0: { michael@0: public : michael@0: enum { michael@0: ENCODE_METADDATA, michael@0: ENCODE_TRACK, michael@0: ENCODE_DONE, michael@0: ENCODE_ERROR, michael@0: }; michael@0: michael@0: MediaEncoder(ContainerWriter* aWriter, michael@0: AudioTrackEncoder* aAudioEncoder, michael@0: VideoTrackEncoder* aVideoEncoder, michael@0: const nsAString& aMIMEType) michael@0: : mWriter(aWriter) michael@0: , mAudioEncoder(aAudioEncoder) michael@0: , mVideoEncoder(aVideoEncoder) michael@0: , mStartTime(TimeStamp::Now()) michael@0: , mMIMEType(aMIMEType) michael@0: , mState(MediaEncoder::ENCODE_METADDATA) michael@0: , mShutdown(false) michael@0: {} michael@0: michael@0: ~MediaEncoder() {}; michael@0: michael@0: /** michael@0: * Notified by the control loop of MediaStreamGraph; aQueueMedia is the raw michael@0: * track data in form of MediaSegment. 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); michael@0: michael@0: /** michael@0: * Notified the stream is being removed. michael@0: */ michael@0: virtual void NotifyRemoved(MediaStreamGraph* aGraph); michael@0: michael@0: /** michael@0: * Creates an encoder with a given MIME type. Returns null if we are unable michael@0: * to create the encoder. For now, default aMIMEType to "audio/ogg" and use michael@0: * Ogg+Opus if it is empty. michael@0: */ michael@0: static already_AddRefed CreateEncoder(const nsAString& aMIMEType, michael@0: uint8_t aTrackTypes = ContainerWriter::CREATE_AUDIO_TRACK); michael@0: /** michael@0: * Encodes the raw track data and returns the final container data. Assuming michael@0: * it is called on a single worker thread. The buffer of container data is michael@0: * allocated in ContainerWriter::GetContainerData(), and is appended to michael@0: * aOutputBufs. aMIMEType is the valid mime-type of this returned container michael@0: * data. michael@0: */ michael@0: void GetEncodedData(nsTArray >* aOutputBufs, michael@0: nsAString& aMIMEType); michael@0: michael@0: /** michael@0: * Return true if MediaEncoder has been shutdown. Reasons are encoding michael@0: * complete, encounter an error, or being canceled by its caller. michael@0: */ michael@0: bool IsShutdown() michael@0: { michael@0: return mShutdown; michael@0: } michael@0: michael@0: /** michael@0: * Cancel the encoding, and wakes up the lock of reentrant monitor in encoder. michael@0: */ michael@0: void Cancel() michael@0: { michael@0: if (mAudioEncoder) { michael@0: mAudioEncoder->NotifyCancel(); michael@0: } michael@0: if (mVideoEncoder) { michael@0: mVideoEncoder->NotifyCancel(); michael@0: } michael@0: } michael@0: michael@0: bool HasError() michael@0: { michael@0: return mState == ENCODE_ERROR; michael@0: } michael@0: michael@0: #ifdef MOZ_WEBM_ENCODER michael@0: static bool IsWebMEncoderEnabled(); michael@0: #endif michael@0: michael@0: #ifdef MOZ_OMX_ENCODER michael@0: static bool IsOMXEncoderEnabled(); michael@0: #endif michael@0: michael@0: private: michael@0: // Get encoded data from trackEncoder and write to muxer michael@0: nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder); michael@0: // Get metadata from trackEncoder and copy to muxer michael@0: nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder); michael@0: nsAutoPtr mWriter; michael@0: nsAutoPtr mAudioEncoder; michael@0: nsAutoPtr mVideoEncoder; michael@0: TimeStamp mStartTime; michael@0: nsString mMIMEType; michael@0: int mState; michael@0: bool mShutdown; michael@0: // Get duration from create encoder, for logging purpose michael@0: double GetEncodeTimeStamp() michael@0: { michael@0: TimeDuration decodeTime; michael@0: decodeTime = TimeStamp::Now() - mStartTime; michael@0: return decodeTime.ToMilliseconds(); michael@0: } michael@0: }; michael@0: michael@0: } michael@0: #endif