diff options
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); |