mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-11-04 10:05:51 +00:00
370 lines
12 KiB
C
370 lines
12 KiB
C
|
/* -*- 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 OMXCodecWrapper_h_
|
||
|
#define OMXCodecWrapper_h_
|
||
|
|
||
|
#include <gui/Surface.h>
|
||
|
#include <utils/RefBase.h>
|
||
|
#include <stagefright/foundation/ABuffer.h>
|
||
|
#include <stagefright/foundation/AMessage.h>
|
||
|
#include <stagefright/MediaCodec.h>
|
||
|
|
||
|
#include "AudioSegment.h"
|
||
|
#include "GonkNativeWindow.h"
|
||
|
#include "GonkNativeWindowClient.h"
|
||
|
#include "mozilla/media/MediaSystemResourceClient.h"
|
||
|
#include "mozilla/RefPtr.h"
|
||
|
|
||
|
#include <speex/speex_resampler.h>
|
||
|
|
||
|
namespace android {
|
||
|
|
||
|
// Wrapper class for managing HW codec reservations
|
||
|
class OMXCodecReservation : public RefBase
|
||
|
{
|
||
|
public:
|
||
|
OMXCodecReservation(bool aEncoder) : mOwned(false)
|
||
|
{
|
||
|
mType = aEncoder ? mozilla::MediaSystemResourceType::VIDEO_ENCODER :
|
||
|
mozilla::MediaSystemResourceType::VIDEO_DECODER;
|
||
|
}
|
||
|
|
||
|
virtual ~OMXCodecReservation()
|
||
|
{
|
||
|
ReleaseOMXCodec();
|
||
|
}
|
||
|
|
||
|
/** Reserve the Encode or Decode resource for this instance */
|
||
|
virtual bool ReserveOMXCodec();
|
||
|
|
||
|
/** Release the Encode or Decode resource for this instance */
|
||
|
virtual void ReleaseOMXCodec();
|
||
|
|
||
|
private:
|
||
|
mozilla::MediaSystemResourceType mType;
|
||
|
bool mOwned; // We already own this resource
|
||
|
|
||
|
RefPtr<mozilla::MediaSystemResourceClient> mClient;
|
||
|
};
|
||
|
|
||
|
|
||
|
class OMXAudioEncoder;
|
||
|
class OMXVideoEncoder;
|
||
|
|
||
|
/**
|
||
|
* This class (and its subclasses) wraps the video and audio codec from
|
||
|
* MediaCodec API in libstagefright. Currently only AVC/H.264 video encoder and
|
||
|
* AAC audio encoder are supported.
|
||
|
*
|
||
|
* OMXCodecWrapper has static creator functions that returns actual codec
|
||
|
* instances for different types of codec supported and serves as superclass to
|
||
|
* provide a function to read encoded data as byte array from codec. Two
|
||
|
* subclasses, OMXAudioEncoder and OMXVideoEncoder, respectively provides
|
||
|
* functions for encoding data from audio and video track.
|
||
|
*
|
||
|
* A typical usage is as follows:
|
||
|
* - Call one of the creator function Create...() to get either a
|
||
|
* OMXAudioEncoder or OMXVideoEncoder object.
|
||
|
* - Configure codec by providing characteristics of input raw data, such as
|
||
|
* video frame width and height, using Configure().
|
||
|
* - Send raw data (and notify end of stream) with Encode().
|
||
|
* - Get encoded data through GetNextEncodedFrame().
|
||
|
* - Repeat previous 2 steps until end of stream.
|
||
|
* - Destroy the object.
|
||
|
*
|
||
|
* The lifecycle of underlying OMX codec is binded with construction and
|
||
|
* destruction of OMXCodecWrapper and subclass objects. For some types of
|
||
|
* codecs, such as HW accelerated AVC/H.264 encoder, there can be only one
|
||
|
* instance system-wise at a time, attempting to create another instance will
|
||
|
* fail.
|
||
|
*/
|
||
|
class OMXCodecWrapper
|
||
|
{
|
||
|
public:
|
||
|
// Codec types.
|
||
|
enum CodecType {
|
||
|
AAC_ENC, // AAC encoder.
|
||
|
AMR_NB_ENC, // AMR_NB encoder.
|
||
|
AVC_ENC, // AVC/H.264 encoder.
|
||
|
EVRC_ENC, // EVRC encoder
|
||
|
TYPE_COUNT
|
||
|
};
|
||
|
|
||
|
// Input and output flags.
|
||
|
enum {
|
||
|
// For Encode() and Encode, it indicates the end of input stream;
|
||
|
// For GetNextEncodedFrame(), it indicates the end of output
|
||
|
// stream.
|
||
|
BUFFER_EOS = MediaCodec::BUFFER_FLAG_EOS,
|
||
|
// For GetNextEncodedFrame(). It indicates the output buffer is an I-frame.
|
||
|
BUFFER_SYNC_FRAME = MediaCodec::BUFFER_FLAG_SYNCFRAME,
|
||
|
// For GetNextEncodedFrame(). It indicates that the output buffer contains
|
||
|
// codec specific configuration info. (SPS & PPS for AVC/H.264;
|
||
|
// DecoderSpecificInfo for AAC)
|
||
|
BUFFER_CODEC_CONFIG = MediaCodec::BUFFER_FLAG_CODECCONFIG,
|
||
|
};
|
||
|
|
||
|
// Hard-coded values for AAC DecoderConfigDescriptor in libstagefright.
|
||
|
// See MPEG4Writer::Track::writeMp4aEsdsBox()
|
||
|
// Exposed for the need of MP4 container writer.
|
||
|
enum {
|
||
|
kAACBitrate = 96000, // kbps
|
||
|
kAACFrameSize = 768, // bytes
|
||
|
kAACFrameDuration = 1024, // How many samples per AAC frame.
|
||
|
};
|
||
|
|
||
|
/** Create a AAC audio encoder. Returns nullptr when failed. */
|
||
|
static OMXAudioEncoder* CreateAACEncoder();
|
||
|
|
||
|
/** Create a AMR audio encoder. Returns nullptr when failed. */
|
||
|
static OMXAudioEncoder* CreateAMRNBEncoder();
|
||
|
|
||
|
/** Create a EVRC audio encoder. Returns nullptr when failed. */
|
||
|
static OMXAudioEncoder* CreateEVRCEncoder();
|
||
|
|
||
|
/** Create a AVC/H.264 video encoder. Returns nullptr when failed. */
|
||
|
static OMXVideoEncoder* CreateAVCEncoder();
|
||
|
|
||
|
virtual ~OMXCodecWrapper();
|
||
|
|
||
|
/**
|
||
|
* Get the next available encoded data from MediaCodec. The data will be
|
||
|
* copied into aOutputBuf array, with its timestamp (in microseconds) in
|
||
|
* aOutputTimestamp.
|
||
|
* Wait at most aTimeout microseconds to dequeue a output buffer.
|
||
|
*/
|
||
|
nsresult GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
|
||
|
int64_t* aOutputTimestamp, int* aOutputFlags,
|
||
|
int64_t aTimeOut);
|
||
|
/*
|
||
|
* Get the codec type
|
||
|
*/
|
||
|
int GetCodecType() { return mCodecType; }
|
||
|
protected:
|
||
|
/**
|
||
|
* See whether the object has been initialized successfully and is ready to
|
||
|
* use.
|
||
|
*/
|
||
|
virtual bool IsValid() { return mCodec != nullptr; }
|
||
|
|
||
|
/**
|
||
|
* Construct codec specific configuration blob with given data aData generated
|
||
|
* by media codec and append it into aOutputBuf. Needed by MP4 container
|
||
|
* writer for generating decoder config box, or WebRTC for generating RTP
|
||
|
* packets. Returns OK if succeed.
|
||
|
*/
|
||
|
virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
|
||
|
ABuffer* aData) = 0;
|
||
|
|
||
|
/**
|
||
|
* Append encoded frame data generated by media codec (stored in aData and
|
||
|
* is aSize bytes long) into aOutputBuf. Subclasses can override this function
|
||
|
* to process the data for specific container writer.
|
||
|
*/
|
||
|
virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
|
||
|
const uint8_t* aData, size_t aSize)
|
||
|
{
|
||
|
aOutputBuf->AppendElements(aData, aSize);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Hide these. User should always use creator functions to get a media codec.
|
||
|
OMXCodecWrapper() = delete;
|
||
|
OMXCodecWrapper(const OMXCodecWrapper&) = delete;
|
||
|
OMXCodecWrapper& operator=(const OMXCodecWrapper&) = delete;
|
||
|
|
||
|
/**
|
||
|
* Create a media codec of given type. It will be a AVC/H.264 video encoder if
|
||
|
* aCodecType is CODEC_AVC_ENC, or AAC audio encoder if aCodecType is
|
||
|
* CODEC_AAC_ENC.
|
||
|
*/
|
||
|
OMXCodecWrapper(CodecType aCodecType);
|
||
|
|
||
|
// For subclasses to access hidden constructor and implementation details.
|
||
|
friend class OMXAudioEncoder;
|
||
|
friend class OMXVideoEncoder;
|
||
|
|
||
|
/**
|
||
|
* Start the media codec.
|
||
|
*/
|
||
|
status_t Start();
|
||
|
|
||
|
/**
|
||
|
* Stop the media codec.
|
||
|
*/
|
||
|
status_t Stop();
|
||
|
|
||
|
// The actual codec instance provided by libstagefright.
|
||
|
sp<MediaCodec> mCodec;
|
||
|
|
||
|
// A dedicate message loop with its own thread used by MediaCodec.
|
||
|
sp<ALooper> mLooper;
|
||
|
|
||
|
Vector<sp<ABuffer> > mInputBufs; // MediaCodec buffers to hold input data.
|
||
|
Vector<sp<ABuffer> > mOutputBufs; // MediaCodec buffers to hold output data.
|
||
|
|
||
|
int mCodecType;
|
||
|
bool mStarted; // Has MediaCodec been started?
|
||
|
bool mAMRCSDProvided;
|
||
|
bool mEVRCCSDProvided;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Audio encoder.
|
||
|
*/
|
||
|
class OMXAudioEncoder final : public OMXCodecWrapper
|
||
|
{
|
||
|
public:
|
||
|
/**
|
||
|
* Configure audio codec parameters and start media codec. It must be called
|
||
|
* before calling Encode() and GetNextEncodedFrame().
|
||
|
* aReSamplingRate = 0 means no resampler required
|
||
|
*/
|
||
|
nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate);
|
||
|
|
||
|
/**
|
||
|
* Encode 16-bit PCM audio samples stored in aSegment. To notify end of
|
||
|
* stream, set aInputFlags to BUFFER_EOS. Since encoder has limited buffers,
|
||
|
* this function might not be able to encode all chunks in one call, however
|
||
|
* it will remove chunks it consumes from aSegment.
|
||
|
* aSendEOS is the output to tell the caller EOS signal sent into MediaCodec
|
||
|
* because the signal might not be sent due to the dequeueInputBuffer timeout.
|
||
|
* And the value of aSendEOS won't be set to any default value, only set to
|
||
|
* true when EOS signal sent into MediaCodec.
|
||
|
*/
|
||
|
nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0,
|
||
|
bool* aSendEOS = nullptr);
|
||
|
|
||
|
~OMXAudioEncoder();
|
||
|
protected:
|
||
|
virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
|
||
|
ABuffer* aData) override;
|
||
|
private:
|
||
|
// Hide these. User should always use creator functions to get a media codec.
|
||
|
OMXAudioEncoder() = delete;
|
||
|
OMXAudioEncoder(const OMXAudioEncoder&) = delete;
|
||
|
OMXAudioEncoder& operator=(const OMXAudioEncoder&) = delete;
|
||
|
|
||
|
/**
|
||
|
* Create a audio codec. It will be a AAC encoder if aCodecType is
|
||
|
* CODEC_AAC_ENC.
|
||
|
*/
|
||
|
OMXAudioEncoder(CodecType aCodecType)
|
||
|
: OMXCodecWrapper(aCodecType)
|
||
|
, mResampler(nullptr)
|
||
|
, mChannels(0)
|
||
|
, mResamplingRatio(0)
|
||
|
, mTimestamp(0)
|
||
|
, mSampleDuration(0) {}
|
||
|
|
||
|
// For creator function to access hidden constructor.
|
||
|
friend class OMXCodecWrapper;
|
||
|
friend class InputBufferHelper;
|
||
|
|
||
|
/**
|
||
|
* If the input sample rate does not divide 48kHz evenly, the input data are
|
||
|
* resampled.
|
||
|
*/
|
||
|
SpeexResamplerState* mResampler;
|
||
|
// Number of audio channels.
|
||
|
size_t mChannels;
|
||
|
|
||
|
float mResamplingRatio;
|
||
|
// The total duration of audio samples that have been encoded in microseconds.
|
||
|
int64_t mTimestamp;
|
||
|
// Time per audio sample in microseconds.
|
||
|
int64_t mSampleDuration;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Video encoder.
|
||
|
*/
|
||
|
class OMXVideoEncoder final : public OMXCodecWrapper
|
||
|
{
|
||
|
public:
|
||
|
// Types of output blob format.
|
||
|
enum BlobFormat {
|
||
|
AVC_MP4, // MP4 file config descripter (defined in ISO/IEC 14496-15 5.2.4.1.1)
|
||
|
AVC_NAL // NAL (Network Abstract Layer) (defined in ITU-T H.264 7.4.1)
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Configure video codec parameters and start media codec. It must be called
|
||
|
* before calling Encode() and GetNextEncodedFrame().
|
||
|
* aBlobFormat specifies output blob format provided by encoder. It can be
|
||
|
* AVC_MP4 or AVC_NAL.
|
||
|
* Configure sets up most format value to values appropriate for camera use.
|
||
|
* ConfigureDirect lets the caller determine all the defaults.
|
||
|
*/
|
||
|
nsresult Configure(int aWidth, int aHeight, int aFrameRate,
|
||
|
BlobFormat aBlobFormat = BlobFormat::AVC_MP4);
|
||
|
nsresult ConfigureDirect(sp<AMessage>& aFormat,
|
||
|
BlobFormat aBlobFormat = BlobFormat::AVC_MP4);
|
||
|
|
||
|
/**
|
||
|
* Encode a aWidth pixels wide and aHeight pixels tall video frame of
|
||
|
* semi-planar YUV420 format stored in the buffer of aImage. aTimestamp gives
|
||
|
* the frame timestamp/presentation time (in microseconds). To notify end of
|
||
|
* stream, set aInputFlags to BUFFER_EOS.
|
||
|
* aSendEOS is the output to tell the caller EOS signal sent into MediaCodec
|
||
|
* because the signal might not be sent due to the dequeueInputBuffer timeout.
|
||
|
* And the value of aSendEOS won't be set to any default value, only set to
|
||
|
* true when EOS signal sent into MediaCodec.
|
||
|
*/
|
||
|
nsresult Encode(const mozilla::layers::Image* aImage, int aWidth, int aHeight,
|
||
|
int64_t aTimestamp, int aInputFlags = 0,
|
||
|
bool* aSendEOS = nullptr);
|
||
|
|
||
|
#if ANDROID_VERSION >= 18
|
||
|
/** Set encoding bitrate (in kbps). */
|
||
|
nsresult SetBitrate(int32_t aKbps);
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* Ask codec to generate an instantaneous decoding refresh (IDR) frame
|
||
|
* (defined in ISO/IEC 14496-10).
|
||
|
*/
|
||
|
nsresult RequestIDRFrame();
|
||
|
|
||
|
protected:
|
||
|
virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
|
||
|
ABuffer* aData) override;
|
||
|
|
||
|
// If configured to output MP4 format blob, AVC/H.264 encoder has to replace
|
||
|
// NAL unit start code with the unit length as specified in
|
||
|
// ISO/IEC 14496-15 5.2.3.
|
||
|
virtual void AppendFrame(nsTArray<uint8_t>* aOutputBuf,
|
||
|
const uint8_t* aData, size_t aSize) override;
|
||
|
|
||
|
private:
|
||
|
// Hide these. User should always use creator functions to get a media codec.
|
||
|
OMXVideoEncoder() = delete;
|
||
|
OMXVideoEncoder(const OMXVideoEncoder&) = delete;
|
||
|
OMXVideoEncoder& operator=(const OMXVideoEncoder&) = delete;
|
||
|
|
||
|
/**
|
||
|
* Create a video codec. It will be a AVC/H.264 encoder if aCodecType is
|
||
|
* CODEC_AVC_ENC.
|
||
|
*/
|
||
|
OMXVideoEncoder(CodecType aCodecType)
|
||
|
: OMXCodecWrapper(aCodecType)
|
||
|
, mWidth(0)
|
||
|
, mHeight(0)
|
||
|
, mBlobFormat(BlobFormat::AVC_MP4)
|
||
|
{}
|
||
|
|
||
|
// For creator function to access hidden constructor.
|
||
|
friend class OMXCodecWrapper;
|
||
|
|
||
|
int mWidth;
|
||
|
int mHeight;
|
||
|
BlobFormat mBlobFormat;
|
||
|
};
|
||
|
|
||
|
} // namespace android
|
||
|
|
||
|
#endif // OMXCodecWrapper_h_
|