diff -r 000000000000 -r 6474c204b198 content/media/encoder/MediaEncoder.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/encoder/MediaEncoder.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef MediaEncoder_h_ +#define MediaEncoder_h_ + +#include "mozilla/DebugOnly.h" +#include "TrackEncoder.h" +#include "ContainerWriter.h" +#include "MediaStreamGraph.h" + +namespace mozilla { + +/** + * MediaEncoder is the framework of encoding module, it controls and manages + * procedures between ContainerWriter and TrackEncoder. ContainerWriter packs + * the encoded track data with a specific container (e.g. ogg, mp4). + * AudioTrackEncoder and VideoTrackEncoder are subclasses of TrackEncoder, and + * are responsible for encoding raw data coming from MediaStreamGraph. + * + * Also, MediaEncoder is a type of MediaStreamListener, it starts to receive raw + * segments after itself is added to the source stream. In the mean time, + * encoded track data is pulled by its owner periodically on a worker thread. A + * reentrant monitor is used to protect the push and pull of resource. + * + * MediaEncoder is designed to be a passive component, neither it owns nor in + * charge of managing threads. However, a monitor is used in function + * TrackEncoder::GetEncodedTrack() for the purpose of thread safety (e.g. + * between callbacks of MediaStreamListener and others), a call to this function + * might block. Therefore, MediaEncoder should not run on threads that forbid + * blocking, such as main thread or I/O thread. + * + * For example, an usage from MediaRecorder of this component would be: + * 1) Create an encoder with a valid MIME type. + * => encoder = MediaEncoder::CreateEncoder(aMIMEType); + * It then generate a ContainerWriter according to the MIME type, and an + * AudioTrackEncoder (or a VideoTrackEncoder too) associated with the media + * type. + * + * 2) Dispatch the task GetEncodedData() to a worker thread. + * + * 3) To start encoding, add this component to its source stream. + * => sourceStream->AddListener(encoder); + * + * 4) To stop encoding, remove this component from its source stream. + * => sourceStream->RemoveListener(encoder); + */ +class MediaEncoder : public MediaStreamListener +{ +public : + enum { + ENCODE_METADDATA, + ENCODE_TRACK, + ENCODE_DONE, + ENCODE_ERROR, + }; + + MediaEncoder(ContainerWriter* aWriter, + AudioTrackEncoder* aAudioEncoder, + VideoTrackEncoder* aVideoEncoder, + const nsAString& aMIMEType) + : mWriter(aWriter) + , mAudioEncoder(aAudioEncoder) + , mVideoEncoder(aVideoEncoder) + , mStartTime(TimeStamp::Now()) + , mMIMEType(aMIMEType) + , mState(MediaEncoder::ENCODE_METADDATA) + , mShutdown(false) + {} + + ~MediaEncoder() {}; + + /** + * Notified by the control loop of MediaStreamGraph; aQueueMedia is the raw + * track data in form of MediaSegment. + */ + virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, + TrackRate aTrackRate, + TrackTicks aTrackOffset, + uint32_t aTrackEvents, + const MediaSegment& aQueuedMedia); + + /** + * Notified the stream is being removed. + */ + virtual void NotifyRemoved(MediaStreamGraph* aGraph); + + /** + * Creates an encoder with a given MIME type. Returns null if we are unable + * to create the encoder. For now, default aMIMEType to "audio/ogg" and use + * Ogg+Opus if it is empty. + */ + static already_AddRefed CreateEncoder(const nsAString& aMIMEType, + uint8_t aTrackTypes = ContainerWriter::CREATE_AUDIO_TRACK); + /** + * Encodes the raw track data and returns the final container data. Assuming + * it is called on a single worker thread. The buffer of container data is + * allocated in ContainerWriter::GetContainerData(), and is appended to + * aOutputBufs. aMIMEType is the valid mime-type of this returned container + * data. + */ + void GetEncodedData(nsTArray >* aOutputBufs, + nsAString& aMIMEType); + + /** + * Return true if MediaEncoder has been shutdown. Reasons are encoding + * complete, encounter an error, or being canceled by its caller. + */ + bool IsShutdown() + { + return mShutdown; + } + + /** + * Cancel the encoding, and wakes up the lock of reentrant monitor in encoder. + */ + void Cancel() + { + if (mAudioEncoder) { + mAudioEncoder->NotifyCancel(); + } + if (mVideoEncoder) { + mVideoEncoder->NotifyCancel(); + } + } + + bool HasError() + { + return mState == ENCODE_ERROR; + } + +#ifdef MOZ_WEBM_ENCODER + static bool IsWebMEncoderEnabled(); +#endif + +#ifdef MOZ_OMX_ENCODER + static bool IsOMXEncoderEnabled(); +#endif + +private: + // Get encoded data from trackEncoder and write to muxer + nsresult WriteEncodedDataToMuxer(TrackEncoder *aTrackEncoder); + // Get metadata from trackEncoder and copy to muxer + nsresult CopyMetadataToMuxer(TrackEncoder* aTrackEncoder); + nsAutoPtr mWriter; + nsAutoPtr mAudioEncoder; + nsAutoPtr mVideoEncoder; + TimeStamp mStartTime; + nsString mMIMEType; + int mState; + bool mShutdown; + // Get duration from create encoder, for logging purpose + double GetEncodeTimeStamp() + { + TimeDuration decodeTime; + decodeTime = TimeStamp::Now() - mStartTime; + return decodeTime.ToMilliseconds(); + } +}; + +} +#endif