Merge "Added two more video encoders"
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 8ab94ad..eb4b733 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "stagefright"
+#include <media/stagefright/foundation/ADebug.h>
+
#include <sys/time.h>
#include <stdlib.h>
@@ -30,7 +34,6 @@
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/JPEGSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
@@ -43,6 +46,8 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MPEG4Writer.h>
+#include <fcntl.h>
+
using namespace android;
static long gNumRepetitions;
@@ -120,7 +125,7 @@
bool shouldSeek = false;
if (err == INFO_FORMAT_CHANGED) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
printf("format changed.\n");
continue;
@@ -206,7 +211,7 @@
options.clearSeekTo();
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
if (err == INFO_FORMAT_CHANGED) {
printf("format changed.\n");
@@ -267,14 +272,98 @@
}
}
-static void writeSourceToMP4(const sp<MediaSource> &source) {
+////////////////////////////////////////////////////////////////////////////////
+
+struct DetectSyncSource : public MediaSource {
+ DetectSyncSource(const sp<MediaSource> &source);
+
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+private:
+ sp<MediaSource> mSource;
+ bool mIsAVC;
+
+ DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
+};
+
+DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
+ : mSource(source),
+ mIsAVC(false) {
+ const char *mime;
+ CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+ mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
+}
+
+status_t DetectSyncSource::start(MetaData *params) {
+ return mSource->start(params);
+}
+
+status_t DetectSyncSource::stop() {
+ return mSource->stop();
+}
+
+sp<MetaData> DetectSyncSource::getFormat() {
+ return mSource->getFormat();
+}
+
+static bool isIDRFrame(MediaBuffer *buffer) {
+ const uint8_t *data =
+ (const uint8_t *)buffer->data() + buffer->range_offset();
+ size_t size = buffer->range_length();
+ for (size_t i = 0; i + 3 < size; ++i) {
+ if (!memcmp("\x00\x00\x01", &data[i], 3)) {
+ uint8_t nalType = data[i + 3] & 0x1f;
+ if (nalType == 5) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+status_t DetectSyncSource::read(
+ MediaBuffer **buffer, const ReadOptions *options) {
+ status_t err = mSource->read(buffer, options);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (mIsAVC && isIDRFrame(*buffer)) {
+ (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true);
+ } else {
+ (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, false);
+ }
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void writeSourceToMP4(
+ sp<MediaSource> &source, bool syncInfoPresent) {
+ if (!syncInfoPresent) {
+ source = new DetectSyncSource(source);
+ }
+
sp<MPEG4Writer> writer =
new MPEG4Writer(gWriteMP4Filename.string());
- CHECK_EQ(writer->addSource(source), OK);
+ // at most one minute.
+ writer->setMaxFileDuration(60000000ll);
+
+ CHECK_EQ(writer->addSource(source), (status_t)OK);
sp<MetaData> params = new MetaData;
- CHECK_EQ(writer->start(), OK);
+ params->setInt32(kKeyNotRealTime, true);
+ CHECK_EQ(writer->start(params.get()), (status_t)OK);
while (!writer->reachedEOS()) {
usleep(100000);
@@ -283,7 +372,7 @@
}
static void performSeekTest(const sp<MediaSource> &source) {
- CHECK_EQ(OK, source->start());
+ CHECK_EQ((status_t)OK, source->start());
int64_t durationUs;
CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -335,7 +424,7 @@
}
}
- CHECK_EQ(OK, source->stop());
+ CHECK_EQ((status_t)OK, source->stop());
}
static void usage(const char *me) {
@@ -481,10 +570,10 @@
for (int k = 0; k < argc; ++k) {
const char *filename = argv[k];
- CHECK_EQ(retriever->setDataSource(filename), OK);
+ CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
CHECK_EQ(retriever->setMode(
METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL),
- OK);
+ (status_t)OK);
sp<IMemory> mem = retriever->captureFrame();
@@ -530,7 +619,7 @@
Vector<CodecCapabilities> results;
CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
true, // queryDecoders
- &results), OK);
+ &results), (status_t)OK);
for (size_t i = 0; i < results.size(); ++i) {
printf(" decoder '%s' supports ",
@@ -579,6 +668,8 @@
status_t err = client.connect();
for (int k = 0; k < argc; ++k) {
+ bool syncInfoPresent = true;
+
const char *filename = argv[k];
sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
@@ -625,6 +716,8 @@
}
extractor = rtspController.get();
+
+ syncInfoPresent = false;
} else {
extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
@@ -674,7 +767,7 @@
}
if (gWriteMP4) {
- writeSourceToMP4(mediaSource);
+ writeSourceToMP4(mediaSource, syncInfoPresent);
} else if (seekTest) {
performSeekTest(mediaSource);
} else {
diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp
index 8c964b4..865a294 100644
--- a/media/mtp/MtpCursor.cpp
+++ b/media/mtp/MtpCursor.cpp
@@ -66,7 +66,8 @@
#define OBJECT_THUMB 221
MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID,
- int storageID, int objectID, int columnCount, int* columns)
+ MtpStorageID storageID, MtpObjectHandle objectID,
+ int columnCount, int* columns)
: mClient(client),
mQueryType(queryType),
mDeviceID(deviceID),
@@ -427,7 +428,8 @@
return true;
}
-bool MtpCursor::putThumbnail(CursorWindow* window, int objectID, int format, int row, int column) {
+bool MtpCursor::putThumbnail(CursorWindow* window, MtpObjectHandle objectID,
+ MtpObjectFormat format, int row, int column) {
MtpDevice* device = mClient->getDevice(mDeviceID);
void* thumbnail;
int size, offset;
diff --git a/media/mtp/MtpCursor.h b/media/mtp/MtpCursor.h
index 3f84753..9e9833f 100644
--- a/media/mtp/MtpCursor.h
+++ b/media/mtp/MtpCursor.h
@@ -36,17 +36,18 @@
OBJECT_CHILDREN = 8,
};
- MtpClient* mClient;
- int mQueryType;
- int mDeviceID;
- int mStorageID;
- int mQbjectID;
- int mColumnCount;
- int* mColumns;
+ MtpClient* mClient;
+ int mQueryType;
+ int mDeviceID;
+ MtpStorageID mStorageID;
+ MtpObjectHandle mQbjectID;
+ int mColumnCount;
+ int* mColumns;
public:
MtpCursor(MtpClient* client, int queryType, int deviceID,
- int storageID, int objectID, int columnCount, int* columns);
+ MtpStorageID storageID, MtpObjectHandle objectID,
+ int columnCount, int* columns);
virtual ~MtpCursor();
int fillWindow(CursorWindow* window, int startPos);
@@ -68,7 +69,8 @@
bool prepareRow(CursorWindow* window);
bool putLong(CursorWindow* window, int value, int row, int column);
bool putString(CursorWindow* window, const char* text, int row, int column);
- bool putThumbnail(CursorWindow* window, int objectID, int format, int row, int column);
+ bool putThumbnail(CursorWindow* window, MtpObjectHandle objectID,
+ MtpObjectFormat format, int row, int column);
};
}; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 6332b4e..84a3e2c 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -26,6 +26,8 @@
#include <cutils/properties.h>
+#define LOG_TAG "MtpServer"
+
#include "MtpDebug.h"
#include "MtpDatabase.h"
#include "MtpProperty.h"
@@ -68,8 +70,8 @@
// MTP_OPERATION_INITIATE_OPEN_CAPTURE,
MTP_OPERATION_GET_OBJECT_PROPS_SUPPORTED,
MTP_OPERATION_GET_OBJECT_PROP_DESC,
-// MTP_OPERATION_GET_OBJECT_PROP_VALUE,
-// MTP_OPERATION_SET_OBJECT_PROP_VALUE,
+ MTP_OPERATION_GET_OBJECT_PROP_VALUE,
+ MTP_OPERATION_SET_OBJECT_PROP_VALUE,
MTP_OPERATION_GET_OBJECT_REFERENCES,
MTP_OPERATION_SET_OBJECT_REFERENCES,
// MTP_OPERATION_SKIP,
@@ -294,6 +296,7 @@
response = doGetDevicePropDesc();
break;
default:
+ LOGE("got unsupported command %s", MtpDebug::getOperationCodeName(operation));
response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED;
break;
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 56de765..8a732ed 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -4653,29 +4653,44 @@
goto Exit;
}
+ // check audio settings permission for global effects
+ if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) {
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+
+ // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects
+ // that can only be created by audio policy manager (running in same process)
+ if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) {
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+
+ // check recording permission for visualizer
+ if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
+ memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&
+ !recordingAllowed()) {
+ lStatus = PERMISSION_DENIED;
+ goto Exit;
+ }
+
+ if (output == 0) {
+ if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {
+ // output must be specified by AudioPolicyManager when using session
+ // AudioSystem::SESSION_OUTPUT_STAGE
+ lStatus = BAD_VALUE;
+ goto Exit;
+ } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
+ // if the output returned by getOutputForEffect() is removed before we lock the
+ // mutex below, the call to checkPlaybackThread_l(output) below will detect it
+ // and we will exit safely
+ output = AudioSystem::getOutputForEffect(&desc);
+ }
+ }
+
{
Mutex::Autolock _l(mLock);
- // check audio settings permission for global effects
- if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && !settingsAllowed()) {
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
-
- // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects
- // that can only be created by audio policy manager (running in same process)
- if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && getpid() != pid) {
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
-
- // check recording permission for visualizer
- if ((memcmp(&pDesc->type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0 ||
- memcmp(&pDesc->uuid, &VISUALIZATION_UUID_, sizeof(effect_uuid_t)) == 0) &&
- !recordingAllowed()) {
- lStatus = PERMISSION_DENIED;
- goto Exit;
- }
if (!EffectIsNullUuid(&pDesc->uuid)) {
// if uuid is specified, request effect descriptor
@@ -4744,32 +4759,24 @@
// If output is not specified try to find a matching audio session ID in one of the
// output threads.
- // TODO: allow attachment of effect to inputs
+ // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
+ // because of code checking output when entering the function.
if (output == 0) {
- if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) {
- // output must be specified by AudioPolicyManager when using session
- // AudioSystem::SESSION_OUTPUT_STAGE
- lStatus = BAD_VALUE;
- goto Exit;
- } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) {
- output = AudioSystem::getOutputForEffect(&desc);
- LOGV("createEffect() got output %d for effect %s", output, desc.name);
- } else {
- // look for the thread where the specified audio session is present
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
- output = mPlaybackThreads.keyAt(i);
- break;
- }
- }
- // If no output thread contains the requested session ID, default to
- // first output. The effect chain will be moved to the correct output
- // thread when a track with the same session ID is created
- if (output == 0 && mPlaybackThreads.size()) {
- output = mPlaybackThreads.keyAt(0);
+ // look for the thread where the specified audio session is present
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+ output = mPlaybackThreads.keyAt(i);
+ break;
}
}
+ // If no output thread contains the requested session ID, default to
+ // first output. The effect chain will be moved to the correct output
+ // thread when a track with the same session ID is created
+ if (output == 0 && mPlaybackThreads.size()) {
+ output = mPlaybackThreads.keyAt(0);
+ }
}
+ LOGV("createEffect() got output %d for effect %s", output, desc.name);
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread == NULL) {
LOGE("createEffect() unknown output thread");
@@ -4777,6 +4784,8 @@
goto Exit;
}
+ // TODO: allow attachment of effect to inputs
+
wclient = mClients.valueFor(pid);
if (wclient != NULL) {