Merge "Enable CFI for some media components."
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 3e05532..d5aec3f 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -44,7 +44,8 @@
virtual status_t setOutputFormat(int of) = 0;
virtual status_t setVideoEncoder(int ve) = 0;
virtual status_t setAudioEncoder(int ae) = 0;
- virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setOutputFile(int fd) = 0;
+ virtual status_t setNextOutputFile(int fd) = 0;
virtual status_t setVideoSize(int width, int height) = 0;
virtual status_t setVideoFrameRate(int frames_per_second) = 0;
virtual status_t setParameters(const String8& params) = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index b9105b1..c273da7 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -44,7 +44,8 @@
virtual status_t setCamera(const sp<hardware::ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy) = 0;
virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
- virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
+ virtual status_t setOutputFile(int fd) = 0;
+ virtual status_t setNextOutputFile(int fd) {return INVALID_OPERATION;}
virtual status_t setOutputFileAuxiliary(int /*fd*/) {return INVALID_OPERATION;}
virtual status_t setParameters(const String8& params) = 0;
virtual status_t setListener(const sp<IMediaRecorderClient>& listener) = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 9130159..5d7c25a 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -22,6 +22,7 @@
#include <binder/IMemory.h>
#include <media/AudioResamplerPublic.h>
+#include <media/BufferingSettings.h>
#include <media/IMediaPlayerClient.h>
#include <media/IMediaPlayer.h>
#include <media/IMediaDeathNotifier.h>
@@ -220,6 +221,7 @@
const sp<IGraphicBufferProducer>& bufferProducer);
status_t setListener(const sp<MediaPlayerListener>& listener);
status_t getDefaultBufferingSettings(BufferingSettings* buffering /* nonnull */);
+ status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */);
status_t setBufferingSettings(const BufferingSettings& buffering);
status_t prepare();
status_t prepareAsync();
@@ -294,6 +296,7 @@
float mSendLevel;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
+ BufferingSettings mCurrentBufferingSettings;
};
}; // namespace android
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index c3f39a2..c2916be 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -171,6 +171,8 @@
MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800,
MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801,
+ MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802,
+ MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803,
// All track related informtional events start here
MEDIA_RECORDER_TRACK_INFO_LIST_START = 1000,
@@ -227,7 +229,8 @@
status_t setOutputFormat(int of);
status_t setVideoEncoder(int ve);
status_t setAudioEncoder(int ae);
- status_t setOutputFile(int fd, int64_t offset, int64_t length);
+ status_t setOutputFile(int fd);
+ status_t setNextOutputFile(int fd);
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
status_t setParameters(const String8& params);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index d415b8b..39e7d01 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -24,10 +24,12 @@
#include <media/stagefright/MediaWriter.h>
#include <utils/List.h>
#include <utils/threads.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <media/stagefright/foundation/ALooper.h>
namespace android {
-struct AMessage;
+class AMessage;
class MediaBuffer;
class MetaData;
@@ -65,16 +67,25 @@
status_t setGeoData(int latitudex10000, int longitudex10000);
status_t setCaptureRate(float captureFps);
status_t setTemporalLayerCount(uint32_t layerCount);
+ void notifyApproachingLimit();
virtual void setStartTimeOffsetMs(int ms) { mStartTimeOffsetMs = ms; }
virtual int32_t getStartTimeOffsetMs() const { return mStartTimeOffsetMs; }
+ virtual status_t setNextFd(int fd);
protected:
virtual ~MPEG4Writer();
private:
class Track;
+ friend struct AHandlerReflector<MPEG4Writer>;
+
+ enum {
+ kWhatSwitch = 'swch',
+ };
int mFd;
+ int mNextFd;
+ sp<MetaData> mStartMeta;
status_t mInitCheck;
bool mIsRealTimeRecording;
bool mUse4ByteNalLength;
@@ -83,6 +94,7 @@
bool mPaused;
bool mStarted; // Writer thread + track threads started successfully
bool mWriterThreadStarted; // Only writer thread started successfully
+ bool mSendNotify;
off64_t mOffset;
off_t mMdatOffset;
uint8_t *mMoovBoxBuffer;
@@ -99,6 +111,10 @@
int mLongitudex10000;
bool mAreGeoTagsAvailable;
int32_t mStartTimeOffsetMs;
+ bool mSwitchPending;
+
+ sp<ALooper> mLooper;
+ sp<AHandlerReflector<MPEG4Writer> > mReflector;
Mutex mLock;
@@ -184,6 +200,8 @@
void lock();
void unlock();
+ void initInternal(int fd);
+
// Acquire lock before calling these methods
off64_t addSample_l(MediaBuffer *buffer);
off64_t addLengthPrefixedSample_l(MediaBuffer *buffer);
@@ -192,6 +210,7 @@
bool exceedsFileSizeLimit();
bool use32BitFileOffset() const;
bool exceedsFileDurationLimit();
+ bool approachingFileSizeLimit();
bool isFileStreamable() const;
void trackProgressStatus(size_t trackId, int64_t timeUs, status_t err = OK);
void writeCompositionMatrix(int32_t degrees);
@@ -202,6 +221,7 @@
void writeGeoDataBox();
void writeLatitude(int degreex10000);
void writeLongitude(int degreex10000);
+ void finishCurrentSession();
void addDeviceMeta();
void writeHdlr();
@@ -210,10 +230,13 @@
void writeMetaBox();
void sendSessionSummary();
void release();
- status_t reset();
+ status_t switchFd();
+ status_t reset(bool stopSource = true);
static uint32_t getMpeg4Time();
+ void onMessageReceived(const sp<AMessage> &msg);
+
MPEG4Writer(const MPEG4Writer &);
MPEG4Writer &operator=(const MPEG4Writer &);
};
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index 2b19523..9c30ffa 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -50,6 +50,7 @@
virtual void setStartTimeOffsetMs(int /*ms*/) {}
virtual int32_t getStartTimeOffsetMs() const { return 0; }
+ virtual status_t setNextFd(int fd) { return INVALID_OPERATION; }
protected:
virtual ~MediaWriter() {}
diff --git a/media/libaudiohal/DevicesFactoryHalHidl.cpp b/media/libaudiohal/DevicesFactoryHalHidl.cpp
index a91f145..b0f28b9 100644
--- a/media/libaudiohal/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/DevicesFactoryHalHidl.cpp
@@ -65,6 +65,9 @@
} else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
*device = IDevicesFactory::Device::R_SUBMIX;
return OK;
+ } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_STUB) == 0) {
+ *device = IDevicesFactory::Device::STUB;
+ return OK;
}
ALOGE("Invalid device name %s", name);
return BAD_VALUE;
diff --git a/media/libaudiohal/EffectHalHidl.cpp b/media/libaudiohal/EffectHalHidl.cpp
index 6cf6412..d74ef8a 100644
--- a/media/libaudiohal/EffectHalHidl.cpp
+++ b/media/libaudiohal/EffectHalHidl.cpp
@@ -172,7 +172,7 @@
}
status_t status;
uint32_t replySizeStub = 0;
- if (replySize == nullptr) replySize = &replySizeStub;
+ if (replySize == nullptr || pReplyData == nullptr) replySize = &replySizeStub;
Return<void> ret = mEffect->command(cmdCode, hidlData, *replySize,
[&](int32_t s, const hidl_vec<uint8_t>& result) {
status = s;
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 5599830..5730c76 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -50,6 +50,7 @@
SET_VIDEO_ENCODER,
SET_AUDIO_ENCODER,
SET_OUTPUT_FILE_FD,
+ SET_NEXT_OUTPUT_FILE_FD,
SET_VIDEO_SIZE,
SET_VIDEO_FRAMERATE,
SET_PARAMETERS,
@@ -172,17 +173,24 @@
return reply.readInt32();
}
- status_t setOutputFile(int fd, int64_t offset, int64_t length) {
- ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
+ status_t setOutputFile(int fd) {
+ ALOGV("setOutputFile(%d)", fd);
Parcel data, reply;
data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
data.writeFileDescriptor(fd);
- data.writeInt64(offset);
- data.writeInt64(length);
remote()->transact(SET_OUTPUT_FILE_FD, data, &reply);
return reply.readInt32();
}
+ status_t setNextOutputFile(int fd) {
+ ALOGV("setNextOutputFile(%d)", fd);
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ data.writeFileDescriptor(fd);
+ remote()->transact(SET_NEXT_OUTPUT_FILE_FD, data, &reply);
+ return reply.readInt32();
+ }
+
status_t setVideoSize(int width, int height)
{
ALOGV("setVideoSize(%dx%d)", width, height);
@@ -429,9 +437,15 @@
ALOGV("SET_OUTPUT_FILE_FD");
CHECK_INTERFACE(IMediaRecorder, data, reply);
int fd = dup(data.readFileDescriptor());
- int64_t offset = data.readInt64();
- int64_t length = data.readInt64();
- reply->writeInt32(setOutputFile(fd, offset, length));
+ reply->writeInt32(setOutputFile(fd));
+ ::close(fd);
+ return NO_ERROR;
+ } break;
+ case SET_NEXT_OUTPUT_FILE_FD: {
+ ALOGV("SET_NEXT_OUTPUT_FILE_FD");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ int fd = dup(data.readFileDescriptor());
+ reply->writeInt32(setNextOutputFile(fd));
::close(fd);
return NO_ERROR;
} break;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 6bba1f1..40af8de 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -136,8 +136,10 @@
mPlayer = player;
if (player != 0) {
mCurrentState = MEDIA_PLAYER_INITIALIZED;
+ player->getDefaultBufferingSettings(&mCurrentBufferingSettings);
err = NO_ERROR;
} else {
+ mCurrentBufferingSettings = BufferingSettings();
ALOGE("Unable to create media player");
}
}
@@ -255,6 +257,18 @@
return mPlayer->getDefaultBufferingSettings(buffering);
}
+status_t MediaPlayer::getBufferingSettings(BufferingSettings* buffering /* nonnull */)
+{
+ ALOGV("getBufferingSettings");
+
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) {
+ return NO_INIT;
+ }
+ *buffering = mCurrentBufferingSettings;
+ return NO_ERROR;
+}
+
status_t MediaPlayer::setBufferingSettings(const BufferingSettings& buffering)
{
ALOGV("setBufferingSettings");
@@ -263,7 +277,11 @@
if (mPlayer == 0) {
return NO_INIT;
}
- return mPlayer->setBufferingSettings(buffering);
+ status_t err = mPlayer->setBufferingSettings(buffering);
+ if (err == NO_ERROR) {
+ mCurrentBufferingSettings = buffering;
+ }
+ return err;
}
// must call with lock held
@@ -606,6 +624,7 @@
// setDataSource has to be called again to create a
// new mediaplayer.
mPlayer = 0;
+ mCurrentBufferingSettings = BufferingSettings();
return ret;
}
clear_l();
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6eb208c..39a7710 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -256,6 +256,7 @@
return INVALID_OPERATION;
}
+
status_t ret = mMediaRecorder->setAudioEncoder(ae);
if (OK != ret) {
ALOGV("setAudioEncoder failed: %d", ret);
@@ -266,9 +267,9 @@
return ret;
}
-status_t MediaRecorder::setOutputFile(int fd, int64_t offset, int64_t length)
+status_t MediaRecorder::setOutputFile(int fd)
{
- ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
+ ALOGV("setOutputFile(%d)", fd);
if (mMediaRecorder == NULL) {
ALOGE("media recorder is not initialized yet");
return INVALID_OPERATION;
@@ -288,14 +289,16 @@
// the invalid file descritpor never gets invoked. This is to workaround
// this issue by checking the file descriptor first before passing
// it through binder call.
- if (fd < 0) {
- ALOGE("Invalid file descriptor: %d", fd);
+ int flags = fcntl(fd, F_GETFL);
+ // fd must be in read-write mode.
+ if (flags == -1 || (flags & O_RDWR) == 0) {
+ ALOGE("Invalid file descriptor: %d err: %s", fd, strerror(errno));
return BAD_VALUE;
}
- status_t ret = mMediaRecorder->setOutputFile(fd, offset, length);
+ status_t ret = mMediaRecorder->setOutputFile(fd);
if (OK != ret) {
- ALOGV("setOutputFile failed: %d", ret);
+ ALOGE("setOutputFile failed: %d", ret);
mCurrentState = MEDIA_RECORDER_ERROR;
return ret;
}
@@ -303,6 +306,34 @@
return ret;
}
+status_t MediaRecorder::setNextOutputFile(int fd)
+{
+ ALOGV("setNextOutputFile(%d)", fd);
+ if (mMediaRecorder == NULL) {
+ ALOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+
+ // It appears that if an invalid file descriptor is passed through
+ // binder calls, the server-side of the inter-process function call
+ // is skipped. As a result, the check at the server-side to catch
+ // the invalid file descritpor never gets invoked. This is to workaround
+ // this issue by checking the file descriptor first before passing
+ // it through binder call.
+ int flags = fcntl(fd, F_GETFL);
+ // fd must be in read-write mode.
+ if (flags == -1 || (flags & O_RDWR) == 0) {
+ ALOGE("Invalid file descriptor: %d err: %s", fd, strerror(errno));
+ return BAD_VALUE;
+ }
+
+ status_t ret = mMediaRecorder->setNextOutputFile(fd);
+ if (OK != ret) {
+ ALOGE("setNextOutputFile failed: %d", ret);
+ }
+ return ret;
+}
+
status_t MediaRecorder::setVideoSize(int width, int height)
{
ALOGV("setVideoSize(%d, %d)", width, height);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 2a07e5b..bb2d28b 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -161,15 +161,26 @@
return mRecorder->setAudioEncoder((audio_encoder)ae);
}
-status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
+status_t MediaRecorderClient::setOutputFile(int fd)
{
- ALOGV("setOutputFile(%d, %lld, %lld)", fd, (long long)offset, (long long)length);
+ ALOGV("setOutputFile(%d)", fd);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
ALOGE("recorder is not initialized");
return NO_INIT;
}
- return mRecorder->setOutputFile(fd, offset, length);
+ return mRecorder->setOutputFile(fd);
+}
+
+status_t MediaRecorderClient::setNextOutputFile(int fd)
+{
+ ALOGV("setNextOutputFile(%d)", fd);
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->setNextOutputFile(fd);
}
status_t MediaRecorderClient::setVideoSize(int width, int height)
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 83ef80a..8ddd680 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -53,8 +53,8 @@
virtual status_t setOutputFormat(int of);
virtual status_t setVideoEncoder(int ve);
virtual status_t setAudioEncoder(int ae);
- virtual status_t setOutputFile(int fd, int64_t offset,
- int64_t length);
+ virtual status_t setOutputFile(int fd);
+ virtual status_t setNextOutputFile(int fd);
virtual status_t setVideoSize(int width, int height);
virtual status_t setVideoFrameRate(int frames_per_second);
virtual status_t setParameters(const String8& params);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 279bc86..9ce65c4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -255,11 +255,8 @@
return OK;
}
-status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
- ALOGV("setOutputFile: %d, %lld, %lld", fd, (long long)offset, (long long)length);
- // These don't make any sense, do they?
- CHECK_EQ(offset, 0ll);
- CHECK_EQ(length, 0ll);
+status_t StagefrightRecorder::setOutputFile(int fd) {
+ ALOGV("setOutputFile: %d", fd);
if (fd < 0) {
ALOGE("Invalid file descriptor: %d", fd);
@@ -277,6 +274,25 @@
return OK;
}
+status_t StagefrightRecorder::setNextOutputFile(int fd) {
+ // Only support MPEG4
+ if (mOutputFormat != OUTPUT_FORMAT_MPEG_4) {
+ ALOGE("Only MP4 file format supports setting next output file");
+ return INVALID_OPERATION;
+ }
+ ALOGV("setNextOutputFile: %d", fd);
+
+ if (fd < 0) {
+ ALOGE("Invalid file descriptor: %d", fd);
+ return -EBADF;
+ }
+
+ // start with a clean, empty file
+ ftruncate(fd, 0);
+ int nextFd = dup(fd);
+ return mWriter->setNextFd(nextFd);
+}
+
// Attempt to parse an float literal optionally surrounded by whitespace,
// returns true on success, false otherwise.
static bool safe_strtof(const char *s, float *val) {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 4c2e65c..870c5d0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -55,7 +55,8 @@
virtual status_t setCamera(const sp<hardware::ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
virtual status_t setInputSurface(const sp<PersistentSurface>& surface);
- virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
+ virtual status_t setOutputFile(int fd);
+ virtual status_t setNextOutputFile(int fd);
virtual status_t setParameters(const String8 ¶ms);
virtual status_t setListener(const sp<IMediaRecorderClient> &listener);
virtual status_t setClientName(const String16 &clientName);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 02a1239..ef288da 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -101,7 +101,7 @@
~Track();
status_t start(MetaData *params);
- status_t stop();
+ status_t stop(bool stopSource = true);
status_t pause();
bool reachedEOS();
@@ -118,6 +118,7 @@
status_t dump(int fd, const Vector<String16>& args) const;
static const char *getFourCCForMime(const char *mime);
const char *getTrackType() const;
+ void resetInternal();
private:
enum {
@@ -275,6 +276,7 @@
bool mIsAudio;
bool mIsVideo;
bool mIsMPEG4;
+ bool mGotStartKeyFrame;
bool mIsMalformed;
int32_t mTrackId;
int64_t mTrackDurationUs;
@@ -411,41 +413,8 @@
Track &operator=(const Track &);
};
-MPEG4Writer::MPEG4Writer(int fd)
- : mFd(dup(fd)),
- mInitCheck(mFd < 0? NO_INIT: OK),
- mIsRealTimeRecording(true),
- mUse4ByteNalLength(true),
- mUse32BitOffset(true),
- mIsFileSizeLimitExplicitlyRequested(false),
- mPaused(false),
- mStarted(false),
- mWriterThreadStarted(false),
- mOffset(0),
- mMdatOffset(0),
- mMoovBoxBuffer(NULL),
- mMoovBoxBufferOffset(0),
- mWriteMoovBoxToMemory(false),
- mFreeBoxOffset(0),
- mStreamableFile(false),
- mEstimatedMoovBoxSize(0),
- mMoovExtraSize(0),
- mInterleaveDurationUs(1000000),
- mTimeScale(-1),
- mStartTimestampUs(-1ll),
- mLatitudex10000(0),
- mLongitudex10000(0),
- mAreGeoTagsAvailable(false),
- mStartTimeOffsetMs(-1),
- mMetaKeys(new AMessage()) {
- addDeviceMeta();
-
- // Verify mFd is seekable
- off64_t off = lseek64(mFd, 0, SEEK_SET);
- if (off < 0) {
- ALOGE("cannot seek mFd: %s (%d)", strerror(errno), errno);
- release();
- }
+MPEG4Writer::MPEG4Writer(int fd) {
+ initInternal(fd);
}
MPEG4Writer::~MPEG4Writer() {
@@ -458,6 +427,54 @@
mTracks.erase(it);
}
mTracks.clear();
+
+ if (mNextFd != -1) {
+ close(mNextFd);
+ }
+}
+
+void MPEG4Writer::initInternal(int fd) {
+ ALOGV("initInternal");
+ mFd = fd;
+ mNextFd = -1;
+ mInitCheck = mFd < 0? NO_INIT: OK;
+ mIsRealTimeRecording = true;
+ mUse4ByteNalLength = true;
+ mUse32BitOffset = true;
+ mIsFileSizeLimitExplicitlyRequested = false;
+ mPaused = false;
+ mStarted = false;
+ mWriterThreadStarted = false;
+ mSendNotify = false;
+ mOffset = 0;
+ mMdatOffset = 0;
+ mMoovBoxBuffer = NULL;
+ mMoovBoxBufferOffset = 0;
+ mWriteMoovBoxToMemory = false;
+ mFreeBoxOffset = 0;
+ mStreamableFile = false;
+ mEstimatedMoovBoxSize = 0;
+ mMoovExtraSize = 0;
+ mInterleaveDurationUs = 1000000;
+ mTimeScale = -1;
+ mStartTimestampUs = -1ll;
+ mLatitudex10000 = 0;
+ mLongitudex10000 = 0;
+ mAreGeoTagsAvailable = false;
+ mStartTimeOffsetMs = -1;
+ mSwitchPending = false;
+ mMetaKeys = new AMessage();
+ addDeviceMeta();
+ // Verify mFd is seekable
+ off64_t off = lseek64(mFd, 0, SEEK_SET);
+ if (off < 0) {
+ ALOGE("cannot seek mFd: %s (%d) %lld", strerror(errno), errno, (long long)mFd);
+ release();
+ }
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ (*it)->resetInternal();
+ }
}
status_t MPEG4Writer::dump(
@@ -667,6 +684,7 @@
if (mInitCheck != OK) {
return UNKNOWN_ERROR;
}
+ mStartMeta = param;
/*
* Check mMaxFileSizeLimitBytes at the beginning
@@ -924,7 +942,30 @@
mMoovBoxBuffer = NULL;
}
-status_t MPEG4Writer::reset() {
+void MPEG4Writer::finishCurrentSession() {
+ reset(false /* stopSource */);
+}
+
+status_t MPEG4Writer::switchFd() {
+ ALOGV("switchFd");
+ Mutex::Autolock l(mLock);
+ if (mSwitchPending) {
+ return OK;
+ }
+
+ if (mNextFd == -1) {
+ ALOGW("No FileDescripter for next recording");
+ return INVALID_OPERATION;
+ }
+
+ mSwitchPending = true;
+ sp<AMessage> msg = new AMessage(kWhatSwitch, mReflector);
+ status_t err = msg->post();
+
+ return err;
+}
+
+status_t MPEG4Writer::reset(bool stopSource) {
if (mInitCheck != OK) {
return OK;
} else {
@@ -943,7 +984,7 @@
int64_t minDurationUs = 0x7fffffffffffffffLL;
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
- status_t status = (*it)->stop();
+ status_t status = (*it)->stop(stopSource);
if (err == OK && status != OK) {
err = status;
}
@@ -1433,6 +1474,18 @@
return OK;
}
+void MPEG4Writer::notifyApproachingLimit() {
+ Mutex::Autolock autolock(mLock);
+ // Only notify once.
+ if (mSendNotify) {
+ return;
+ }
+ ALOGW("Recorded file size is approaching limit %" PRId64 "bytes",
+ mMaxFileSizeLimitBytes);
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING, 0);
+ mSendNotify = true;
+}
+
void MPEG4Writer::write(const void *data, size_t size) {
write(data, 1, size);
}
@@ -1446,7 +1499,6 @@
if (mMaxFileSizeLimitBytes == 0) {
return false;
}
-
int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
for (List<Track *>::iterator it = mTracks.begin();
it != mTracks.end(); ++it) {
@@ -1457,12 +1509,33 @@
// Add 1024 bytes as error tolerance
return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
}
+
// Be conservative in the estimate: do not exceed 95% of
// the target file limit. For small target file size limit, though,
// this will not help.
return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
}
+bool MPEG4Writer::approachingFileSizeLimit() {
+ // No limit
+ if (mMaxFileSizeLimitBytes == 0) {
+ return false;
+ }
+
+ int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
+ for (List<Track *>::iterator it = mTracks.begin();
+ it != mTracks.end(); ++it) {
+ nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
+ }
+
+ if (!mStreamableFile) {
+ // Add 1024 bytes as error tolerance
+ return nTotalBytesEstimate + 1024 >= (90 * mMaxFileSizeLimitBytes) / 100;
+ }
+
+ return (nTotalBytesEstimate >= (90 * mMaxFileSizeLimitBytes) / 100);
+}
+
bool MPEG4Writer::exceedsFileDurationLimit() {
// No limit
if (mMaxFileDurationLimitUs == 0) {
@@ -1522,6 +1595,7 @@
mPaused(false),
mResumed(false),
mStarted(false),
+ mGotStartKeyFrame(false),
mIsMalformed(false),
mTrackId(trackId),
mTrackDurationUs(0),
@@ -1561,6 +1635,50 @@
setTimeScale();
}
+// Clear all the internal states except the CSD data.
+void MPEG4Writer::Track::resetInternal() {
+ mDone = false;
+ mPaused = false;
+ mResumed = false;
+ mStarted = false;
+ mGotStartKeyFrame = false;
+ mIsMalformed = false;
+ mTrackDurationUs = 0;
+ mEstimatedTrackSizeBytes = 0;
+ mSamplesHaveSameSize = 0;
+ if (mStszTableEntries != NULL) {
+ delete mStszTableEntries;
+ mStszTableEntries = new ListTableEntries<uint32_t, 1>(1000);
+ }
+
+ if (mStcoTableEntries != NULL) {
+ delete mStcoTableEntries;
+ mStcoTableEntries = new ListTableEntries<uint32_t, 1>(1000);
+ }
+ if (mCo64TableEntries != NULL) {
+ delete mCo64TableEntries;
+ mCo64TableEntries = new ListTableEntries<off64_t, 1>(1000);
+ }
+
+ if (mStscTableEntries != NULL) {
+ delete mStscTableEntries;
+ mStscTableEntries = new ListTableEntries<uint32_t, 3>(1000);
+ }
+ if (mStssTableEntries != NULL) {
+ delete mStssTableEntries;
+ mStssTableEntries = new ListTableEntries<uint32_t, 1>(1000);
+ }
+ if (mSttsTableEntries != NULL) {
+ delete mSttsTableEntries;
+ mSttsTableEntries = new ListTableEntries<uint32_t, 2>(1000);
+ }
+ if (mCttsTableEntries != NULL) {
+ delete mCttsTableEntries;
+ mCttsTableEntries = new ListTableEntries<uint32_t, 2>(1000);
+ }
+ mReachedEOS = false;
+}
+
void MPEG4Writer::Track::updateTrackSizeEstimate() {
uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
@@ -1614,6 +1732,24 @@
mCttsTableEntries->add(htonl(duration));
}
+status_t MPEG4Writer::setNextFd(int fd) {
+ ALOGV("addNextFd");
+ Mutex::Autolock l(mLock);
+ if (mLooper == NULL) {
+ mReflector = new AHandlerReflector<MPEG4Writer>(this);
+ mLooper = new ALooper;
+ mLooper->registerHandler(mReflector);
+ mLooper->start();
+ }
+
+ if (mNextFd != -1) {
+ // No need to set a new FD yet.
+ return INVALID_OPERATION;
+ }
+ mNextFd = fd;
+ return OK;
+}
+
void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
if (mOwner->use32BitFileOffset()) {
uint32_t value = offset;
@@ -1645,8 +1781,29 @@
CHECK_GT(mTimeScale, 0);
}
+void MPEG4Writer::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatSwitch:
+ {
+ finishCurrentSession();
+ mLock.lock();
+ int fd = mNextFd;
+ mNextFd = -1;
+ mLock.unlock();
+ initInternal(fd);
+ start(mStartMeta.get());
+ mSwitchPending = false;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, 0);
+ break;
+ }
+ default:
+ TRESPASS();
+ }
+}
+
void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
const char *mime;
+
CHECK(mMeta->findCString(kKeyMIMEType, &mime));
uint32_t type;
@@ -1949,8 +2106,8 @@
return OK;
}
-status_t MPEG4Writer::Track::stop() {
- ALOGD("%s track stopping", getTrackType());
+status_t MPEG4Writer::Track::stop(bool stopSource) {
+ ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
if (!mStarted) {
ALOGE("Stop() called but track is not started");
return ERROR_END_OF_STREAM;
@@ -1960,16 +2117,17 @@
return OK;
}
mDone = true;
-
- ALOGD("%s track source stopping", getTrackType());
- mSource->stop();
- ALOGD("%s track source stopped", getTrackType());
+ if (stopSource) {
+ ALOGD("%s track source stopping", getTrackType());
+ mSource->stop();
+ ALOGD("%s track source stopped", getTrackType());
+ }
void *dummy;
pthread_join(mThread, &dummy);
status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
- ALOGD("%s track stopped", getTrackType());
+ ALOGD("%s track stopped. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
return err;
}
@@ -2476,13 +2634,20 @@
updateTrackSizeEstimate();
if (mOwner->exceedsFileSizeLimit()) {
- ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
- mOwner->mMaxFileSizeLimitBytes);
- mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ if (mOwner->switchFd() != OK) {
+ ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
+ mOwner->mMaxFileSizeLimitBytes);
+ mSource->stop();
+ mOwner->notify(
+ MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ } else {
+ ALOGV("%s Current recorded file size exceeds limit %" PRId64 "bytes. Switching output",
+ getTrackType(), mOwner->mMaxFileSizeLimitBytes);
+ }
copy->release();
- mSource->stop();
break;
}
+
if (mOwner->exceedsFileDurationLimit()) {
ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds",
mOwner->mMaxFileDurationLimitUs);
@@ -2492,11 +2657,23 @@
break;
}
+ if (mOwner->approachingFileSizeLimit()) {
+ mOwner->notifyApproachingLimit();
+ }
int32_t isSync = false;
meta_data->findInt32(kKeyIsSyncFrame, &isSync);
CHECK(meta_data->findInt64(kKeyTime, ×tampUs));
+ // For video, skip the first several non-key frames until getting the first key frame.
+ if (mIsVideo && !mGotStartKeyFrame && !isSync) {
+ ALOGD("Video skip non-key frame");
+ copy->release();
+ continue;
+ }
+ if (mIsVideo && isSync) {
+ mGotStartKeyFrame = true;
+ }
////////////////////////////////////////////////////////////////////////////////
if (mStszTableEntries->count() == 0) {
mFirstSampleTimeRealUs = systemTime() / 1000;
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index d419133..ea58343 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -466,7 +466,7 @@
mr->setVideoSource(videoSource);
mr->setOutputFormat(outputFormat);
mr->setVideoEncoder(videoEncoder);
- mr->setOutputFile(fd, 0, 0);
+ mr->setOutputFile(fd);
mr->setVideoSize(width, height);
mr->setVideoFrameRate(fps);
mr->prepare();
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index d0696a8..9f0f8bf 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -27,6 +27,7 @@
#include <string.h>
#include <sys/endian.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -488,13 +489,15 @@
mFd(fd),
mAllocSize(alloc_size) {
if (ioctl(mFd, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(mAllocSize)))
- PLOG(DEBUG) << "FFS endpoint alloc failed!";
+ PLOG(ERROR) << "FFS endpoint alloc failed!";
}
~ScopedEndpointBufferAlloc() {
if (ioctl(mFd, FUNCTIONFS_ENDPOINT_ALLOC, static_cast<__u32>(0)))
- PLOG(DEBUG) << "FFS endpoint alloc reset failed!";
+ PLOG(ERROR) << "FFS endpoint alloc reset failed!";
}
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedEndpointBufferAlloc);
};
/* Read from USB and write to a local file. */
@@ -524,7 +527,9 @@
bool write = false;
posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
- ScopedEndpointBufferAlloc(mBulkOut, mMaxRead);
+ posix_madvise(data, buf1_len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
+ posix_madvise(data2, buf2_len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
+ ScopedEndpointBufferAlloc scoped_alloc(mBulkOut, mMaxRead);
// Break down the file into pieces that fit in buffers
while (file_length > 0 || write) {
@@ -602,8 +607,6 @@
packet_size = mBulkIn_desc.wMaxPacketSize;
}
- posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
-
int init_read_len = packet_size - sizeof(mtp_data_header);
int buf1_len = std::max(static_cast<uint64_t>(packet_size), std::min(
static_cast<uint64_t>(MAX_FILE_CHUNK_SIZE), file_length - init_read_len));
@@ -616,6 +619,10 @@
std::vector<char> buf2(std::max(0, buf2_len));
char *data2 = buf2.data();
+ posix_fadvise(mfr.fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
+ posix_madvise(data, buf1_len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
+ posix_madvise(data2, buf2_len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED);
+
struct aiocb aio;
aio.aio_fildes = mfr.fd;
struct aiocb *aiol[] = {&aio};
@@ -640,7 +647,7 @@
if (writeHandle(mBulkIn, data, packet_size) == -1) return -1;
if (file_length == 0) return 0;
- ScopedEndpointBufferAlloc(mBulkIn, mMaxWrite);
+ ScopedEndpointBufferAlloc scoped_alloc(mBulkIn, mMaxWrite);
// Break down the file into pieces that fit in buffers
while(file_length > 0) {
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 343ad25..2ce99e2 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1630,11 +1630,16 @@
// and 'update' / 'commit' do nothing for allocated buffers, thus
// it's not needed to consider any other buffers here.
mInBuffer->update();
- mOutBuffer->update();
+ if (mInBuffer->audioBuffer()->raw != mOutBuffer->audioBuffer()->raw) {
+ mOutBuffer->update();
+ }
for (size_t i = 0; i < size; i++) {
mEffects[i]->process();
}
- mOutBuffer->commit();
+ mInBuffer->commit();
+ if (mInBuffer->audioBuffer()->raw != mOutBuffer->audioBuffer()->raw) {
+ mOutBuffer->commit();
+ }
}
bool doResetVolume = false;
for (size_t i = 0; i < size; i++) {
@@ -1935,6 +1940,17 @@
}
}
+static void dumpInOutBuffer(
+ char *dump, size_t dumpSize, bool isInput, EffectBufferHalInterface *buffer) {
+ if (buffer->externalData() != nullptr) {
+ snprintf(dump, dumpSize, "%p -> %p",
+ isInput ? buffer->externalData() : buffer->audioBuffer()->raw,
+ isInput ? buffer->audioBuffer()->raw : buffer->externalData());
+ } else {
+ snprintf(dump, dumpSize, "%p", buffer->audioBuffer()->raw);
+ }
+}
+
void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
@@ -1952,11 +1968,14 @@
result.append("\tCould not lock mutex:\n");
}
- result.append("\tIn buffer Out buffer Active tracks:\n");
- snprintf(buffer, SIZE, "\t%p %p %d\n",
- mInBuffer->audioBuffer(),
- mOutBuffer->audioBuffer(),
- mActiveTrackCnt);
+ char inBufferStr[64], outBufferStr[64];
+ dumpInOutBuffer(inBufferStr, sizeof(inBufferStr), true, mInBuffer.get());
+ dumpInOutBuffer(outBufferStr, sizeof(outBufferStr), false, mOutBuffer.get());
+ snprintf(buffer, SIZE, "\t%-*s%-*s Active tracks:\n",
+ (int)strlen(inBufferStr), "In buffer ",
+ (int)strlen(outBufferStr), "Out buffer ");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "\t%s %s %d\n", inBufferStr, outBufferStr, mActiveTrackCnt);
result.append(buffer);
write(fd, result.string(), result.size());
diff --git a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy b/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
index 0afaa15..9a0894d 100644
--- a/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
+++ b/services/mediacodec/minijail/seccomp_policy/mediacodec-seccomp-arm.policy
@@ -12,6 +12,14 @@
dup: 1
ppoll: 1
mmap2: 1
+
+# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
+# parser support for '<' is in this needs to be modified to also prevent
+# |old_address| and |new_address| from touching the exception vector page, which
+# on ARM is statically loaded at 0xffff 0000. See
+# http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211h/Babfeega.html
+# for more details.
+mremap: arg3 == 3
munmap: 1
mprotect: 1
madvise: 1