Merge "Support for auxiliary video parameters."
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 5a87f4c..c424281 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -32,9 +32,15 @@
using namespace android;
+static const int32_t kFramerate = 24; // fps
+static const int32_t kIFramesIntervalSec = 1;
+static const int32_t kVideoBitRate = 512 * 1024;
+static const int32_t kAudioBitRate = 12200;
+static const int32_t kColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+static const int64_t kDurationUs = 10000000LL; // 10 seconds
+
#if 1
class DummySource : public MediaSource {
- static const int32_t kFramerate = 24; // fps
public:
DummySource(int width, int height)
@@ -176,6 +182,12 @@
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
+ enc_meta->setInt32(kKeySampleRate, kFramerate);
+ enc_meta->setInt32(kKeyBitRate, kVideoBitRate);
+ enc_meta->setInt32(kKeyStride, width);
+ enc_meta->setInt32(kKeySliceHeight, height);
+ enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
+ enc_meta->setInt32(kKeyColorFormat, kColorFormat);
sp<MediaSource> encoder =
OMXCodec::Create(
@@ -184,8 +196,10 @@
#if 1
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
writer->addSource(encoder);
+ writer->setMaxFileDuration(kDurationUs);
writer->start();
while (!writer->reachedEOS()) {
+ fprintf(stderr, ".");
usleep(100000);
}
writer->stop();
@@ -194,6 +208,8 @@
MediaBuffer *buffer;
while (encoder->read(&buffer) == OK) {
+ printf(".");
+ fflush(stdout);
int32_t isSync;
if (!buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)) {
isSync = false;
@@ -209,6 +225,7 @@
encoder->stop();
#endif
+ printf("$\n");
client.disconnect();
#endif
@@ -267,6 +284,7 @@
encMeta->setInt32(kKeySampleRate, kSampleRate);
encMeta->setInt32(kKeyChannelCount, kNumChannels);
encMeta->setInt32(kKeyMaxInputSize, 8192);
+ encMeta->setInt32(kKeyBitRate, kAudioBitRate);
sp<MediaSource> encoder =
OMXCodec::Create(client.interface(), encMeta, true, audioSource);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index d3bb96e..7297811 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -258,16 +258,24 @@
pContext->pBundledContext->firstVolume = LVM_TRUE;
#ifdef LVM_PCM
- pContext->pBundledContext->PcmInPtr = NULL;
- pContext->pBundledContext->PcmOutPtr = NULL;
- pContext->pBundledContext->PcmInPtr = fopen("/data/tmp/bundle_pcm_in.pcm", "w");
- pContext->pBundledContext->PcmOutPtr = fopen("/data/tmp/bundle_pcm_out.pcm", "w");
-
- if((pContext->pBundledContext->PcmInPtr == NULL)||
- (pContext->pBundledContext->PcmOutPtr == NULL)){
+ char fileName[256];
+ snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_in.pcm", pContext->pBundledContext);
+ pContext->pBundledContext->PcmInPtr = fopen(fileName, "w");
+ if (pContext->pBundledContext->PcmInPtr == NULL) {
+ LOGV("cannot open %s", fileName);
return -EINVAL;
}
+
+ snprintf(fileName, 256, "/data/tmp/bundle_%p_pcm_out.pcm", pContext->pBundledContext);
+ pContext->pBundledContext->PcmOutPtr = fopen(fileName, "w");
+ if (pContext->pBundledContext->PcmOutPtr == NULL) {
+ LOGV("cannot open %s", fileName);
+ fclose(pContext->pBundledContext->PcmInPtr);
+ pContext->pBundledContext->PcmInPtr = NULL;
+ return -EINVAL;
+ }
+
#endif
/* Saved strength is used to return the exact strength that was used in the set to the get
@@ -375,8 +383,14 @@
(GlobalSessionMemory[pContext->pBundledContext->SessionNo].bVirtualizerInstantiated==LVM_FALSE))
{
#ifdef LVM_PCM
- fclose(pContext->pBundledContext->PcmInPtr);
- fclose(pContext->pBundledContext->PcmOutPtr);
+ if (pContext->pBundledContext->PcmInPtr != NULL) {
+ fclose(pContext->pBundledContext->PcmInPtr);
+ pContext->pBundledContext->PcmInPtr = NULL;
+ }
+ if (pContext->pBundledContext->PcmOutPtr != NULL) {
+ fclose(pContext->pBundledContext->PcmOutPtr);
+ pContext->pBundledContext->PcmOutPtr = NULL;
+ }
#endif
LvmSessionsActive--;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 085e92d..183874c 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -274,9 +274,13 @@
status_t AwesomePlayer::setDataSource(
int fd, int64_t offset, int64_t length) {
#if 0
+ // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/sl.m3u8");
+ return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0440.m3u8");
+ // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0640.m3u8");
+ // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/1240_vod.m3u8");
// return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
// return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
- return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
+ // return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
// return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
// return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
// return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 26a0fb3..72de8d7 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -78,6 +78,8 @@
unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
const uint8_t *data, size_t size);
+ void extractAACFrames(const sp<ABuffer> &buffer);
+
DISALLOW_EVIL_CONSTRUCTORS(Stream);
};
@@ -226,7 +228,7 @@
ATSParser::Stream::Stream(unsigned elementaryPID, unsigned streamType)
: mElementaryPID(elementaryPID),
mStreamType(streamType),
- mBuffer(new ABuffer(65536)),
+ mBuffer(new ABuffer(128 * 1024)),
mPayloadStarted(false) {
mBuffer->setRange(0, 0);
}
@@ -662,7 +664,7 @@
csd->data()[sizeof(kStaticESDS) + 1] =
((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
- hexdump(csd->data(), csd->size());
+ // hexdump(csd->data(), csd->size());
return csd;
}
@@ -727,13 +729,76 @@
buffer->meta()->setInt64("time", (PTS * 100) / 9);
if (mStreamType == 0x0f) {
- // WHY???
- buffer->setRange(7, buffer->size() - 7);
+ extractAACFrames(buffer);
}
mSource->queueAccessUnit(buffer);
}
+// Disassemble one or more ADTS frames into their constituent parts and
+// leave only the concatenated raw_data_blocks in the buffer.
+void ATSParser::Stream::extractAACFrames(const sp<ABuffer> &buffer) {
+ size_t dstOffset = 0;
+
+ size_t offset = 0;
+ while (offset < buffer->size()) {
+ CHECK_LE(offset + 7, buffer->size());
+
+ ABitReader bits(buffer->data() + offset, buffer->size() - offset);
+
+ // adts_fixed_header
+
+ CHECK_EQ(bits.getBits(12), 0xfffu);
+ bits.skipBits(3); // ID, layer
+ bool protection_absent = bits.getBits(1) != 0;
+
+ // profile_ObjectType, sampling_frequency_index, private_bits,
+ // channel_configuration, original_copy, home
+ bits.skipBits(12);
+
+ // adts_variable_header
+
+ // copyright_identification_bit, copyright_identification_start
+ bits.skipBits(2);
+
+ unsigned aac_frame_length = bits.getBits(13);
+
+ bits.skipBits(11); // adts_buffer_fullness
+
+ unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
+
+ if (number_of_raw_data_blocks_in_frame == 0) {
+ size_t scan = offset + aac_frame_length;
+
+ offset += 7;
+ if (!protection_absent) {
+ offset += 2;
+ }
+
+ CHECK_LE(scan, buffer->size());
+
+ LOG(VERBOSE)
+ << "found aac raw data block at ["
+ << StringPrintf("0x%08x", offset)
+ << " ; "
+ << StringPrintf("0x%08x", scan)
+ << ")";
+
+ memmove(&buffer->data()[dstOffset], &buffer->data()[offset],
+ scan - offset);
+
+ dstOffset += scan - offset;
+ offset = scan;
+ } else {
+ // To be implemented.
+ TRESPASS();
+ }
+ }
+ CHECK_EQ(offset, buffer->size());
+
+ buffer->setRange(buffer->offset(), dstOffset);
+}
+
sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
if ((type == AVC_VIDEO && mStreamType == 0x1b)
|| (type == MPEG2ADTS_AUDIO && mStreamType == 0x0f)) {
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 7dd3e3f..f68a35b 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -18,29 +18,160 @@
#include "ARTPSource.h"
+#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/Utils.h>
+#include <ctype.h>
#include <stdint.h>
#define BE_VERBOSE 0
namespace android {
+static bool GetAttribute(const char *s, const char *key, AString *value) {
+ value->clear();
+
+ size_t keyLen = strlen(key);
+
+ for (;;) {
+ while (isspace(*s)) {
+ ++s;
+ }
+
+ const char *colonPos = strchr(s, ';');
+
+ size_t len =
+ (colonPos == NULL) ? strlen(s) : colonPos - s;
+
+ if (len >= keyLen + 1 && s[keyLen] == '='
+ && !strncasecmp(s, key, keyLen)) {
+ value->setTo(&s[keyLen + 1], len - keyLen - 1);
+ return true;
+ }
+
+ if (colonPos == NULL) {
+ return false;
+ }
+
+ s = colonPos + 1;
+ }
+}
+
+static bool GetIntegerAttribute(
+ const char *s, const char *key, unsigned *x) {
+ *x = 0;
+
+ AString val;
+ if (!GetAttribute(s, key, &val)) {
+ return false;
+ }
+
+ s = val.c_str();
+ char *end;
+ unsigned y = strtoul(s, &end, 10);
+
+ if (end == s || *end != '\0') {
+ return false;
+ }
+
+ *x = y;
+
+ return true;
+}
+
// static
-AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify)
+AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(
+ const sp<AMessage> ¬ify, const AString &desc, const AString ¶ms)
: mNotifyMsg(notify),
+ mIsGeneric(false),
+ mParams(params),
+ mSizeLength(0),
+ mIndexLength(0),
+ mIndexDeltaLength(0),
+ mCTSDeltaLength(0),
+ mDTSDeltaLength(0),
+ mRandomAccessIndication(false),
+ mStreamStateIndication(0),
+ mAuxiliaryDataSizeLength(0),
+ mHasAUHeader(false),
mAccessUnitRTPTime(0),
mNextExpectedSeqNoValid(false),
mNextExpectedSeqNo(0),
mAccessUnitDamaged(false) {
+ mIsGeneric = desc.startsWith("mpeg4-generic/");
+
+ if (mIsGeneric) {
+ AString value;
+ CHECK(GetAttribute(params.c_str(), "mode", &value));
+
+ if (!GetIntegerAttribute(params.c_str(), "sizeLength", &mSizeLength)) {
+ mSizeLength = 0;
+ }
+
+ if (!GetIntegerAttribute(
+ params.c_str(), "indexLength", &mIndexLength)) {
+ mIndexLength = 0;
+ }
+
+ if (!GetIntegerAttribute(
+ params.c_str(), "indexDeltaLength", &mIndexDeltaLength)) {
+ mIndexDeltaLength = 0;
+ }
+
+ if (!GetIntegerAttribute(
+ params.c_str(), "CTSDeltaLength", &mCTSDeltaLength)) {
+ mCTSDeltaLength = 0;
+ }
+
+ if (!GetIntegerAttribute(
+ params.c_str(), "DTSDeltaLength", &mDTSDeltaLength)) {
+ mDTSDeltaLength = 0;
+ }
+
+ unsigned x;
+ if (!GetIntegerAttribute(
+ params.c_str(), "randomAccessIndication", &x)) {
+ mRandomAccessIndication = false;
+ } else {
+ CHECK(x == 0 || x == 1);
+ mRandomAccessIndication = (x != 0);
+ }
+
+ if (!GetIntegerAttribute(
+ params.c_str(), "streamStateIndication",
+ &mStreamStateIndication)) {
+ mStreamStateIndication = 0;
+ }
+
+ if (!GetIntegerAttribute(
+ params.c_str(), "auxiliaryDataSizeLength",
+ &mAuxiliaryDataSizeLength)) {
+ mAuxiliaryDataSizeLength = 0;
+ }
+
+ mHasAUHeader =
+ mSizeLength > 0
+ || mIndexLength > 0
+ || mIndexDeltaLength > 0
+ || mCTSDeltaLength > 0
+ || mDTSDeltaLength > 0
+ || mRandomAccessIndication
+ || mStreamStateIndication > 0;
+ }
}
AMPEG4ElementaryAssembler::~AMPEG4ElementaryAssembler() {
}
+struct AUHeader {
+ unsigned mSize;
+ unsigned mSerial;
+};
+
ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket(
const sp<ARTPSource> &source) {
List<sp<ABuffer> > *queue = source->queue();
@@ -85,8 +216,116 @@
}
mAccessUnitRTPTime = rtpTime;
- mPackets.push_back(buffer);
- // hexdump(buffer->data(), buffer->size());
+ if (!mIsGeneric) {
+ mPackets.push_back(buffer);
+ } else {
+ // hexdump(buffer->data(), buffer->size());
+
+ CHECK_GE(buffer->size(), 2u);
+ unsigned AU_headers_length = U16_AT(buffer->data()); // in bits
+
+ CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8);
+
+ List<AUHeader> headers;
+
+ ABitReader bits(buffer->data() + 2, buffer->size() - 2);
+ unsigned numBitsLeft = AU_headers_length;
+
+ unsigned AU_serial = 0;
+ for (;;) {
+ if (numBitsLeft < mSizeLength) { break; }
+
+ unsigned AU_size = bits.getBits(mSizeLength);
+ numBitsLeft -= mSizeLength;
+
+ size_t n = headers.empty() ? mIndexLength : mIndexDeltaLength;
+ if (numBitsLeft < n) { break; }
+
+ unsigned AU_index = bits.getBits(n);
+ numBitsLeft -= n;
+
+ if (headers.empty()) {
+ AU_serial = AU_index;
+ } else {
+ AU_serial += 1 + AU_index;
+ }
+
+ if (mCTSDeltaLength > 0) {
+ if (numBitsLeft < 1) {
+ break;
+ }
+ --numBitsLeft;
+ if (bits.getBits(1)) {
+ if (numBitsLeft < mCTSDeltaLength) {
+ break;
+ }
+ bits.skipBits(mCTSDeltaLength);
+ numBitsLeft -= mCTSDeltaLength;
+ }
+ }
+
+ if (mDTSDeltaLength > 0) {
+ if (numBitsLeft < 1) {
+ break;
+ }
+ --numBitsLeft;
+ if (bits.getBits(1)) {
+ if (numBitsLeft < mDTSDeltaLength) {
+ break;
+ }
+ bits.skipBits(mDTSDeltaLength);
+ numBitsLeft -= mDTSDeltaLength;
+ }
+ }
+
+ if (mRandomAccessIndication) {
+ if (numBitsLeft < 1) {
+ break;
+ }
+ bits.skipBits(1);
+ --numBitsLeft;
+ }
+
+ if (mStreamStateIndication > 0) {
+ if (numBitsLeft < mStreamStateIndication) {
+ break;
+ }
+ bits.skipBits(mStreamStateIndication);
+ }
+
+ AUHeader header;
+ header.mSize = AU_size;
+ header.mSerial = AU_serial;
+ headers.push_back(header);
+ }
+
+ size_t offset = 2 + (AU_headers_length + 7) / 8;
+
+ if (mAuxiliaryDataSizeLength > 0) {
+ ABitReader bits(buffer->data() + offset, buffer->size() - offset);
+
+ unsigned auxSize = bits.getBits(mAuxiliaryDataSizeLength);
+
+ offset += (mAuxiliaryDataSizeLength + auxSize + 7) / 8;
+ }
+
+ for (List<AUHeader>::iterator it = headers.begin();
+ it != headers.end(); ++it) {
+ const AUHeader &header = *it;
+
+ CHECK_LE(offset + header.mSize, buffer->size());
+
+ sp<ABuffer> accessUnit = new ABuffer(header.mSize);
+ memcpy(accessUnit->data(), buffer->data() + offset, header.mSize);
+
+ offset += header.mSize;
+
+ CopyTimes(accessUnit, buffer);
+ mPackets.push_back(accessUnit);
+ }
+
+ CHECK_EQ(offset, buffer->size());
+ }
queue->erase(queue->begin());
++mNextExpectedSeqNo;
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
index 1566d00..794bbcc 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
@@ -20,6 +20,8 @@
#include "ARTPAssembler.h"
+#include <media/stagefright/foundation/AString.h>
+
#include <utils/List.h>
#include <utils/RefBase.h>
@@ -29,7 +31,9 @@
struct AMessage;
struct AMPEG4ElementaryAssembler : public ARTPAssembler {
- AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify);
+ AMPEG4ElementaryAssembler(
+ const sp<AMessage> ¬ify, const AString &desc,
+ const AString ¶ms);
protected:
virtual ~AMPEG4ElementaryAssembler();
@@ -40,6 +44,18 @@
private:
sp<AMessage> mNotifyMsg;
+ bool mIsGeneric;
+ AString mParams;
+
+ unsigned mSizeLength;
+ unsigned mIndexLength;
+ unsigned mIndexDeltaLength;
+ unsigned mCTSDeltaLength;
+ unsigned mDTSDeltaLength;
+ bool mRandomAccessIndication;
+ unsigned mStreamStateIndication;
+ unsigned mAuxiliaryDataSizeLength;
+ bool mHasAUHeader;
uint32_t mAccessUnitRTPTime;
bool mNextExpectedSeqNoValid;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 2d7738b..75b4571 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -247,6 +247,65 @@
return csd;
}
+// From mpeg4-generic configuration data.
+sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
+ AString val;
+ unsigned long objectType;
+ if (GetAttribute(params, "objectType", &val)) {
+ const char *s = val.c_str();
+ char *end;
+ objectType = strtoul(s, &end, 10);
+ CHECK(end > s && *end == '\0');
+ } else {
+ objectType = 0x40; // Audio ISO/IEC 14496-3
+ }
+
+ CHECK(GetAttribute(params, "config", &val));
+
+ sp<ABuffer> config = decodeHex(val);
+ CHECK(config != NULL);
+
+ // Make sure size fits into a single byte and doesn't have to
+ // be encoded.
+ CHECK_LT(20 + config->size(), 128u);
+
+ const uint8_t *data = config->data();
+
+ static const uint8_t kStaticESDS[] = {
+ 0x03, 22,
+ 0x00, 0x00, // ES_ID
+ 0x00, // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+ 0x04, 17,
+ 0x40, // Audio ISO/IEC 14496-3
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+
+ 0x05, 2,
+ // AudioSpecificInfo follows
+ };
+
+ sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + config->size());
+ uint8_t *dst = csd->data();
+ *dst++ = 0x03;
+ *dst++ = 20 + config->size();
+ *dst++ = 0x00; // ES_ID
+ *dst++ = 0x00;
+ *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
+ *dst++ = 0x04;
+ *dst++ = 15 + config->size();
+ *dst++ = objectType;
+ for (int i = 0; i < 12; ++i) { *dst++ = 0x00; }
+ *dst++ = 0x05;
+ *dst++ = config->size();
+ memcpy(dst, config->data(), config->size());
+
+ // hexdump(csd->data(), csd->size());
+
+ return csd;
+}
+
static size_t GetSizeWidth(size_t x) {
size_t n = 1;
while (x > 127) {
@@ -560,6 +619,30 @@
mFormat->setInt32(kKeyWidth, width);
mFormat->setInt32(kKeyHeight, height);
+ } else if (!strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
+ AString val;
+ if (!GetAttribute(params.c_str(), "mode", &val)
+ || (strcasecmp(val.c_str(), "AAC-lbr")
+ && strcasecmp(val.c_str(), "AAC-hbr"))) {
+ mInitCheck = ERROR_UNSUPPORTED;
+ return;
+ }
+
+ mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+ int32_t sampleRate, numChannels;
+ ASessionDescription::ParseFormatDesc(
+ desc.c_str(), &sampleRate, &numChannels);
+
+ mFormat->setInt32(kKeySampleRate, sampleRate);
+ mFormat->setInt32(kKeyChannelCount, numChannels);
+
+ sp<ABuffer> codecSpecificData =
+ MakeAACCodecSpecificData2(params.c_str());
+
+ mFormat->setData(
+ kKeyESDS, 0,
+ codecSpecificData->data(), codecSpecificData->size());
} else {
mInitCheck = ERROR_UNSUPPORTED;
}
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 12f8f32..10c9e02 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -362,7 +362,6 @@
if (receiveRTP) {
err = parseRTP(s, buffer);
} else {
- ++s->mNumRTCPPacketsReceived;
err = parseRTCP(s, buffer);
}
@@ -456,6 +455,12 @@
}
status_t ARTPConnection::parseRTCP(StreamInfo *s, const sp<ABuffer> &buffer) {
+ if (s->mNumRTCPPacketsReceived++ == 0) {
+ sp<AMessage> notify = s->mNotifyMsg->dup();
+ notify->setInt32("first-rtcp", true);
+ notify->post();
+ }
+
const uint8_t *data = buffer->data();
size_t size = buffer->size();
@@ -626,7 +631,6 @@
if (it->mRTPSocket == index) {
err = parseRTP(s, buffer);
} else {
- ++s->mNumRTCPPacketsReceived;
err = parseRTCP(s, buffer);
}
}
diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp
index f60c1a9..8ce93b7 100644
--- a/media/libstagefright/rtsp/ARTPSession.cpp
+++ b/media/libstagefright/rtsp/ARTPSession.cpp
@@ -125,6 +125,14 @@
switch (msg->what()) {
case kWhatAccessUnitComplete:
{
+ int32_t firstRTCP;
+ if (msg->findInt32("first-rtcp", &firstRTCP)) {
+ // There won't be an access unit here, it's just a notification
+ // that the data communication worked since we got the first
+ // rtcp packet.
+ break;
+ }
+
size_t trackIndex;
CHECK(msg->findSize("track-index", &trackIndex));
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 775c4ee..9656ba2 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -64,8 +64,9 @@
mAssembler = new AAMRAssembler(notify, false /* isWide */, params);
} else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
- } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
- mAssembler = new AMPEG4ElementaryAssembler(notify);
+ } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)
+ || !strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
+ mAssembler = new AMPEG4ElementaryAssembler(notify, desc, params);
mIssueFIRRequests = true;
} else {
TRESPASS();
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 3d8d86b..0aefd58 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -82,7 +82,8 @@
mFirstAccessUnitNTP(0),
mNumAccessUnitsReceived(0),
mCheckPending(false),
- mTryTCPInterleaving(false) {
+ mTryTCPInterleaving(false),
+ mReceivedFirstRTCPPacket(false) {
mNetLooper->setName("rtsp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
@@ -199,31 +200,35 @@
break;
}
- CHECK_EQ(response->mStatusCode, 200u);
-
- mSessionDesc = new ASessionDescription;
-
- mSessionDesc->setTo(
- response->mContent->data(),
- response->mContent->size());
-
- CHECK(mSessionDesc->isValid());
-
- ssize_t i = response->mHeaders.indexOfKey("content-base");
- if (i >= 0) {
- mBaseURL = response->mHeaders.valueAt(i);
+ if (response->mStatusCode != 200) {
+ result = UNKNOWN_ERROR;
} else {
- i = response->mHeaders.indexOfKey("content-location");
+ mSessionDesc = new ASessionDescription;
+
+ mSessionDesc->setTo(
+ response->mContent->data(),
+ response->mContent->size());
+
+ CHECK(mSessionDesc->isValid());
+
+ ssize_t i = response->mHeaders.indexOfKey("content-base");
if (i >= 0) {
mBaseURL = response->mHeaders.valueAt(i);
} else {
- mBaseURL = mSessionURL;
+ i = response->mHeaders.indexOfKey("content-location");
+ if (i >= 0) {
+ mBaseURL = response->mHeaders.valueAt(i);
+ } else {
+ mBaseURL = mSessionURL;
+ }
}
- }
- CHECK_GT(mSessionDesc->countTracks(), 1u);
- setupTrack(1);
- } else {
+ CHECK_GT(mSessionDesc->countTracks(), 1u);
+ setupTrack(1);
+ }
+ }
+
+ if (result != OK) {
sp<AMessage> reply = new AMessage('disc', id());
mConn->disconnect(reply);
}
@@ -247,6 +252,39 @@
LOG(INFO) << "SETUP(" << index << ") completed with result "
<< result << " (" << strerror(-result) << ")";
+ if (result == OK) {
+ CHECK(track != NULL);
+
+ sp<RefBase> obj;
+ CHECK(msg->findObject("response", &obj));
+ sp<ARTSPResponse> response =
+ static_cast<ARTSPResponse *>(obj.get());
+
+ if (response->mStatusCode != 200) {
+ result = UNKNOWN_ERROR;
+ } else {
+ ssize_t i = response->mHeaders.indexOfKey("session");
+ CHECK_GE(i, 0);
+
+ mSessionID = response->mHeaders.valueAt(i);
+ i = mSessionID.find(";");
+ if (i >= 0) {
+ // Remove options, i.e. ";timeout=90"
+ mSessionID.erase(i, mSessionID.size() - i);
+ }
+
+ sp<AMessage> notify = new AMessage('accu', id());
+ notify->setSize("track-index", trackIndex);
+
+ mRTPConn->addStream(
+ track->mRTPSocket, track->mRTCPSocket,
+ mSessionDesc, index,
+ notify, track->mUsingInterleavedTCP);
+
+ mSetupTracksSuccessful = true;
+ }
+ }
+
if (result != OK) {
if (track) {
if (!track->mUsingInterleavedTCP) {
@@ -256,37 +294,6 @@
mTracks.removeItemsAt(trackIndex);
}
- } else {
- CHECK(track != NULL);
-
- sp<RefBase> obj;
- CHECK(msg->findObject("response", &obj));
- sp<ARTSPResponse> response =
- static_cast<ARTSPResponse *>(obj.get());
-
- CHECK_EQ(response->mStatusCode, 200u);
-
- ssize_t i = response->mHeaders.indexOfKey("session");
- CHECK_GE(i, 0);
-
- if (index == 1) {
- mSessionID = response->mHeaders.valueAt(i);
- i = mSessionID.find(";");
- if (i >= 0) {
- // Remove options, i.e. ";timeout=90"
- mSessionID.erase(i, mSessionID.size() - i);
- }
- }
-
- sp<AMessage> notify = new AMessage('accu', id());
- notify->setSize("track-index", trackIndex);
-
- mRTPConn->addStream(
- track->mRTPSocket, track->mRTCPSocket,
- mSessionDesc, index,
- notify, track->mUsingInterleavedTCP);
-
- mSetupTracksSuccessful = true;
}
++index;
@@ -355,6 +362,12 @@
}
}
mTracks.clear();
+ mSetupTracksSuccessful = false;
+ mSeekPending = false;
+ mFirstAccessUnit = true;
+ mFirstAccessUnitNTP = 0;
+ mNumAccessUnitsReceived = 0;
+ mReceivedFirstRTCPPacket = false;
sp<AMessage> reply = new AMessage('tear', id());
@@ -424,6 +437,12 @@
case 'accu':
{
+ int32_t firstRTCP;
+ if (msg->findInt32("first-rtcp", &firstRTCP)) {
+ mReceivedFirstRTCPPacket = true;
+ break;
+ }
+
++mNumAccessUnitsReceived;
if (!mCheckPending) {
@@ -612,7 +631,7 @@
case 'tiou':
{
- if (mFirstAccessUnit) {
+ if (!mReceivedFirstRTCPPacket) {
if (mTryTCPInterleaving) {
LOG(WARNING) << "Never received any data, disconnecting.";
(new AMessage('abor', id()))->post();
@@ -747,6 +766,7 @@
int64_t mNumAccessUnitsReceived;
bool mCheckPending;
bool mTryTCPInterleaving;
+ bool mReceivedFirstRTCPPacket;
struct TrackInfo {
AString mURL;
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 899b34a..c8cb016 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -93,6 +93,10 @@
MtpObjectFormat format) = 0;
virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property) = 0;
+
+ virtual void sessionStarted() = 0;
+
+ virtual void sessionEnded() = 0;
};
}; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 1e64e4f..c982114 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -185,6 +185,9 @@
LOGV("skipping response\n");
}
}
+
+ if (mSessionOpen)
+ mDatabase->sessionEnded();
}
void MtpServer::sendObjectAdded(MtpObjectHandle handle) {
@@ -346,6 +349,9 @@
}
mSessionID = mRequest.getParameter(1);
mSessionOpen = true;
+
+ mDatabase->sessionStarted();
+
return MTP_RESPONSE_OK;
}
@@ -354,6 +360,7 @@
return MTP_RESPONSE_SESSION_NOT_OPEN;
mSessionID = 0;
mSessionOpen = false;
+ mDatabase->sessionEnded();
return MTP_RESPONSE_OK;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ff31470..1acdaaf 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1781,6 +1781,14 @@
if (chain != 0 && chain->setVolume_l(&vl, &vr)) {
// Do not ramp volume is volume is controlled by effect
param = AudioMixer::VOLUME;
+ track->mHasVolumeController = true;
+ } else {
+ // force no volume ramp when volume controller was just disabled or removed
+ // from effect chain to avoid volume spike
+ if (track->mHasVolumeController) {
+ param = AudioMixer::VOLUME;
+ }
+ track->mHasVolumeController = false;
}
// Convert volumes from 8.24 to 4.12 format
@@ -2901,7 +2909,8 @@
const sp<IMemory>& sharedBuffer,
int sessionId)
: TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer, sessionId),
- mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL), mAuxEffectId(0)
+ mMute(false), mSharedBuffer(sharedBuffer), mName(-1), mMainBuffer(NULL), mAuxBuffer(NULL),
+ mAuxEffectId(0), mHasVolumeController(false)
{
if (mCblk != NULL) {
sp<ThreadBase> baseThread = thread.promote();
@@ -5371,7 +5380,7 @@
return;
}
- if (mState == ACTIVE || mState == STOPPING || mState == STOPPED || mState == RESTART) {
+ if (isProcessEnabled()) {
// do 32 bit to 16 bit conversion for auxiliary effect input buffer
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32,
@@ -5600,6 +5609,8 @@
// going from enabled to disabled
case RESTART:
+ mState = STOPPED;
+ break;
case STARTING:
mState = IDLE;
break;
@@ -5632,6 +5643,21 @@
}
}
+bool AudioFlinger::EffectModule::isProcessEnabled()
+{
+ switch (mState) {
+ case RESTART:
+ case ACTIVE:
+ case STOPPING:
+ case STOPPED:
+ return true;
+ case IDLE:
+ case STARTING:
+ default:
+ return false;
+ }
+}
+
status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right, bool controller)
{
Mutex::Autolock _l(mLock);
@@ -5639,7 +5665,7 @@
// Send volume indication if EFFECT_FLAG_VOLUME_IND is set and read back altered volume
// if controller flag is set (Note that controller == TRUE => EFFECT_FLAG_VOLUME_CTRL set)
- if ((mState >= ACTIVE) &&
+ if (isProcessEnabled() &&
((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
(mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND)) {
status_t cmdStatus;
@@ -6288,7 +6314,7 @@
// first update volume controller
for (size_t i = size; i > 0; i--) {
- if ((mEffects[i - 1]->state() >= EffectModule::ACTIVE) &&
+ if (mEffects[i - 1]->isProcessEnabled() &&
(mEffects[i - 1]->desc().flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL) {
ctrlIdx = i - 1;
hasControl = true;
@@ -6304,9 +6330,6 @@
return hasControl;
}
- if (mVolumeCtrlIdx != -1) {
- hasControl = true;
- }
mVolumeCtrlIdx = ctrlIdx;
mLeftVolume = newLeft;
mRightVolume = newRight;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 51881f0..5917632 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -514,6 +514,7 @@
int16_t *mMainBuffer;
int32_t *mAuxBuffer;
int mAuxEffectId;
+ bool mHasVolumeController;
}; // end of Track
@@ -965,6 +966,7 @@
}
status_t setEnabled(bool enabled);
bool isEnabled();
+ bool isProcessEnabled();
void setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c6a9909..d1fbf17 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -336,11 +336,6 @@
int callingPid = getCallingPid();
LOG1("Client::~Client E (pid %d, this %p)", callingPid, this);
- // Clean up the ANativeWindow
- if (mSurface != 0) {
- setPreviewDisplay(0);
- }
-
// set mClientPid to let disconnet() tear down the hardware
mClientPid = callingPid;
disconnect();