Bug 959490 - [MediaEncoder] Support *.3gp with AMR-NB audio format on certificated application. r=roc

This commit is contained in:
Randy Lin 2014-03-19 14:52:45 +08:00
parent 68a17dc990
commit c9dd4c92fe
10 changed files with 288 additions and 86 deletions

View File

@ -16,7 +16,8 @@
#include "EncodedBufferCache.h"
#include "nsIDOMFile.h"
#include "mozilla/dom/BlobEvent.h"
#include "nsIPrincipal.h"
#include "nsMimeTypes.h"
#include "mozilla/dom/AudioStreamTrack.h"
#include "mozilla/dom/VideoStreamTrack.h"
@ -320,7 +321,19 @@ private:
// Allocate encoder and bind with union stream.
// At this stage, the API doesn't allow UA to choose the output mimeType format.
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
if (doc) {
doc->NodePrincipal()->GetAppStatus(&appStatus);
}
// Only allow certificated application can assign AUDIO_3GPP
if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP)) {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), aTrackTypes);
} else {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
}
if (!mEncoder) {
DoSessionEndTask(NS_ERROR_ABORT);
@ -579,7 +592,9 @@ MediaRecorder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
/* static */ already_AddRefed<MediaRecorder>
MediaRecorder::Constructor(const GlobalObject& aGlobal,
DOMMediaStream& aStream, ErrorResult& aRv)
DOMMediaStream& aStream,
const MediaRecorderOptions& aInitDict,
ErrorResult& aRv)
{
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
if (!sgo) {
@ -594,6 +609,7 @@ MediaRecorder::Constructor(const GlobalObject& aGlobal,
}
nsRefPtr<MediaRecorder> object = new MediaRecorder(aStream, ownerWindow);
object->SetMimeType(aInitDict.mMimeType);
return object.forget();
}

View File

@ -20,6 +20,7 @@ class EncodedBufferCache;
class MediaEncoder;
class ProcessedMediaStream;
class MediaInputPort;
struct MediaRecorderOptions;
namespace dom {
@ -75,7 +76,9 @@ public:
static already_AddRefed<MediaRecorder>
Constructor(const GlobalObject& aGlobal,
DOMMediaStream& aStream, ErrorResult& aRv);
DOMMediaStream& aStream,
const MediaRecorderOptions& aInitDict,
ErrorResult& aRv);
// EventHandler
IMPL_EVENT_HANDLER(dataavailable)

View File

@ -115,7 +115,7 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes)
(aMIMEType.EqualsLiteral(VIDEO_MP4) ||
(aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) {
if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK) {
audioEncoder = new OmxAudioTrackEncoder();
audioEncoder = new OmxAACAudioTrackEncoder();
NS_ENSURE_TRUE(audioEncoder, nullptr);
}
videoEncoder = new OmxVideoTrackEncoder();
@ -123,6 +123,14 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes)
NS_ENSURE_TRUE(writer, nullptr);
NS_ENSURE_TRUE(videoEncoder, nullptr);
mimeType = NS_LITERAL_STRING(VIDEO_MP4);
} else if (MediaEncoder::IsOMXEncoderEnabled() &&
(aMIMEType.EqualsLiteral(AUDIO_3GPP))) {
audioEncoder = new OmxAMRAudioTrackEncoder();
NS_ENSURE_TRUE(audioEncoder, nullptr);
writer = new ISOMediaWriter(aTrackTypes, ISOMediaWriter::TYPE_FRAG_3GP);
NS_ENSURE_TRUE(writer, nullptr);
mimeType = NS_LITERAL_STRING(AUDIO_3GPP);
}
#endif // MOZ_OMX_ENCODER
else if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled() &&

View File

@ -155,49 +155,6 @@ OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
return NS_OK;
}
nsresult
OmxAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
{
mChannels = aChannels;
mSamplingRate = aSamplingRate;
mEncoder = OMXCodecWrapper::CreateAACEncoder();
NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
nsresult rv = mEncoder->Configure(mChannels, mSamplingRate);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mInitialized = (rv == NS_OK);
mReentrantMonitor.NotifyAll();
return NS_OK;
}
already_AddRefed<TrackMetadataBase>
OmxAudioTrackEncoder::GetMetadata()
{
{
// Wait if mEncoder is not initialized nor is being canceled.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (!mCanceled && !mInitialized) {
mReentrantMonitor.Wait();
}
}
if (mCanceled || mEncodingComplete) {
return nullptr;
}
nsRefPtr<AACTrackMetadata> meta = new AACTrackMetadata();
meta->mChannels = mChannels;
meta->mSampleRate = mSamplingRate;
meta->mFrameSize = OMXCodecWrapper::kAACFrameSize;
meta->mFrameDuration = OMXCodecWrapper::kAACFrameDuration;
return meta.forget();
}
nsresult
OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
{
@ -218,8 +175,15 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
}
nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
audiodata->SetFrameType(isCSD ?
EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME);
if (mEncoder->GetCodecType() == OMXCodecWrapper::AAC_ENC) {
audiodata->SetFrameType(isCSD ?
EncodedFrame::AAC_CSD : EncodedFrame::AAC_AUDIO_FRAME);
} else if (mEncoder->GetCodecType() == OMXCodecWrapper::AMR_NB_ENC){
audiodata->SetFrameType(isCSD ?
EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME);
} else {
MOZ_ASSERT("audio codec not supported");
}
audiodata->SetTimeStamp(outTimeUs);
rv = audiodata->SwapInFrameData(frameData);
NS_ENSURE_SUCCESS(rv, rv);
@ -277,4 +241,82 @@ OmxAudioTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
return NS_OK;
}
nsresult
OmxAACAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
{
mChannels = aChannels;
mSamplingRate = aSamplingRate;
mEncoder = OMXCodecWrapper::CreateAACEncoder();
NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, mSamplingRate);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mInitialized = (rv == NS_OK);
mReentrantMonitor.NotifyAll();
return NS_OK;
}
already_AddRefed<TrackMetadataBase>
OmxAACAudioTrackEncoder::GetMetadata()
{
{
// Wait if mEncoder is not initialized nor is being canceled.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (!mCanceled && !mInitialized) {
mReentrantMonitor.Wait();
}
}
if (mCanceled || mEncodingComplete) {
return nullptr;
}
nsRefPtr<AACTrackMetadata> meta = new AACTrackMetadata();
meta->mChannels = mChannels;
meta->mSampleRate = mSamplingRate;
meta->mFrameSize = OMXCodecWrapper::kAACFrameSize;
meta->mFrameDuration = OMXCodecWrapper::kAACFrameDuration;
return meta.forget();
}
nsresult
OmxAMRAudioTrackEncoder::Init(int aChannels, int aSamplingRate)
{
mChannels = aChannels;
mSamplingRate = aSamplingRate;
mEncoder = OMXCodecWrapper::CreateAMRNBEncoder();
NS_ENSURE_TRUE(mEncoder, NS_ERROR_FAILURE);
nsresult rv = mEncoder->Configure(mChannels, mSamplingRate, AMR_NB_SAMPLERATE);
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mInitialized = (rv == NS_OK);
mReentrantMonitor.NotifyAll();
return NS_OK;
}
already_AddRefed<TrackMetadataBase>
OmxAMRAudioTrackEncoder::GetMetadata()
{
{
// Wait if mEncoder is not initialized nor is being canceled.
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
while (!mCanceled && !mInitialized) {
mReentrantMonitor.Wait();
}
}
if (mCanceled || mEncodingComplete) {
return nullptr;
}
nsRefPtr<AMRTrackMetadata> meta = new AMRTrackMetadata();
return meta.forget();
}
}

View File

@ -43,26 +43,54 @@ private:
nsAutoPtr<android::OMXVideoEncoder> mEncoder;
};
class OmxAudioTrackEncoder MOZ_FINAL : public AudioTrackEncoder
class OmxAudioTrackEncoder : public AudioTrackEncoder
{
public:
OmxAudioTrackEncoder()
: AudioTrackEncoder()
{}
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
already_AddRefed<TrackMetadataBase> GetMetadata() = 0;
nsresult GetEncodedTrack(EncodedFrameContainer& aData) MOZ_OVERRIDE;
protected:
nsresult Init(int aChannels, int aSamplingRate) MOZ_OVERRIDE;
nsresult Init(int aChannels, int aSamplingRate) = 0;
private:
// Append encoded frames to aContainer.
nsresult AppendEncodedFrames(EncodedFrameContainer& aContainer);
nsAutoPtr<android::OMXAudioEncoder> mEncoder;
};
class OmxAACAudioTrackEncoder MOZ_FINAL : public OmxAudioTrackEncoder
{
public:
OmxAACAudioTrackEncoder()
: OmxAudioTrackEncoder()
{}
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
protected:
nsresult Init(int aChannels, int aSamplingRate) MOZ_OVERRIDE;
};
class OmxAMRAudioTrackEncoder MOZ_FINAL : public OmxAudioTrackEncoder
{
public:
OmxAMRAudioTrackEncoder()
: OmxAudioTrackEncoder()
{}
enum {
AMR_NB_SAMPLERATE = 8000,
};
already_AddRefed<TrackMetadataBase> GetMetadata() MOZ_OVERRIDE;
protected:
nsresult Init(int aChannels, int aSamplingRate) MOZ_OVERRIDE;
};
}
#endif

View File

@ -167,6 +167,7 @@ nsresult
ISOControl::SetMetadata(TrackMetadataBase* aTrackMeta)
{
if (aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AAC ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AMR ||
aTrackMeta->GetKind() == TrackMetadataBase::METADATA_AVC) {
mMetaArray.AppendElement(aTrackMeta);
return NS_OK;
@ -178,7 +179,8 @@ nsresult
ISOControl::GetAudioMetadata(nsRefPtr<AudioTrackMetadata>& aAudMeta)
{
for (uint32_t i = 0; i < mMetaArray.Length() ; i++) {
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC) {
if (mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AAC ||
mMetaArray[i]->GetKind() == TrackMetadataBase::METADATA_AMR) {
aAudMeta = static_cast<AudioTrackMetadata*>(mMetaArray[i].get());
return NS_OK;
}

View File

@ -27,6 +27,8 @@ using namespace mozilla::layers;
#define ENCODER_CONFIG_I_FRAME_INTERVAL 1
// Wait up to 5ms for input buffers.
#define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll)
// AMR NB kbps
#define AMRNB_BITRATE 12200
#define CODEC_ERROR(args...) \
do { \
@ -45,6 +47,16 @@ OMXCodecWrapper::CreateAACEncoder()
return aac.forget();
}
OMXAudioEncoder*
OMXCodecWrapper::CreateAMRNBEncoder()
{
nsAutoPtr<OMXAudioEncoder> amr(new OMXAudioEncoder(CodecType::AMR_NB_ENC));
// Return the object only when media codec is valid.
NS_ENSURE_TRUE(amr->IsValid(), nullptr);
return amr.forget();
}
OMXVideoEncoder*
OMXCodecWrapper::CreateAVCEncoder()
{
@ -56,7 +68,9 @@ OMXCodecWrapper::CreateAVCEncoder()
}
OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
: mStarted(false)
: mCodecType(aCodecType)
, mStarted(false)
, mAMRCSDProvided(false)
{
ProcessState::self()->startThreadPool();
@ -65,6 +79,8 @@ OMXCodecWrapper::OMXCodecWrapper(CodecType aCodecType)
if (aCodecType == CodecType::AVC_ENC) {
mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_VIDEO_AVC, true);
} else if (aCodecType == CodecType::AMR_NB_ENC) {
mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AMR_NB, true);
} else if (aCodecType == CodecType::AAC_ENC) {
mCodec = MediaCodec::CreateByType(mLooper, MEDIA_MIMETYPE_AUDIO_AAC, true);
} else {
@ -380,28 +396,53 @@ void OMXVideoEncoder::AppendFrame(nsTArray<uint8_t>* aOutputBuf,
}
nsresult
OMXAudioEncoder::Configure(int aChannels, int aSamplingRate)
OMXAudioEncoder::Configure(int aChannels, int aInputSampleRate,
int aEncodedSampleRate)
{
MOZ_ASSERT(!mStarted);
NS_ENSURE_TRUE(aChannels > 0 && aSamplingRate > 0, NS_ERROR_INVALID_ARG);
NS_ENSURE_TRUE(aChannels > 0 && aInputSampleRate > 0 && aEncodedSampleRate >= 0,
NS_ERROR_INVALID_ARG);
if (aInputSampleRate != aEncodedSampleRate) {
int error;
mResampler = speex_resampler_init(aChannels,
aInputSampleRate,
aEncodedSampleRate,
SPEEX_RESAMPLER_QUALITY_DEFAULT,
&error);
if (error != RESAMPLER_ERR_SUCCESS) {
return NS_ERROR_FAILURE;
}
speex_resampler_skip_zeros(mResampler);
}
// Set up configuration parameters for AAC encoder.
sp<AMessage> format = new AMessage;
// Fixed values.
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
format->setInt32("bitrate", kAACBitrate);
format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
if (mCodecType == AAC_ENC) {
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
format->setInt32("aac-profile", OMX_AUDIO_AACObjectLC);
format->setInt32("bitrate", kAACBitrate);
format->setInt32("sample-rate", aInputSampleRate);
} else if (mCodecType == AMR_NB_ENC) {
format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
format->setInt32("bitrate", AMRNB_BITRATE);
format->setInt32("sample-rate", aEncodedSampleRate);
} else {
MOZ_ASSERT(false, "Can't support this codec type!!");
}
// Input values.
format->setInt32("channel-count", aChannels);
format->setInt32("sample-rate", aSamplingRate);
status_t result = mCodec->configure(format, nullptr, nullptr,
MediaCodec::CONFIGURE_FLAG_ENCODE);
NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
mChannels = aChannels;
mSampleDuration = 1000000 / aSamplingRate;
mSampleDuration = 1000000 / aInputSampleRate;
mResamplingRatio = aEncodedSampleRate > 0 ? 1.0 *
aEncodedSampleRate / aInputSampleRate : 1.0;
result = Start();
return result == OK ? NS_OK : NS_ERROR_FAILURE;
@ -474,6 +515,14 @@ private:
size_t mOffset;
};
OMXAudioEncoder::~OMXAudioEncoder()
{
if (mResampler) {
speex_resampler_destroy(mResampler);
mResampler = nullptr;
}
}
nsresult
OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
{
@ -495,16 +544,16 @@ OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
}
NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
size_t samplesCopied = 0; // Number of copied samples.
size_t sourceSamplesCopied = 0; // Number of copied samples.
if (numSamples > 0) {
// Copy input PCM data to input buffer until queue is empty.
AudioSegment::ChunkIterator iter(const_cast<AudioSegment&>(aSegment));
while (!iter.IsEnded()) {
AudioChunk chunk = *iter;
size_t samplesToCopy = chunk.GetDuration(); // Number of samples to copy.
size_t bytesToCopy = samplesToCopy * mChannels * sizeof(AudioDataValue);
size_t sourceSamplesToCopy = chunk.GetDuration(); // Number of samples to copy.
size_t bytesToCopy = sourceSamplesToCopy * mChannels *
sizeof(AudioDataValue) * mResamplingRatio;
if (bytesToCopy > buffer.AvailableSize()) {
// Not enough space left in input buffer. Send it to encoder and get a
// new one.
@ -515,32 +564,47 @@ OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
if (result == -EAGAIN) {
// All input buffers are full. Caller can try again later after
// consuming some output buffers.
aSegment.RemoveLeading(samplesCopied);
aSegment.RemoveLeading(sourceSamplesCopied);
return NS_OK;
}
mTimestamp += samplesCopied * mSampleDuration;
samplesCopied = 0;
mTimestamp += sourceSamplesCopied * mSampleDuration;
sourceSamplesCopied = 0;
NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
}
AudioDataValue* dst = reinterpret_cast<AudioDataValue*>(buffer.GetPointer());
uint32_t dstSamplesCopied = sourceSamplesToCopy;
if (!chunk.IsNull()) {
// Append the interleaved data to input buffer.
AudioTrackEncoder::InterleaveTrackData(chunk, samplesToCopy, mChannels,
dst);
if (mResampler) {
nsAutoTArray<AudioDataValue, 9600> pcm;
pcm.SetLength(bytesToCopy);
// Append the interleaved data to input buffer.
AudioTrackEncoder::InterleaveTrackData(chunk, sourceSamplesToCopy,
mChannels,
pcm.Elements());
uint32_t inframes = sourceSamplesToCopy;
short* in = reinterpret_cast<short*>(pcm.Elements());
speex_resampler_process_interleaved_int(mResampler, in, &inframes,
dst, &dstSamplesCopied);
} else {
AudioTrackEncoder::InterleaveTrackData(chunk, sourceSamplesToCopy,
mChannels,
dst);
dstSamplesCopied = sourceSamplesToCopy * mChannels;
}
} else {
// Silence.
memset(dst, 0, bytesToCopy);
memset(dst, 0, mResamplingRatio * sourceSamplesToCopy * sizeof(AudioDataValue));
}
samplesCopied += samplesToCopy;
buffer.IncreaseOffset(bytesToCopy);
sourceSamplesCopied += sourceSamplesToCopy;
buffer.IncreaseOffset(dstSamplesCopied * sizeof(AudioDataValue));
iter.Next();
}
if (samplesCopied > 0) {
aSegment.RemoveLeading(samplesCopied);
if (sourceSamplesCopied > 0) {
aSegment.RemoveLeading(sourceSamplesCopied);
}
} else if (aInputFlags & BUFFER_EOS) {
// No audio data left in segment but we still have to feed something to
@ -548,10 +612,10 @@ OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
size_t bytesToCopy = mChannels * sizeof(AudioDataValue);
memset(buffer.GetPointer(), 0, bytesToCopy);
buffer.IncreaseOffset(bytesToCopy);
samplesCopied = 1;
sourceSamplesCopied = 1;
}
if (samplesCopied > 0) {
if (sourceSamplesCopied > 0) {
int flags = aInputFlags;
if (aSegment.GetDuration() > 0) {
// Don't signal EOS until source segment is empty.
@ -560,7 +624,7 @@ OMXAudioEncoder::Encode(AudioSegment& aSegment, int aInputFlags)
result = buffer.Enqueue(mTimestamp, flags);
NS_ENSURE_TRUE(result == OK, NS_ERROR_FAILURE);
mTimestamp += samplesCopied * mSampleDuration;
mTimestamp += sourceSamplesCopied * mSampleDuration;
}
return NS_OK;
@ -663,6 +727,20 @@ OMXCodecWrapper::GetNextEncodedFrame(nsTArray<uint8_t>* aOutputBuf,
mCodec->releaseOutputBuffer(index);
return NS_ERROR_FAILURE;
}
} else if ((mCodecType == AMR_NB_ENC) && !mAMRCSDProvided){
// OMX AMR codec won't provide csd data, need to generate a fake one.
nsRefPtr<EncodedFrame> audiodata = new EncodedFrame();
// Decoder config descriptor
const uint8_t decConfig[] = {
0x0, 0x0, 0x0, 0x0, // vendor: 4 bytes
0x0, // decoder version
0x83, 0xFF, // mode set: all enabled
0x00, // mode change period
0x01, // frames per sample
};
aOutputBuf->AppendElements(decConfig, sizeof(decConfig));
outFlags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
mAMRCSDProvided = true;
} else {
AppendFrame(aOutputBuf, omxBuf->data(), omxBuf->size());
}

View File

@ -15,6 +15,8 @@
#include "GonkNativeWindow.h"
#include "GonkNativeWindowClient.h"
#include <speex/speex_resampler.h>
namespace android {
class OMXAudioEncoder;
@ -53,6 +55,7 @@ public:
// Codec types.
enum CodecType {
AAC_ENC, // AAC encoder.
AMR_NB_ENC, // AMR_NB encoder.
AVC_ENC, // AVC/H.264 encoder.
TYPE_COUNT
};
@ -83,6 +86,9 @@ public:
/** 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 AVC/H.264 video encoder. Returns nullptr when failed. */
static OMXVideoEncoder* CreateAVCEncoder();
@ -97,7 +103,10 @@ public:
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
@ -160,7 +169,9 @@ private:
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;
};
/**
@ -172,8 +183,9 @@ 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 aSampleRate);
nsresult Configure(int aChannelCount, int aInputSampleRate, int aEncodedSampleRate);
/**
* Encode 16-bit PCM audio samples stored in aSegment. To notify end of
@ -183,10 +195,10 @@ public:
*/
nsresult Encode(mozilla::AudioSegment& aSegment, int aInputFlags = 0);
~OMXAudioEncoder();
protected:
virtual status_t AppendDecoderConfig(nsTArray<uint8_t>* aOutputBuf,
ABuffer* aData) MOZ_OVERRIDE;
private:
// Hide these. User should always use creator functions to get a media codec.
OMXAudioEncoder() MOZ_DELETE;
@ -199,15 +211,24 @@ private:
*/
OMXAudioEncoder(CodecType aCodecType)
: OMXCodecWrapper(aCodecType)
, mResampler(nullptr)
, mChannels(0)
, mTimestamp(0)
, mSampleDuration(0) {}
, mSampleDuration(0)
, mResamplingRatio(0) {}
// For creator function to access hidden constructor.
friend class OMXCodecWrapper;
/**
* 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.

View File

@ -12,7 +12,7 @@
enum RecordingState { "inactive", "recording", "paused" };
[Constructor(MediaStream stream)]
[Constructor(MediaStream stream, optional MediaRecorderOptions options)]
interface MediaRecorder : EventTarget {
readonly attribute MediaStream stream;
@ -45,3 +45,6 @@ interface MediaRecorder : EventTarget {
void requestData();
};
dictionary MediaRecorderOptions {
DOMString mimeType = ""; // Default encoding mimeType.
};

View File

@ -79,6 +79,7 @@
#define AUDIO_MP3 "audio/mpeg"
#define AUDIO_MP4 "audio/mp4"
#define AUDIO_AMR "audio/amr"
#define AUDIO_3GPP "audio/3gpp"
#define AUDIO_MIDI "audio/x-midi"
#define BINARY_OCTET_STREAM "binary/octet-stream"