summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/camera/CameraParameters.h30
-rw-r--r--include/media/stagefright/AudioSource.h3
-rw-r--r--media/libmedia/IMediaRecorder.cpp2
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp10
-rw-r--r--media/libstagefright/AudioSource.cpp26
-rw-r--r--media/libstagefright/AwesomePlayer.cpp68
-rw-r--r--media/libstagefright/CameraSource.cpp2
-rw-r--r--media/libstagefright/HTTPStream.cpp4
-rw-r--r--media/libstagefright/MPEG4Writer.cpp91
-rw-r--r--media/libstagefright/OMXCodec.cpp8
-rw-r--r--media/libstagefright/codecs/avc/enc/AVCEncoder.cpp54
-rw-r--r--media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp22
-rw-r--r--media/libstagefright/include/AVCEncoder.h1
-rw-r--r--media/libstagefright/include/M4vH263Encoder.h1
-rw-r--r--media/libstagefright/rtsp/AH263Assembler.cpp2
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp39
-rw-r--r--media/libstagefright/rtsp/ARTPConnection.cpp24
-rw-r--r--media/libstagefright/rtsp/ARTPConnection.h9
-rw-r--r--media/libstagefright/rtsp/ARTPSession.cpp5
-rw-r--r--media/libstagefright/rtsp/ARTPSource.cpp9
-rw-r--r--media/libstagefright/rtsp/ARTPWriter.cpp2
21 files changed, 214 insertions, 198 deletions
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index e12a694..6a5d254 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -171,10 +171,9 @@ public:
// Supported flash modes.
// Example value: "auto,on,off". Read only.
static const char KEY_SUPPORTED_FLASH_MODES[];
- // Current focus mode. If the camera does not support auto-focus, the value
- // should be FOCUS_MODE_FIXED. If the focus mode is not FOCUS_MODE_FIXED or
- // or FOCUS_MODE_INFINITY, applications should call
- // CameraHardwareInterface.autoFocus to start the focus.
+ // Current focus mode. This will not be empty. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus if focus mode is
+ // FOCUS_MODE_AUTO or FOCUS_MODE_MACRO.
// Example value: "auto" or FOCUS_MODE_XXX constants. Read/write.
static const char KEY_FOCUS_MODE[];
// Supported focus modes.
@@ -231,11 +230,16 @@ public:
// be in focus. The object is sharpest at the optimal focus distance. The
// depth of field is the far focus distance minus near focus distance.
//
- // Applications can read this parameter anytime to get the latest focus
- // distances. If the focus mode is FOCUS_MODE_EDOF, the values may be all
- // 0, which means focus distance is not applicable. If the focus mode is
- // FOCUS_MODE_CONTINUOUS and autofocus has started, focus distances may
- // change from time to time.
+ // Focus distances may change after starting auto focus, canceling auto
+ // focus, or starting the preview. Applications can read this anytime to get
+ // the latest focus distances. If the focus mode is FOCUS_MODE_CONTINUOUS,
+ // focus distances may change from time to time.
+ //
+ // This is intended to estimate the distance between the camera and the
+ // subject. After autofocus, the subject distance may be within near and far
+ // focus distance. However, the precision depends on the camera hardware,
+ // autofocus algorithm, the focus area, and the scene. The error can be
+ // large and it should be only used as a reference.
//
// Far focus distance > optimal focus distance > near focus distance. If
// the far focus distance is infinity, the value should be "Infinity" (case
@@ -348,10 +352,10 @@ public:
// continuously. Applications should not call
// CameraHardwareInterface.autoFocus in this mode.
static const char FOCUS_MODE_EDOF[];
- // Continuous focus mode. The camera continuously tries to focus. This is
- // ideal for shooting video or shooting photo of moving object. Continuous
- // focus starts when CameraHardwareInterface.autoFocus is called. Focus
- // callback will be only called once as soon as the picture is in focus.
+ // Continuous auto focus mode. The camera continuously tries to focus. This
+ // is ideal for shooting video or shooting photo of moving object. Auto
+ // focus starts when the parameter is set. Applications should not call
+ // CameraHardwareInterface.autoFocus in this mode.
static const char FOCUS_MODE_CONTINUOUS[];
// The camera determines the exposure by giving more weight to the
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index f1d45d2..2597e9e 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -60,7 +60,8 @@ private:
int64_t mStartTimeUs;
int16_t mMaxAmplitude;
int64_t mPrevSampleTimeUs;
- int64_t mNumLostFrames;
+ int64_t mTotalLostFrames;
+ int64_t mPrevLostBytes;
MediaBufferGroup *mGroup;
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 4eb63e8..947ff34 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -23,6 +23,7 @@
#include <camera/ICamera.h>
#include <media/IMediaRecorderClient.h>
#include <media/IMediaRecorder.h>
+#include <unistd.h>
namespace android {
@@ -373,6 +374,7 @@ status_t BnMediaRecorder::onTransact(
int64_t offset = data.readInt64();
int64_t length = data.readInt64();
reply->writeInt32(setOutputFile(fd, offset, length));
+ ::close(fd);
return NO_ERROR;
} break;
case SET_VIDEO_SIZE: {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f6f89c7..8481d49 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -55,11 +55,6 @@ StagefrightRecorder::StagefrightRecorder()
StagefrightRecorder::~StagefrightRecorder() {
LOGV("Destructor");
stop();
-
- if (mOutputFd >= 0) {
- ::close(mOutputFd);
- mOutputFd = -1;
- }
}
status_t StagefrightRecorder::init() {
@@ -1084,6 +1079,11 @@ status_t StagefrightRecorder::stop() {
mFlags = 0;
}
+ if (mOutputFd >= 0) {
+ ::close(mOutputFd);
+ mOutputFd = -1;
+ }
+
return OK;
}
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 99978e8..c8dfede 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -35,7 +35,8 @@ AudioSource::AudioSource(
: mStarted(false),
mCollectStats(false),
mPrevSampleTimeUs(0),
- mNumLostFrames(0),
+ mTotalLostFrames(0),
+ mPrevLostBytes(0),
mGroup(NULL) {
LOGV("sampleRate: %d, channels: %d", sampleRate, channels);
@@ -108,7 +109,8 @@ status_t AudioSource::stop() {
mStarted = false;
if (mCollectStats) {
- LOGI("Total lost audio frames: %lld", mNumLostFrames);
+ LOGI("Total lost audio frames: %lld",
+ mTotalLostFrames + (mPrevLostBytes >> 1));
}
return OK;
@@ -186,10 +188,11 @@ status_t AudioSource::read(
// Insert null frames when lost frames are detected.
int64_t timestampUs = mPrevSampleTimeUs;
uint32_t numLostBytes = mRecord->getInputFramesLost() << 1;
+ numLostBytes += mPrevLostBytes;
#if 0
// Simulate lost frames
- numLostBytes = ((rand() * 1.0 / RAND_MAX)) * kMaxBufferSize;
- numLostBytes &= 0xFFFFFFFE; // Alignment request
+ numLostBytes = ((rand() * 1.0 / RAND_MAX)) * 2 * kMaxBufferSize;
+ numLostBytes &= 0xFFFFFFFE; // Alignment requirement
// Reduce the chance to lose
if (rand() * 1.0 / RAND_MAX >= 0.05) {
@@ -197,13 +200,18 @@ status_t AudioSource::read(
}
#endif
if (numLostBytes > 0) {
- // Not expect too many lost frames!
- CHECK(numLostBytes <= kMaxBufferSize);
+ if (numLostBytes > kMaxBufferSize) {
+ mPrevLostBytes = numLostBytes - kMaxBufferSize;
+ numLostBytes = kMaxBufferSize;
+ }
+
+ CHECK_EQ(numLostBytes & 1, 0);
+ timestampUs += ((1000000LL * (numLostBytes >> 1)) +
+ (sampleRate >> 1)) / sampleRate;
- timestampUs += (1000000LL * numLostBytes >> 1) / sampleRate;
CHECK(timestampUs > mPrevSampleTimeUs);
if (mCollectStats) {
- mNumLostFrames += (numLostBytes >> 1);
+ mTotalLostFrames += (numLostBytes >> 1);
}
if ((err = skipFrame(timestampUs, options)) == -1) {
buffer->release();
@@ -240,7 +248,7 @@ status_t AudioSource::read(
buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs);
CHECK(timestampUs > mPrevSampleTimeUs);
- if (mNumLostFrames == 0) {
+ if (mTotalLostFrames == 0) {
CHECK_EQ(mPrevSampleTimeUs,
mStartTimeUs + (1000000LL * numFramesRecorded) / sampleRate);
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index e426fca..f2653cf 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -854,18 +854,6 @@ void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
status_t AwesomePlayer::initVideoDecoder() {
uint32_t flags = 0;
-#if 0
- if (mRTPSession != NULL) {
- // XXX hack.
-
- const char *mime;
- CHECK(mVideoTrack->getFormat()->findCString(kKeyMIMEType, &mime));
- if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
- flags |= OMXCodec::kPreferSoftwareCodecs;
- }
- }
-#endif
-
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false, // createEncoder
@@ -1019,6 +1007,12 @@ void AwesomePlayer::onVideoEvent() {
int64_t latenessUs = nowUs - timeUs;
+ if (mRTPSession != NULL) {
+ // We'll completely ignore timestamps for gtalk videochat
+ // and we'll play incoming video as fast as we get it.
+ latenessUs = 0;
+ }
+
if (latenessUs > 40000) {
// We're more than 40ms late.
LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
@@ -1222,7 +1216,7 @@ status_t AwesomePlayer::finishSetDataSource_l() {
MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
return setDataSource_l(extractor);
- } else if (!strcmp("rtsp://gtalk", mUri.string())) {
+ } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
if (mLooper == NULL) {
mLooper = new ALooper;
mLooper->start(
@@ -1231,6 +1225,22 @@ status_t AwesomePlayer::finishSetDataSource_l() {
PRIORITY_HIGHEST);
}
+ const char *startOfCodecString = &mUri.string()[13];
+ const char *startOfSlash1 = strchr(startOfCodecString, '/');
+ if (startOfSlash1 == NULL) {
+ return BAD_VALUE;
+ }
+ const char *startOfWidthString = &startOfSlash1[1];
+ const char *startOfSlash2 = strchr(startOfWidthString, '/');
+ if (startOfSlash2 == NULL) {
+ return BAD_VALUE;
+ }
+ const char *startOfHeightString = &startOfSlash2[1];
+
+ String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString);
+ String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString);
+ String8 heightString(startOfHeightString);
+
#if 0
mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434);
mLooper->registerHandler(mRTPPusher);
@@ -1257,8 +1267,8 @@ status_t AwesomePlayer::finishSetDataSource_l() {
"a=rtpmap:97 AMR/8000/1\r\n"
"a=fmtp:97 octet-align\r\n";
#elif 1
- // My GTalk H.264 SDP
- static const char *raw =
+ String8 sdp;
+ sdp.appendFormat(
"v=0\r\n"
"o=- 64 233572944 IN IP4 127.0.0.0\r\n"
"s=QuickTime\r\n"
@@ -1268,24 +1278,16 @@ status_t AwesomePlayer::finishSetDataSource_l() {
"m=video 5434 RTP/AVP 97\r\n"
"c=IN IP4 127.0.0.1\r\n"
"b=AS:30\r\n"
- "a=rtpmap:97 H264/90000\r\n"
- "a=cliprect:0,0,200,320\r\n"
- "a=framesize:97 320-200\r\n";
-#else
- // GTalk H263 SDP
- static const char *raw =
- "v=0\r\n"
- "o=- 64 233572944 IN IP4 127.0.0.0\r\n"
- "s=QuickTime\r\n"
- "t=0 0\r\n"
- "a=range:npt=0-315\r\n"
- "a=isma-compliance:2,2.0,2\r\n"
- "m=video 5434 RTP/AVP 98\r\n"
- "c=IN IP4 127.0.0.1\r\n"
- "b=AS:30\r\n"
- "a=rtpmap:98 H263-1998/90000\r\n"
- "a=cliprect:0,0,200,320\r\n"
- "a=framesize:98 320-200\r\n";
+ "a=rtpmap:97 %s/90000\r\n"
+ "a=cliprect:0,0,%s,%s\r\n"
+ "a=framesize:97 %s-%s\r\n",
+
+ codecString.string(),
+ heightString.string(), widthString.string(),
+ widthString.string(), heightString.string()
+ );
+ const char *raw = sdp.string();
+
#endif
sp<ASessionDescription> desc = new ASessionDescription;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 9c48daf..3e31d61 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -244,6 +244,7 @@ void CameraSource::releaseOneRecordingFrame(const sp<IMemory>& frame) {
void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
LOGV("signalBufferReturned: %p", buffer->data());
+ Mutex::Autolock autoLock(mLock);
for (List<sp<IMemory> >::iterator it = mFramesBeingEncoded.begin();
it != mFramesBeingEncoded.end(); ++it) {
if ((*it)->pointer() == buffer->data()) {
@@ -312,6 +313,7 @@ status_t CameraSource::read(
(*buffer)->setObserver(this);
(*buffer)->add_ref();
(*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
+
return OK;
}
}
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 9c99866..ccc6a34 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -68,7 +68,7 @@ status_t HTTPStream::connect(const char *server, int port) {
return UNKNOWN_ERROR;
}
- setReceiveTimeout(5); // Time out reads after 5 secs by default
+ setReceiveTimeout(30); // Time out reads after 30 secs by default
mState = CONNECTING;
@@ -158,7 +158,7 @@ status_t HTTPStream::send(const char *data) {
// The workaround accepts both behaviours but could potentially break
// legitimate responses that use a single newline to "fold" headers, which is
// why it's not yet on by default.
-#define WORKAROUND_FOR_MISSING_CR 0
+#define WORKAROUND_FOR_MISSING_CR 1
status_t HTTPStream::receive_line(char *line, size_t size) {
if (mState != CONNECTED) {
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 20fbc05..1460f37 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1377,91 +1377,6 @@ void MPEG4Writer::Track::threadEntry() {
mGotAllCodecSpecificData = true;
continue;
- } else if (!mGotAllCodecSpecificData &&
- count == 1 && mIsMPEG4 && mCodecSpecificData == NULL) {
- // The TI mpeg4 encoder does not properly set the
- // codec-specific-data flag.
-
- const uint8_t *data =
- (const uint8_t *)buffer->data() + buffer->range_offset();
-
- const size_t size = buffer->range_length();
-
- size_t offset = 0;
- while (offset + 3 < size) {
- if (data[offset] == 0x00 && data[offset + 1] == 0x00
- && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
- break;
- }
-
- ++offset;
- }
-
- // CHECK(offset + 3 < size);
- if (offset + 3 >= size) {
- // XXX assume the entire first chunk of data is the codec specific
- // data.
- offset = size;
- }
-
- mCodecSpecificDataSize = offset;
- mCodecSpecificData = malloc(offset);
- memcpy(mCodecSpecificData, data, offset);
-
- buffer->set_range(buffer->range_offset() + offset, size - offset);
-
- if (size == offset) {
- buffer->release();
- buffer = NULL;
-
- continue;
- }
-
- mGotAllCodecSpecificData = true;
- } else if (!mGotAllCodecSpecificData && mIsAvc && count < 3) {
- // The TI video encoder does not flag codec specific data
- // as such and also splits up SPS and PPS across two buffers.
-
- const uint8_t *data =
- (const uint8_t *)buffer->data() + buffer->range_offset();
-
- size_t size = buffer->range_length();
-
- CHECK(count == 2 || mCodecSpecificData == NULL);
-
- size_t offset = mCodecSpecificDataSize;
- mCodecSpecificDataSize += size + 4;
- mCodecSpecificData =
- realloc(mCodecSpecificData, mCodecSpecificDataSize);
-
- memcpy((uint8_t *)mCodecSpecificData + offset,
- "\x00\x00\x00\x01", 4);
-
- memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
-
- buffer->release();
- buffer = NULL;
-
- if (count == 2) {
- void *tmp = mCodecSpecificData;
- size = mCodecSpecificDataSize;
- mCodecSpecificData = NULL;
- mCodecSpecificDataSize = 0;
-
- status_t err = makeAVCCodecSpecificData(
- (const uint8_t *)tmp, size);
- free(tmp);
- tmp = NULL;
- CHECK_EQ(OK, err);
-
- mGotAllCodecSpecificData = true;
- }
-
- continue;
- }
-
- if (!mGotAllCodecSpecificData) {
- mGotAllCodecSpecificData = true;
}
// Make a deep copy of the MediaBuffer and Metadata and release
@@ -1962,6 +1877,8 @@ void MPEG4Writer::Track::writeTrackHeader(
mOwner->writeInt32(samplerate << 16);
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
mOwner->beginBox("esds");
+ CHECK(mCodecSpecificData);
+ CHECK(mCodecSpecificDataSize > 0);
mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt8(0x03); // ES_DescrTag
@@ -2042,6 +1959,8 @@ void MPEG4Writer::Track::writeTrackHeader(
CHECK(23 + mCodecSpecificDataSize < 128);
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
+ CHECK(mCodecSpecificData);
+ CHECK(mCodecSpecificDataSize > 0);
mOwner->beginBox("esds");
mOwner->writeInt32(0); // version=0, flags=0
@@ -2086,6 +2005,8 @@ void MPEG4Writer::Track::writeTrackHeader(
mOwner->endBox(); // d263
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+ CHECK(mCodecSpecificData);
+ CHECK(mCodecSpecificDataSize > 0);
mOwner->beginBox("avcC");
mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
mOwner->endBox(); // avcC
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 11396ef..4741b1d 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1685,6 +1685,14 @@ void OMXCodec::on_message(const omx_message &msg) {
MediaBuffer *buffer = info->mMediaBuffer;
+ if (msg.u.extended_buffer_data.range_offset
+ + msg.u.extended_buffer_data.range_length
+ > buffer->size()) {
+ CODEC_LOGE(
+ "Codec lied about its buffer size requirements, "
+ "sending a buffer larger than the originally "
+ "advertised size in FILL_BUFFER_DONE!");
+ }
buffer->set_range(
msg.u.extended_buffer_data.range_offset,
msg.u.extended_buffer_data.range_length);
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index d5eb156..389180c 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -98,6 +98,7 @@ AVCEncoder::AVCEncoder(
: mSource(source),
mMeta(meta),
mNumInputFrames(-1),
+ mPrevTimestampUs(-1),
mStarted(false),
mInputBuffer(NULL),
mInputFrameData(NULL),
@@ -337,14 +338,18 @@ status_t AVCEncoder::read(
MediaBuffer *outputBuffer;
CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
- uint8_t *outPtr = (uint8_t *) outputBuffer->data();
- uint32_t dataLength = outputBuffer->size();
+
+ // Add 4 bytes for the start code 0x00000001
+ uint8_t *outPtr = (uint8_t *) outputBuffer->data() + 4;
+ uint32_t dataLength = outputBuffer->size() - 4;
int32_t type;
AVCEnc_Status encoderStatus = AVCENC_SUCCESS;
- // Return SPS and PPS for the first two buffers
- if (!mSpsPpsHeaderReceived) {
+ // Combine SPS and PPS and place them in the very first output buffer
+ // SPS and PPS are separated by start code 0x00000001
+ // Assume that we have exactly one SPS and exactly one PPS.
+ while (!mSpsPpsHeaderReceived && mNumInputFrames <= 0) {
encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
if (encoderStatus == AVCENC_WRONG_STATE) {
mSpsPpsHeaderReceived = true;
@@ -352,11 +357,22 @@ status_t AVCEncoder::read(
} else {
switch (type) {
case AVC_NALTYPE_SPS:
+ ++mNumInputFrames;
+ memcpy(outputBuffer->data(), "\x00\x00\x00\x01", 4);
+ outputBuffer->set_range(0, dataLength + 4);
+ outPtr += (dataLength + 4); // 4 bytes for next start code
+ dataLength = outputBuffer->size() -
+ (outputBuffer->range_length() + 4);
+ break;
case AVC_NALTYPE_PPS:
- LOGV("%s received",
- (type == AVC_NALTYPE_SPS)? "SPS": "PPS");
++mNumInputFrames;
- outputBuffer->set_range(0, dataLength);
+ memcpy(((uint8_t *) outputBuffer->data()) +
+ outputBuffer->range_length(),
+ "\x00\x00\x00\x01", 4);
+ outputBuffer->set_range(0,
+ dataLength + outputBuffer->range_length() + 4);
+ outputBuffer->meta_data()->setInt32(kKeyIsCodecConfig, 1);
+ outputBuffer->meta_data()->setInt64(kKeyTime, 0);
*out = outputBuffer;
return OK;
default:
@@ -378,10 +394,34 @@ status_t AVCEncoder::read(
outputBuffer->release();
return err;
}
+
+ if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) {
+ outputBuffer->release();
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ return UNKNOWN_ERROR;
+ }
+
int64_t timeUs;
CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+ // When the timestamp of the current sample is the same as
+ // that of the previous sample, the encoding of the sample
+ // is bypassed, and the output length is set to 0.
+ if (mNumInputFrames >= 1 && mPrevTimestampUs == timeUs) {
+ // Frame arrives too late
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ outputBuffer->set_range(0, 0);
+ *out = outputBuffer;
+ return OK;
+ }
+
+ // Don't accept out-of-order samples
+ CHECK(mPrevTimestampUs < timeUs);
+ mPrevTimestampUs = timeUs;
+
AVCFrameIO videoInput;
memset(&videoInput, 0, sizeof(videoInput));
videoInput.height = ((mVideoHeight + 15) >> 4) << 4;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index 5002442..a011137 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -69,6 +69,7 @@ M4vH263Encoder::M4vH263Encoder(
mMeta(meta),
mNumInputFrames(-1),
mNextModTimeUs(0),
+ mPrevTimestampUs(-1),
mStarted(false),
mInputBuffer(NULL),
mInputFrameData(NULL),
@@ -294,10 +295,23 @@ status_t M4vH263Encoder::read(
outputBuffer->release();
return UNKNOWN_ERROR;
}
+
+ if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) {
+ outputBuffer->release();
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ return UNKNOWN_ERROR;
+ }
+
int64_t timeUs;
CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
- if (mNextModTimeUs > timeUs) {
- LOGV("mNextModTimeUs %lld > timeUs %lld", mNextModTimeUs, timeUs);
+
+ // When the timestamp of the current sample is the same as that
+ // of the previous sample, encoding of the current sample is
+ // bypassed, and the output length of the sample is set to 0
+ if (mNumInputFrames >= 1 &&
+ (mNextModTimeUs > timeUs || mPrevTimestampUs == timeUs)) {
+ // Frame arrives too late
outputBuffer->set_range(0, 0);
*out = outputBuffer;
mInputBuffer->release();
@@ -305,6 +319,10 @@ status_t M4vH263Encoder::read(
return OK;
}
+ // Don't accept out-of-order samples
+ CHECK(mPrevTimestampUs < timeUs);
+ mPrevTimestampUs = timeUs;
+
// Color convert to OMX_COLOR_FormatYUV420Planar if necessary
outputBuffer->meta_data()->setInt64(kKeyTime, timeUs);
uint8_t *inPtr = (uint8_t *) mInputBuffer->data();
diff --git a/media/libstagefright/include/AVCEncoder.h b/media/libstagefright/include/AVCEncoder.h
index 4fe2e30..83e1f97 100644
--- a/media/libstagefright/include/AVCEncoder.h
+++ b/media/libstagefright/include/AVCEncoder.h
@@ -64,6 +64,7 @@ private:
int32_t mVideoBitRate;
int32_t mVideoColorFormat;
int64_t mNumInputFrames;
+ int64_t mPrevTimestampUs;
status_t mInitCheck;
bool mStarted;
bool mSpsPpsHeaderReceived;
diff --git a/media/libstagefright/include/M4vH263Encoder.h b/media/libstagefright/include/M4vH263Encoder.h
index dd146f4..dbe9fd0 100644
--- a/media/libstagefright/include/M4vH263Encoder.h
+++ b/media/libstagefright/include/M4vH263Encoder.h
@@ -59,6 +59,7 @@ private:
int32_t mVideoColorFormat;
int64_t mNumInputFrames;
int64_t mNextModTimeUs;
+ int64_t mPrevTimestampUs;
status_t mInitCheck;
bool mStarted;
diff --git a/media/libstagefright/rtsp/AH263Assembler.cpp b/media/libstagefright/rtsp/AH263Assembler.cpp
index 8b59998..2818041 100644
--- a/media/libstagefright/rtsp/AH263Assembler.cpp
+++ b/media/libstagefright/rtsp/AH263Assembler.cpp
@@ -110,7 +110,7 @@ ARTPAssembler::AssemblyStatus AH263Assembler::addPacket(
buffer->data()[0] = 0x00;
buffer->data()[1] = 0x00;
} else {
- buffer->setRange(2, buffer->size() - 2);
+ buffer->setRange(buffer->offset() + 2, buffer->size() - 2);
}
mPackets.push_back(buffer);
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index a577704..224b4bf 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -356,24 +356,10 @@ status_t APacketSource::read(
if (!mBuffers.empty()) {
const sp<ABuffer> buffer = *mBuffers.begin();
- uint64_t ntpTime;
- CHECK(buffer->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
- mediaBuffer->meta_data()->setInt64(kKeyNTPTime, ntpTime);
-
- if (mFirstAccessUnit) {
- mFirstAccessUnit = false;
- mFirstAccessUnitNTP = ntpTime;
- }
- if (ntpTime > mFirstAccessUnitNTP) {
- ntpTime -= mFirstAccessUnitNTP;
- } else {
- ntpTime = 0;
- }
- int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
+ int64_t timeUs;
+ CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
@@ -390,10 +376,29 @@ status_t APacketSource::read(
void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
int32_t damaged;
if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
- // LOG(VERBOSE) << "discarding damaged AU";
+ LOG(VERBOSE) << "discarding damaged AU";
return;
}
+ uint64_t ntpTime;
+ CHECK(buffer->meta()->findInt64(
+ "ntp-time", (int64_t *)&ntpTime));
+
+ if (mFirstAccessUnit) {
+ mFirstAccessUnit = false;
+ mFirstAccessUnitNTP = ntpTime;
+ }
+
+ if (ntpTime > mFirstAccessUnitNTP) {
+ ntpTime -= mFirstAccessUnitNTP;
+ } else {
+ ntpTime = 0;
+ }
+
+ int64_t timeUs = (int64_t)(ntpTime * 1E6 / (1ll << 32));
+
+ buffer->meta()->setInt64("timeUs", timeUs);
+
Mutex::Autolock autoLock(mLock);
mBuffers.push_back(buffer);
mCondition.signal();
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 5bd306b..469af3e 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -28,8 +28,6 @@
#include <arpa/inet.h>
#include <sys/socket.h>
-#define IGNORE_RTCP_TIME 0
-
namespace android {
static const size_t kMaxUDPSize = 1500;
@@ -61,8 +59,9 @@ struct ARTPConnection::StreamInfo {
struct sockaddr_in mRemoteRTCPAddr;
};
-ARTPConnection::ARTPConnection()
- : mPollEventPending(false),
+ARTPConnection::ARTPConnection(uint32_t flags)
+ : mFlags(flags),
+ mPollEventPending(false),
mLastReceiverReportTimeUs(-1) {
}
@@ -280,7 +279,10 @@ void ARTPConnection::onPollStreams() {
sp<ARTPSource> source = s->mSources.valueAt(i);
source->addReceiverReport(buffer);
- source->addFIR(buffer);
+
+ if (mFlags & kRegularlyRequestFIR) {
+ source->addFIR(buffer);
+ }
}
if (buffer->size() > 0) {
@@ -405,13 +407,11 @@ status_t ARTPConnection::parseRTP(StreamInfo *s, const sp<ABuffer> &buffer) {
buffer->setInt32Data(u16at(&data[2]));
buffer->setRange(payloadOffset, size - payloadOffset);
-#if IGNORE_RTCP_TIME
- if (!source->timeEstablished()) {
+ if ((mFlags & kFakeTimestamps) && !source->timeEstablished()) {
source->timeUpdate(rtpTime, 0);
- source->timeUpdate(rtpTime + 20, 0x100000000ll);
+ source->timeUpdate(rtpTime + 90000, 0x100000000ll);
CHECK(source->timeEstablished());
}
-#endif
source->processRTPPacket(buffer);
@@ -533,9 +533,9 @@ status_t ARTPConnection::parseSR(
sp<ARTPSource> source = findSource(s, id);
-#if !IGNORE_RTCP_TIME
- source->timeUpdate(rtpTime, ntpTime);
-#endif
+ if ((mFlags & kFakeTimestamps) == 0) {
+ source->timeUpdate(rtpTime, ntpTime);
+ }
return 0;
}
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index 49839ad..c535199 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -28,7 +28,12 @@ struct ARTPSource;
struct ASessionDescription;
struct ARTPConnection : public AHandler {
- ARTPConnection();
+ enum Flags {
+ kFakeTimestamps = 1,
+ kRegularlyRequestFIR = 2,
+ };
+
+ ARTPConnection(uint32_t flags = 0);
void addStream(
int rtpSocket, int rtcpSocket,
@@ -56,6 +61,8 @@ private:
static const int64_t kSelectTimeoutUs;
+ uint32_t mFlags;
+
struct StreamInfo;
List<StreamInfo> mStreams;
diff --git a/media/libstagefright/rtsp/ARTPSession.cpp b/media/libstagefright/rtsp/ARTPSession.cpp
index 0e0f45a..e082078 100644
--- a/media/libstagefright/rtsp/ARTPSession.cpp
+++ b/media/libstagefright/rtsp/ARTPSession.cpp
@@ -40,7 +40,10 @@ status_t ARTPSession::setup(const sp<ASessionDescription> &desc) {
mDesc = desc;
- mRTPConn = new ARTPConnection;
+ mRTPConn = new ARTPConnection(
+ ARTPConnection::kFakeTimestamps
+ | ARTPConnection::kRegularlyRequestFIR);
+
looper()->registerHandler(mRTPConn);
for (size_t i = 1; i < mDesc->countTracks(); ++i) {
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index e08183e..225f6e8 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -98,7 +98,7 @@ void ARTPSource::timeUpdate(uint32_t rtpTime, uint64_t ntpTime) {
mNTPTime[mNumTimes] = ntpTime;
mRTPTime[mNumTimes++] = rtpTime;
- if (mNumTimes == 2) {
+ if (timeEstablished()) {
for (List<sp<ABuffer> >::iterator it = mQueue.begin();
it != mQueue.end(); ++it) {
sp<AMessage> meta = (*it)->meta();
@@ -112,13 +112,6 @@ void ARTPSource::timeUpdate(uint32_t rtpTime, uint64_t ntpTime) {
}
bool ARTPSource::queuePacket(const sp<ABuffer> &buffer) {
-#if 1
- if (mNumTimes != 2) {
- // Drop incoming packets until we've established a time base.
- return false;
- }
-#endif
-
uint32_t seqNum = (uint32_t)buffer->int32Data();
if (mNumTimes == 2) {
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index cc23856..d6dd597 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -43,7 +43,7 @@ ARTPWriter::ARTPWriter(int fd)
#if 1
mRTPAddr.sin_addr.s_addr = INADDR_ANY;
#else
- mRTPAddr.sin_addr.s_addr = inet_addr("172.19.19.74");
+ mRTPAddr.sin_addr.s_addr = inet_addr("172.19.18.246");
#endif
mRTPAddr.sin_port = htons(5634);