am 8d30b2d2: Merge "Support AAC recording" into kraken
This commit is contained in:
@@ -36,6 +36,7 @@
|
|||||||
#include <utils/Errors.h>
|
#include <utils/Errors.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
|
|
||||||
@@ -149,9 +150,149 @@ status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t leng
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t StagefrightRecorder::setParameters(const String8 ¶ms) {
|
// Attempt to parse an int64 literal optionally surrounded by whitespace,
|
||||||
mParams = params;
|
// returns true on success, false otherwise.
|
||||||
|
static bool safe_strtoi64(const char *s, int32_t *val) {
|
||||||
|
char *end;
|
||||||
|
*val = static_cast<int32_t>(strtoll(s, &end, 10));
|
||||||
|
|
||||||
|
if (end == s || errno == ERANGE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip trailing whitespace
|
||||||
|
while (isspace(*end)) {
|
||||||
|
++end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For a successful return, the string must contain nothing but a valid
|
||||||
|
// int64 literal optionally surrounded by whitespace.
|
||||||
|
|
||||||
|
return *end == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim both leading and trailing whitespace from the given string.
|
||||||
|
static void TrimString(String8 *s) {
|
||||||
|
size_t num_bytes = s->bytes();
|
||||||
|
const char *data = s->string();
|
||||||
|
|
||||||
|
size_t leading_space = 0;
|
||||||
|
while (leading_space < num_bytes && isspace(data[leading_space])) {
|
||||||
|
++leading_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = num_bytes;
|
||||||
|
while (i > leading_space && isspace(data[i - 1])) {
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->setTo(String8(&data[leading_space], i - leading_space));
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
|
||||||
|
LOGV("setParamAudioSamplingRate: %d", sampleRate);
|
||||||
|
mSampleRate = sampleRate;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
|
||||||
|
LOGV("setParamAudioNumberOfChannels: %d", channels);
|
||||||
|
mAudioChannels = channels;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
|
||||||
|
LOGV("setParamAudioEncodingBitRate: %d", bitRate);
|
||||||
|
mAudioBitRate = bitRate;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
|
||||||
|
LOGV("setParamVideoEncodingBitRate: %d", bitRate);
|
||||||
|
mVideoBitRate = bitRate;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setMaxDurationOrFileSize(int32_t limit, bool limit_is_duration) {
|
||||||
|
LOGV("setMaxDurationOrFileSize: limit (%d) for %s",
|
||||||
|
limit, limit_is_duration?"duration":"size");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setParameter(
|
||||||
|
const String8 &key, const String8 &value) {
|
||||||
|
LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
|
||||||
|
if (key == "max-duration") {
|
||||||
|
int32_t max_duration_ms;
|
||||||
|
if (safe_strtoi64(value.string(), &max_duration_ms)) {
|
||||||
|
return setMaxDurationOrFileSize(
|
||||||
|
max_duration_ms, true /* limit_is_duration */);
|
||||||
|
}
|
||||||
|
} else if (key == "max-filesize") {
|
||||||
|
int32_t max_filesize_bytes;
|
||||||
|
if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
|
||||||
|
return setMaxDurationOrFileSize(
|
||||||
|
max_filesize_bytes, false /* limit is filesize */);
|
||||||
|
}
|
||||||
|
} else if (key == "audio-param-sampling-rate") {
|
||||||
|
int32_t sampling_rate;
|
||||||
|
if (safe_strtoi64(value.string(), &sampling_rate)) {
|
||||||
|
return setParamAudioSamplingRate(sampling_rate);
|
||||||
|
}
|
||||||
|
} else if (key == "audio-param-number-of-channels") {
|
||||||
|
int32_t number_of_channels;
|
||||||
|
if (safe_strtoi64(value.string(), &number_of_channels)) {
|
||||||
|
return setParamAudioNumberOfChannels(number_of_channels);
|
||||||
|
}
|
||||||
|
} else if (key == "audio-param-encoding-bitrate") {
|
||||||
|
int32_t audio_bitrate;
|
||||||
|
if (safe_strtoi64(value.string(), &audio_bitrate)) {
|
||||||
|
return setParamAudioEncodingBitRate(audio_bitrate);
|
||||||
|
}
|
||||||
|
} else if (key == "video-param-encoding-bitrate") {
|
||||||
|
int32_t video_bitrate;
|
||||||
|
if (safe_strtoi64(value.string(), &video_bitrate)) {
|
||||||
|
return setParamVideoEncodingBitRate(video_bitrate);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOGE("setParameter: failed to find key %s", key.string());
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t StagefrightRecorder::setParameters(const String8 ¶ms) {
|
||||||
|
LOGV("setParameters: %s", params.string());
|
||||||
|
const char *cparams = params.string();
|
||||||
|
const char *key_start = cparams;
|
||||||
|
for (;;) {
|
||||||
|
const char *equal_pos = strchr(key_start, '=');
|
||||||
|
if (equal_pos == NULL) {
|
||||||
|
LOGE("Parameters %s miss a value", cparams);
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
String8 key(key_start, equal_pos - key_start);
|
||||||
|
TrimString(&key);
|
||||||
|
if (key.length() == 0) {
|
||||||
|
LOGE("Parameters %s contains an empty key", cparams);
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
const char *value_start = equal_pos + 1;
|
||||||
|
const char *semicolon_pos = strchr(value_start, ';');
|
||||||
|
String8 value;
|
||||||
|
if (semicolon_pos == NULL) {
|
||||||
|
value.setTo(value_start);
|
||||||
|
} else {
|
||||||
|
value.setTo(value_start, semicolon_pos - value_start);
|
||||||
|
}
|
||||||
|
if (setParameter(key, value) != OK) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
if (semicolon_pos == NULL) {
|
||||||
|
break; // Reaches the end
|
||||||
|
}
|
||||||
|
key_start = semicolon_pos + 1;
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,35 +326,46 @@ status_t StagefrightRecorder::start() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<MediaSource> StagefrightRecorder::createAMRAudioSource() {
|
sp<MediaSource> StagefrightRecorder::createAudioSource() {
|
||||||
uint32_t sampleRate =
|
|
||||||
mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000;
|
|
||||||
|
|
||||||
sp<AudioSource> audioSource =
|
sp<AudioSource> audioSource =
|
||||||
new AudioSource(
|
new AudioSource(
|
||||||
mAudioSource,
|
mAudioSource,
|
||||||
sampleRate,
|
mSampleRate,
|
||||||
AudioSystem::CHANNEL_IN_MONO);
|
AudioSystem::CHANNEL_IN_MONO);
|
||||||
|
|
||||||
status_t err = audioSource->initCheck();
|
status_t err = audioSource->initCheck();
|
||||||
|
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
|
LOGE("audio source is not initialized");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<MetaData> encMeta = new MetaData;
|
sp<MetaData> encMeta = new MetaData;
|
||||||
encMeta->setCString(
|
const char *mime;
|
||||||
kKeyMIMEType,
|
switch (mAudioEncoder) {
|
||||||
mAudioEncoder == AUDIO_ENCODER_AMR_NB
|
case AUDIO_ENCODER_AMR_NB:
|
||||||
? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB);
|
case AUDIO_ENCODER_DEFAULT:
|
||||||
|
mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
|
||||||
|
break;
|
||||||
|
case AUDIO_ENCODER_AMR_WB:
|
||||||
|
mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
|
||||||
|
break;
|
||||||
|
case AUDIO_ENCODER_AAC:
|
||||||
|
mime = MEDIA_MIMETYPE_AUDIO_AAC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGE("Unknown audio encoder: %d", mAudioEncoder);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
encMeta->setCString(kKeyMIMEType, mime);
|
||||||
|
|
||||||
int32_t maxInputSize;
|
int32_t maxInputSize;
|
||||||
CHECK(audioSource->getFormat()->findInt32(
|
CHECK(audioSource->getFormat()->findInt32(
|
||||||
kKeyMaxInputSize, &maxInputSize));
|
kKeyMaxInputSize, &maxInputSize));
|
||||||
|
|
||||||
encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
|
encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
|
||||||
encMeta->setInt32(kKeyChannelCount, 1);
|
encMeta->setInt32(kKeyChannelCount, mAudioChannels);
|
||||||
encMeta->setInt32(kKeySampleRate, sampleRate);
|
encMeta->setInt32(kKeySampleRate, mSampleRate);
|
||||||
|
|
||||||
OMXClient client;
|
OMXClient client;
|
||||||
CHECK_EQ(client.connect(), OK);
|
CHECK_EQ(client.connect(), OK);
|
||||||
@@ -240,7 +392,7 @@ status_t StagefrightRecorder::startAMRRecording() {
|
|||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp<MediaSource> audioEncoder = createAMRAudioSource();
|
sp<MediaSource> audioEncoder = createAudioSource();
|
||||||
|
|
||||||
if (audioEncoder == NULL) {
|
if (audioEncoder == NULL) {
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
@@ -257,6 +409,26 @@ status_t StagefrightRecorder::startAMRRecording() {
|
|||||||
status_t StagefrightRecorder::startMPEG4Recording() {
|
status_t StagefrightRecorder::startMPEG4Recording() {
|
||||||
mWriter = new MPEG4Writer(dup(mOutputFd));
|
mWriter = new MPEG4Writer(dup(mOutputFd));
|
||||||
|
|
||||||
|
// Add audio source first if it exists
|
||||||
|
if (mAudioSource != AUDIO_SOURCE_LIST_END) {
|
||||||
|
sp<MediaSource> audioEncoder;
|
||||||
|
switch(mAudioEncoder) {
|
||||||
|
case AUDIO_ENCODER_AMR_NB:
|
||||||
|
case AUDIO_ENCODER_AMR_WB:
|
||||||
|
case AUDIO_ENCODER_AAC:
|
||||||
|
audioEncoder = createAudioSource();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGE("Unsupported audio encoder: %d", mAudioEncoder);
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioEncoder == NULL) {
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWriter->addSource(audioEncoder);
|
||||||
|
}
|
||||||
if (mVideoSource == VIDEO_SOURCE_DEFAULT
|
if (mVideoSource == VIDEO_SOURCE_DEFAULT
|
||||||
|| mVideoSource == VIDEO_SOURCE_CAMERA) {
|
|| mVideoSource == VIDEO_SOURCE_CAMERA) {
|
||||||
CHECK(mCamera != NULL);
|
CHECK(mCamera != NULL);
|
||||||
@@ -308,16 +480,6 @@ status_t StagefrightRecorder::startMPEG4Recording() {
|
|||||||
mWriter->addSource(encoder);
|
mWriter->addSource(encoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAudioSource != AUDIO_SOURCE_LIST_END) {
|
|
||||||
sp<MediaSource> audioEncoder = createAMRAudioSource();
|
|
||||||
|
|
||||||
if (audioEncoder == NULL) {
|
|
||||||
return UNKNOWN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
mWriter->addSource(audioEncoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
mWriter->start();
|
mWriter->start();
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -353,14 +515,22 @@ status_t StagefrightRecorder::close() {
|
|||||||
status_t StagefrightRecorder::reset() {
|
status_t StagefrightRecorder::reset() {
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
|
// No audio or video source by default
|
||||||
mAudioSource = AUDIO_SOURCE_LIST_END;
|
mAudioSource = AUDIO_SOURCE_LIST_END;
|
||||||
mVideoSource = VIDEO_SOURCE_LIST_END;
|
mVideoSource = VIDEO_SOURCE_LIST_END;
|
||||||
mOutputFormat = OUTPUT_FORMAT_LIST_END;
|
|
||||||
mAudioEncoder = AUDIO_ENCODER_LIST_END;
|
// Default parameters
|
||||||
mVideoEncoder = VIDEO_ENCODER_LIST_END;
|
mOutputFormat = OUTPUT_FORMAT_THREE_GPP;
|
||||||
mVideoWidth = -1;
|
mAudioEncoder = AUDIO_ENCODER_AMR_NB;
|
||||||
mVideoHeight = -1;
|
mVideoEncoder = VIDEO_ENCODER_H263;
|
||||||
mFrameRate = -1;
|
mVideoWidth = 176;
|
||||||
|
mVideoHeight = 144;
|
||||||
|
mFrameRate = 20;
|
||||||
|
mVideoBitRate = 192000;
|
||||||
|
mSampleRate = 8000;
|
||||||
|
mAudioChannels = 1;
|
||||||
|
mAudioBitRate = 12200;
|
||||||
|
|
||||||
mOutputFd = -1;
|
mOutputFd = -1;
|
||||||
mFlags = 0;
|
mFlags = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -68,15 +68,26 @@ private:
|
|||||||
output_format mOutputFormat;
|
output_format mOutputFormat;
|
||||||
audio_encoder mAudioEncoder;
|
audio_encoder mAudioEncoder;
|
||||||
video_encoder mVideoEncoder;
|
video_encoder mVideoEncoder;
|
||||||
int mVideoWidth, mVideoHeight;
|
int32_t mVideoWidth, mVideoHeight;
|
||||||
int mFrameRate;
|
int32_t mFrameRate;
|
||||||
|
int32_t mVideoBitRate;
|
||||||
|
int32_t mAudioBitRate;
|
||||||
|
int32_t mAudioChannels;
|
||||||
|
int32_t mSampleRate;
|
||||||
|
|
||||||
String8 mParams;
|
String8 mParams;
|
||||||
int mOutputFd;
|
int mOutputFd;
|
||||||
int32_t mFlags;
|
int32_t mFlags;
|
||||||
|
|
||||||
status_t startMPEG4Recording();
|
status_t startMPEG4Recording();
|
||||||
status_t startAMRRecording();
|
status_t startAMRRecording();
|
||||||
sp<MediaSource> createAMRAudioSource();
|
sp<MediaSource> createAudioSource();
|
||||||
|
status_t setParameter(const String8 &key, const String8 &value);
|
||||||
|
status_t setParamVideoEncodingBitRate(int32_t bitRate);
|
||||||
|
status_t setParamAudioEncodingBitRate(int32_t bitRate);
|
||||||
|
status_t setParamAudioNumberOfChannels(int32_t channles);
|
||||||
|
status_t setParamAudioSamplingRate(int32_t sampleRate);
|
||||||
|
status_t setMaxDurationOrFileSize(int32_t limit, bool limit_is_duration);
|
||||||
|
|
||||||
StagefrightRecorder(const StagefrightRecorder &);
|
StagefrightRecorder(const StagefrightRecorder &);
|
||||||
StagefrightRecorder &operator=(const StagefrightRecorder &);
|
StagefrightRecorder &operator=(const StagefrightRecorder &);
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
#define LOG_TAG "AudioSource"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
#include <media/stagefright/AudioSource.h>
|
#include <media/stagefright/AudioSource.h>
|
||||||
|
|
||||||
#include <media/AudioRecord.h>
|
#include <media/AudioRecord.h>
|
||||||
|
|||||||
@@ -14,6 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//#define LOG_NDEBUG 0
|
||||||
|
#define LOG_TAG "MPEG4Writer"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -58,6 +62,8 @@ private:
|
|||||||
};
|
};
|
||||||
List<SampleInfo> mSampleInfos;
|
List<SampleInfo> mSampleInfos;
|
||||||
|
|
||||||
|
List<int32_t> mStssTableEntries;
|
||||||
|
|
||||||
void *mCodecSpecificData;
|
void *mCodecSpecificData;
|
||||||
size_t mCodecSpecificDataSize;
|
size_t mCodecSpecificDataSize;
|
||||||
bool mGotAllCodecSpecificData;
|
bool mGotAllCodecSpecificData;
|
||||||
@@ -522,7 +528,8 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
sp<MetaData> meta = mSource->getFormat();
|
sp<MetaData> meta = mSource->getFormat();
|
||||||
const char *mime;
|
const char *mime;
|
||||||
meta->findCString(kKeyMIMEType, &mime);
|
meta->findCString(kKeyMIMEType, &mime);
|
||||||
bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
|
bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
|
||||||
|
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
|
||||||
bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
|
bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
|
||||||
int32_t count = 0;
|
int32_t count = 0;
|
||||||
|
|
||||||
@@ -668,6 +675,9 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
|
|
||||||
info.offset = offset;
|
info.offset = offset;
|
||||||
|
|
||||||
|
|
||||||
|
bool is_audio = !strncasecmp(mime, "audio/", 6);
|
||||||
|
|
||||||
int64_t timestampUs;
|
int64_t timestampUs;
|
||||||
CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs));
|
CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs));
|
||||||
|
|
||||||
@@ -680,6 +690,12 @@ void MPEG4Writer::Track::threadEntry() {
|
|||||||
|
|
||||||
mSampleInfos.push_back(info);
|
mSampleInfos.push_back(info);
|
||||||
|
|
||||||
|
int32_t isSync = false;
|
||||||
|
buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync);
|
||||||
|
if (isSync) {
|
||||||
|
mStssTableEntries.push_back(mSampleInfos.size());
|
||||||
|
}
|
||||||
|
// Our timestamp is in ms.
|
||||||
buffer->release();
|
buffer->release();
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
}
|
}
|
||||||
@@ -735,8 +751,8 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
success = success && mMeta->findInt32(kKeyHeight, &height);
|
success = success && mMeta->findInt32(kKeyHeight, &height);
|
||||||
CHECK(success);
|
CHECK(success);
|
||||||
|
|
||||||
mOwner->writeInt32(width);
|
mOwner->writeInt32(width << 16); // 32-bit fixed-point value
|
||||||
mOwner->writeInt32(height);
|
mOwner->writeInt32(height << 16); // 32-bit fixed-point value
|
||||||
}
|
}
|
||||||
mOwner->endBox(); // tkhd
|
mOwner->endBox(); // tkhd
|
||||||
|
|
||||||
@@ -754,26 +770,15 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
|
|
||||||
mOwner->beginBox("hdlr");
|
mOwner->beginBox("hdlr");
|
||||||
mOwner->writeInt32(0); // version=0, flags=0
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
mOwner->writeInt32(0); // predefined
|
mOwner->writeInt32(0); // component type: should be mhlr
|
||||||
mOwner->writeFourcc(is_audio ? "soun" : "vide");
|
mOwner->writeFourcc(is_audio ? "soun" : "vide"); // component subtype
|
||||||
mOwner->writeInt32(0); // reserved
|
mOwner->writeInt32(0); // reserved
|
||||||
mOwner->writeInt32(0); // reserved
|
mOwner->writeInt32(0); // reserved
|
||||||
mOwner->writeInt32(0); // reserved
|
mOwner->writeInt32(0); // reserved
|
||||||
mOwner->writeCString(""); // name
|
mOwner->writeCString("SoundHandler"); // name
|
||||||
mOwner->endBox();
|
mOwner->endBox();
|
||||||
|
|
||||||
mOwner->beginBox("minf");
|
mOwner->beginBox("minf");
|
||||||
|
|
||||||
mOwner->beginBox("dinf");
|
|
||||||
mOwner->beginBox("dref");
|
|
||||||
mOwner->writeInt32(0); // version=0, flags=0
|
|
||||||
mOwner->writeInt32(1);
|
|
||||||
mOwner->beginBox("url ");
|
|
||||||
mOwner->writeInt32(1); // version=0, flags=1
|
|
||||||
mOwner->endBox(); // url
|
|
||||||
mOwner->endBox(); // dref
|
|
||||||
mOwner->endBox(); // dinf
|
|
||||||
|
|
||||||
if (is_audio) {
|
if (is_audio) {
|
||||||
mOwner->beginBox("smhd");
|
mOwner->beginBox("smhd");
|
||||||
mOwner->writeInt32(0); // version=0, flags=0
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
@@ -789,7 +794,18 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
mOwner->writeInt16(0);
|
mOwner->writeInt16(0);
|
||||||
mOwner->endBox();
|
mOwner->endBox();
|
||||||
}
|
}
|
||||||
mOwner->endBox(); // minf
|
|
||||||
|
mOwner->beginBox("dinf");
|
||||||
|
mOwner->beginBox("dref");
|
||||||
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
|
mOwner->writeInt32(1);
|
||||||
|
mOwner->beginBox("url ");
|
||||||
|
mOwner->writeInt32(1); // version=0, flags=1
|
||||||
|
mOwner->endBox(); // url
|
||||||
|
mOwner->endBox(); // dref
|
||||||
|
mOwner->endBox(); // dinf
|
||||||
|
|
||||||
|
mOwner->endBox(); // minf
|
||||||
|
|
||||||
mOwner->beginBox("stbl");
|
mOwner->beginBox("stbl");
|
||||||
|
|
||||||
@@ -802,6 +818,8 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
fourcc = "samr";
|
fourcc = "samr";
|
||||||
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
|
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
|
||||||
fourcc = "sawb";
|
fourcc = "sawb";
|
||||||
|
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
|
||||||
|
fourcc = "mp4a";
|
||||||
} else {
|
} else {
|
||||||
LOGE("Unknown mime type '%s'.", mime);
|
LOGE("Unknown mime type '%s'.", mime);
|
||||||
CHECK(!"should not be here, unknown mime type.");
|
CHECK(!"should not be here, unknown mime type.");
|
||||||
@@ -810,10 +828,12 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
mOwner->beginBox(fourcc); // audio format
|
mOwner->beginBox(fourcc); // audio format
|
||||||
mOwner->writeInt32(0); // reserved
|
mOwner->writeInt32(0); // reserved
|
||||||
mOwner->writeInt16(0); // reserved
|
mOwner->writeInt16(0); // reserved
|
||||||
mOwner->writeInt16(0); // data ref index
|
mOwner->writeInt16(0x1); // data ref index
|
||||||
mOwner->writeInt32(0); // reserved
|
mOwner->writeInt32(0); // reserved
|
||||||
mOwner->writeInt32(0); // reserved
|
mOwner->writeInt32(0); // reserved
|
||||||
mOwner->writeInt16(2); // channel count
|
int32_t nChannels;
|
||||||
|
CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
|
||||||
|
mOwner->writeInt16(nChannels); // channel count
|
||||||
mOwner->writeInt16(16); // sample size
|
mOwner->writeInt16(16); // sample size
|
||||||
mOwner->writeInt16(0); // predefined
|
mOwner->writeInt16(0); // predefined
|
||||||
mOwner->writeInt16(0); // reserved
|
mOwner->writeInt16(0); // reserved
|
||||||
@@ -823,6 +843,38 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
CHECK(success);
|
CHECK(success);
|
||||||
|
|
||||||
mOwner->writeInt32(samplerate << 16);
|
mOwner->writeInt32(samplerate << 16);
|
||||||
|
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
|
||||||
|
mOwner->beginBox("esds");
|
||||||
|
|
||||||
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
|
mOwner->writeInt8(0x03); // ES_DescrTag
|
||||||
|
mOwner->writeInt8(23 + mCodecSpecificDataSize);
|
||||||
|
mOwner->writeInt16(0x0000);// ES_ID
|
||||||
|
mOwner->writeInt8(0x00);
|
||||||
|
|
||||||
|
mOwner->writeInt8(0x04); // DecoderConfigDescrTag
|
||||||
|
mOwner->writeInt8(15 + mCodecSpecificDataSize);
|
||||||
|
mOwner->writeInt8(0x40); // objectTypeIndication ISO/IEC 14492-2
|
||||||
|
mOwner->writeInt8(0x15); // streamType AudioStream
|
||||||
|
|
||||||
|
mOwner->writeInt16(0x03); // XXX
|
||||||
|
mOwner->writeInt8(0x00); // buffer size 24-bit
|
||||||
|
mOwner->writeInt32(96000); // max bit rate
|
||||||
|
mOwner->writeInt32(96000); // avg bit rate
|
||||||
|
|
||||||
|
mOwner->writeInt8(0x05); // DecoderSpecificInfoTag
|
||||||
|
mOwner->writeInt8(mCodecSpecificDataSize);
|
||||||
|
mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
|
||||||
|
|
||||||
|
static const uint8_t kData2[] = {
|
||||||
|
0x06, // SLConfigDescriptorTag
|
||||||
|
0x01,
|
||||||
|
0x02
|
||||||
|
};
|
||||||
|
mOwner->write(kData2, sizeof(kData2));
|
||||||
|
|
||||||
|
mOwner->endBox(); // esds
|
||||||
|
}
|
||||||
mOwner->endBox();
|
mOwner->endBox();
|
||||||
} else {
|
} else {
|
||||||
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
|
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
|
||||||
@@ -883,7 +935,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
0x00, 0x03, 0xe8, 0x00
|
0x00, 0x03, 0xe8, 0x00
|
||||||
};
|
};
|
||||||
mOwner->write(kData, sizeof(kData));
|
mOwner->write(kData, sizeof(kData));
|
||||||
|
|
||||||
mOwner->writeInt8(0x05); // DecoderSpecificInfoTag
|
mOwner->writeInt8(0x05); // DecoderSpecificInfoTag
|
||||||
|
|
||||||
mOwner->writeInt8(mCodecSpecificDataSize);
|
mOwner->writeInt8(mCodecSpecificDataSize);
|
||||||
@@ -943,6 +995,17 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
|
|
||||||
mOwner->endBox(); // stts
|
mOwner->endBox(); // stts
|
||||||
|
|
||||||
|
if (!is_audio) {
|
||||||
|
mOwner->beginBox("stss");
|
||||||
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
|
mOwner->writeInt32(mStssTableEntries.size()); // number of sync frames
|
||||||
|
for (List<int32_t>::iterator it = mStssTableEntries.begin();
|
||||||
|
it != mStssTableEntries.end(); ++it) {
|
||||||
|
mOwner->writeInt32(*it);
|
||||||
|
}
|
||||||
|
mOwner->endBox(); // stss
|
||||||
|
}
|
||||||
|
|
||||||
mOwner->beginBox("stsz");
|
mOwner->beginBox("stsz");
|
||||||
mOwner->writeInt32(0); // version=0, flags=0
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
mOwner->writeInt32(0); // default sample size
|
mOwner->writeInt32(0); // default sample size
|
||||||
@@ -969,7 +1032,7 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
|
|||||||
mOwner->writeInt32(0); // version=0, flags=0
|
mOwner->writeInt32(0); // version=0, flags=0
|
||||||
mOwner->writeInt32(mSampleInfos.size());
|
mOwner->writeInt32(mSampleInfos.size());
|
||||||
for (List<SampleInfo>::iterator it = mSampleInfos.begin();
|
for (List<SampleInfo>::iterator it = mSampleInfos.begin();
|
||||||
it != mSampleInfos.end(); ++it, ++n) {
|
it != mSampleInfos.end(); ++it) {
|
||||||
mOwner->writeInt64((*it).offset);
|
mOwner->writeInt64((*it).offset);
|
||||||
}
|
}
|
||||||
mOwner->endBox(); // co64
|
mOwner->endBox(); // co64
|
||||||
|
|||||||
@@ -520,6 +520,7 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
|
|||||||
|
|
||||||
setAACFormat(numChannels, sampleRate);
|
setAACFormat(numChannels, sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncasecmp(mMIME, "video/", 6)) {
|
if (!strncasecmp(mMIME, "video/", 6)) {
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
bool success = meta->findInt32(kKeyWidth, &width);
|
bool success = meta->findInt32(kKeyWidth, &width);
|
||||||
@@ -567,7 +568,8 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(mComponentName, "OMX.TI.AMR.encode")
|
if (!strcmp(mComponentName, "OMX.TI.AMR.encode")
|
||||||
|| !strcmp(mComponentName, "OMX.TI.WBAMR.encode")) {
|
|| !strcmp(mComponentName, "OMX.TI.WBAMR.encode")
|
||||||
|
|| !strcmp(mComponentName, "OMX.TI.AAC.encode")) {
|
||||||
setMinBufferSize(kPortIndexOutput, 8192); // XXX
|
setMinBufferSize(kPortIndexOutput, 8192); // XXX
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,7 +710,7 @@ void OMXCodec::setVideoInputFormat(
|
|||||||
|
|
||||||
OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
|
OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
|
||||||
if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
|
if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
|
||||||
colorFormat = OMX_COLOR_FormatYUV420Planar;
|
colorFormat = OMX_COLOR_FormatYCbYCr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2127,11 +2129,24 @@ void OMXCodec::setState(State newState) {
|
|||||||
|
|
||||||
void OMXCodec::setRawAudioFormat(
|
void OMXCodec::setRawAudioFormat(
|
||||||
OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
|
OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
|
||||||
|
|
||||||
|
// port definition
|
||||||
|
OMX_PARAM_PORTDEFINITIONTYPE def;
|
||||||
|
InitOMXParams(&def);
|
||||||
|
def.nPortIndex = portIndex;
|
||||||
|
status_t err = mOMX->getParameter(
|
||||||
|
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
|
||||||
|
CHECK_EQ(err, OK);
|
||||||
|
def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
|
||||||
|
CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
|
||||||
|
&def, sizeof(def)), OK);
|
||||||
|
|
||||||
|
// pcm param
|
||||||
OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
|
OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
|
||||||
InitOMXParams(&pcmParams);
|
InitOMXParams(&pcmParams);
|
||||||
pcmParams.nPortIndex = portIndex;
|
pcmParams.nPortIndex = portIndex;
|
||||||
|
|
||||||
status_t err = mOMX->getParameter(
|
err = mOMX->getParameter(
|
||||||
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
|
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
|
||||||
|
|
||||||
CHECK_EQ(err, OK);
|
CHECK_EQ(err, OK);
|
||||||
@@ -2171,6 +2186,8 @@ void OMXCodec::setAMRFormat(bool isWAMR) {
|
|||||||
CHECK_EQ(err, OK);
|
CHECK_EQ(err, OK);
|
||||||
|
|
||||||
def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
|
def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
|
||||||
|
|
||||||
|
// XXX: Select bandmode based on bit rate
|
||||||
def.eAMRBandMode =
|
def.eAMRBandMode =
|
||||||
isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
|
isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
|
||||||
|
|
||||||
@@ -2191,8 +2208,60 @@ void OMXCodec::setAMRFormat(bool isWAMR) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
|
void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
|
||||||
|
CHECK(numChannels == 1 || numChannels == 2);
|
||||||
if (mIsEncoder) {
|
if (mIsEncoder) {
|
||||||
|
//////////////// input port ////////////////////
|
||||||
setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
|
setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
|
||||||
|
|
||||||
|
//////////////// output port ////////////////////
|
||||||
|
// format
|
||||||
|
OMX_AUDIO_PARAM_PORTFORMATTYPE format;
|
||||||
|
format.nPortIndex = kPortIndexOutput;
|
||||||
|
format.nIndex = 0;
|
||||||
|
status_t err = OMX_ErrorNone;
|
||||||
|
while (OMX_ErrorNone == err) {
|
||||||
|
CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat,
|
||||||
|
&format, sizeof(format)), OK);
|
||||||
|
if (format.eEncoding == OMX_AUDIO_CodingAAC) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
format.nIndex++;
|
||||||
|
}
|
||||||
|
CHECK_EQ(OK, err);
|
||||||
|
CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat,
|
||||||
|
&format, sizeof(format)), OK);
|
||||||
|
|
||||||
|
// port definition
|
||||||
|
OMX_PARAM_PORTDEFINITIONTYPE def;
|
||||||
|
InitOMXParams(&def);
|
||||||
|
def.nPortIndex = kPortIndexOutput;
|
||||||
|
CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
|
||||||
|
&def, sizeof(def)), OK);
|
||||||
|
def.format.audio.bFlagErrorConcealment = OMX_TRUE;
|
||||||
|
def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
|
||||||
|
CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
|
||||||
|
&def, sizeof(def)), OK);
|
||||||
|
|
||||||
|
// profile
|
||||||
|
OMX_AUDIO_PARAM_AACPROFILETYPE profile;
|
||||||
|
InitOMXParams(&profile);
|
||||||
|
profile.nPortIndex = kPortIndexOutput;
|
||||||
|
CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioAac,
|
||||||
|
&profile, sizeof(profile)), OK);
|
||||||
|
profile.nChannels = numChannels;
|
||||||
|
profile.eChannelMode = (numChannels == 1?
|
||||||
|
OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo);
|
||||||
|
profile.nSampleRate = sampleRate;
|
||||||
|
profile.nBitRate = 96000; // XXX
|
||||||
|
profile.nAudioBandWidth = 0;
|
||||||
|
profile.nFrameLength = 0;
|
||||||
|
profile.nAACtools = OMX_AUDIO_AACToolAll;
|
||||||
|
profile.nAACERtools = OMX_AUDIO_AACERNone;
|
||||||
|
profile.eAACProfile = OMX_AUDIO_AACObjectLC;
|
||||||
|
profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
|
||||||
|
CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioAac,
|
||||||
|
&profile, sizeof(profile)), OK);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
OMX_AUDIO_PARAM_AACPROFILETYPE profile;
|
OMX_AUDIO_PARAM_AACPROFILETYPE profile;
|
||||||
InitOMXParams(&profile);
|
InitOMXParams(&profile);
|
||||||
@@ -2961,6 +3030,11 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
|
|||||||
} else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
|
} else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
|
||||||
mOutputFormat->setCString(
|
mOutputFormat->setCString(
|
||||||
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
|
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
|
||||||
|
int32_t numChannels, sampleRate;
|
||||||
|
inputFormat->findInt32(kKeyChannelCount, &numChannels);
|
||||||
|
inputFormat->findInt32(kKeySampleRate, &sampleRate);
|
||||||
|
mOutputFormat->setInt32(kKeyChannelCount, numChannels);
|
||||||
|
mOutputFormat->setInt32(kKeySampleRate, sampleRate);
|
||||||
} else {
|
} else {
|
||||||
CHECK(!"Should not be here. Unknown audio encoding.");
|
CHECK(!"Should not be here. Unknown audio encoding.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user