Merge "Added downsample()"
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index b2808f5..4bc1799 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -188,10 +188,9 @@
     // 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.
@@ -248,11 +247,16 @@
     // 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
@@ -350,11 +354,14 @@
     static const char PIXEL_FORMAT_JPEG[];
 
     // Values for focus mode settings.
-    // Auto-focus mode.
+    // Auto-focus mode. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus in this mode.
     static const char FOCUS_MODE_AUTO[];
     // Focus is set at infinity. Applications should not call
     // CameraHardwareInterface.autoFocus in this mode.
     static const char FOCUS_MODE_INFINITY[];
+    // Macro (close-up) focus mode. Applications should call
+    // CameraHardwareInterface.autoFocus to start the focus in this mode.
     static const char FOCUS_MODE_MACRO[];
     // Focus is fixed. The camera is always in this mode if the focus is not
     // adjustable. If the camera has auto-focus, this mode can fix the
@@ -365,10 +372,11 @@
     // 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.  To stop continuous
+    // focus, applications should change the focus mode to other modes.
     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 @@
     int64_t mStartTimeUs;
     int16_t mMaxAmplitude;
     int64_t mPrevSampleTimeUs;
-    int64_t mNumLostFrames;
+    int64_t mTotalLostFrames;
+    int64_t mPrevLostBytes;
 
     MediaBufferGroup *mGroup;
 
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 2e1e8d8..be96935 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -128,6 +128,12 @@
     // Write the first chunk from the given ChunkInfo.
     void writeFirstChunk(ChunkInfo* info);
 
+    // Adjust other track media clock (presumably wall clock)
+    // based on audio track media clock with the drift time.
+    int64_t mDriftTimeUs;
+    void addDriftTimeUs(int64_t driftTimeUs);
+    int64_t getDriftTimeUs();
+
     void lock();
     void unlock();
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index ab1fa4f..43354c2 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -86,10 +86,10 @@
 
     // Track authoring progress status
     // kKeyTrackTimeStatus is used to track progress in elapsed time
-    // kKeyTrackFrameStatus is used to track progress in authored frames
-    kKeyTrackFrameStatus  = 'tkfm',  // int32_t
     kKeyTrackTimeStatus   = 'tktm',  // int64_t
 
+    kKeyNotRealTime       = 'ntrt',  // bool (int32_t)
+
 };
 
 enum {
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 @@
             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 5756e53..a616aae 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -56,11 +56,6 @@
 StagefrightRecorder::~StagefrightRecorder() {
     LOGV("Destructor");
     stop();
-
-    if (mOutputFd >= 0) {
-        ::close(mOutputFd);
-        mOutputFd = -1;
-    }
 }
 
 status_t StagefrightRecorder::init() {
@@ -736,7 +731,9 @@
     encMeta->setInt32(kKeyChannelCount, mAudioChannels);
     encMeta->setInt32(kKeySampleRate, mSampleRate);
     encMeta->setInt32(kKeyBitRate, mAudioBitRate);
-    encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+    if (mAudioTimeScale > 0) {
+        encMeta->setInt32(kKeyTimeScale, mAudioTimeScale);
+    }
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
@@ -1037,7 +1034,9 @@
     enc_meta->setInt32(kKeyStride, stride);
     enc_meta->setInt32(kKeySliceHeight, sliceHeight);
     enc_meta->setInt32(kKeyColorFormat, colorFormat);
-    enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+    if (mVideoTimeScale > 0) {
+        enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
+    }
     if (mVideoEncoderProfile != -1) {
         enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
     }
@@ -1120,7 +1119,9 @@
     meta->setInt32(kKeyFileType, mOutputFormat);
     meta->setInt32(kKeyBitRate, totalBitRate);
     meta->setInt32(kKey64BitFileOffset, mUse64BitFileOffset);
-    meta->setInt32(kKeyTimeScale, mMovieTimeScale);
+    if (mMovieTimeScale > 0) {
+        meta->setInt32(kKeyTimeScale, mMovieTimeScale);
+    }
     if (mTrackEveryTimeDurationUs > 0) {
         meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
     }
@@ -1158,6 +1159,11 @@
         mFlags = 0;
     }
 
+    if (mOutputFd >= 0) {
+        ::close(mOutputFd);
+        mOutputFd = -1;
+    }
+
     return OK;
 }
 
@@ -1191,9 +1197,9 @@
     mIFramesIntervalSec = 1;
     mAudioSourceNode = 0;
     mUse64BitFileOffset = false;
-    mMovieTimeScale  = 1000;
-    mAudioTimeScale  = 1000;
-    mVideoTimeScale  = 1000;
+    mMovieTimeScale  = -1;
+    mAudioTimeScale  = -1;
+    mVideoTimeScale  = -1;
     mCameraId        = 0;
     mVideoEncoderProfile = -1;
     mVideoEncoderLevel   = -1;
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 @@
     : 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 @@
     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 @@
         // 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 @@
         }
 #endif
         if (numLostBytes > 0) {
-            // Not expect too many lost frames!
-            CHECK(numLostBytes <= kMaxBufferSize);
+            if (numLostBytes > kMaxBufferSize) {
+                mPrevLostBytes = numLostBytes - kMaxBufferSize;
+                numLostBytes = kMaxBufferSize;
+            }
 
-            timestampUs += (1000000LL * numLostBytes >> 1) / sampleRate;
+            CHECK_EQ(numLostBytes & 1, 0);
+            timestampUs += ((1000000LL * (numLostBytes >> 1)) +
+                    (sampleRate >> 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 @@
 
         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 efdad43..f2653cf 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1216,7 +1216,7 @@
             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(
@@ -1225,6 +1225,22 @@
                     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);
@@ -1251,8 +1267,8 @@
             "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"
@@ -1262,24 +1278,16 @@
             "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 5e7dd5c..9ccd140 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -260,6 +260,7 @@
 
 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()) {
@@ -327,6 +328,7 @@
                 (*buffer)->setObserver(this);
                 (*buffer)->add_ref();
                 (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
+
                 return OK;
             }
         }
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 1fd256a..ba99501 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -187,6 +187,7 @@
     if (mUseStillCameraForTimeLapse) {
         void *dummy;
         pthread_join(mThreadTimeLapse, &dummy);
+        CHECK_EQ(OK, mCamera->startPreview());
     } else {
         mCamera->stopRecording();
     }
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6af3a7f..12a1e6e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1273,6 +1273,14 @@
     hexdump(csd, csd_size);
 #endif
 
+    if (csd_size == 0) {
+        // There's no further information, i.e. no codec specific data
+        // Let's assume that the information provided in the mpeg4 headers
+        // is accurate and hope for the best.
+
+        return OK;
+    }
+
     if (csd_size < 2) {
         return ERROR_MALFORMED;
     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index c860c5c..f52ec1a 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -72,6 +72,11 @@
     bool mIsAudio;
     bool mIsMPEG4;
     int64_t mTrackDurationUs;
+
+    // For realtime applications, we need to adjust the media clock
+    // for video track based on the audio media clock
+    bool mIsRealTimeRecording;
+    int64_t mMaxTimeStampUs;
     int64_t mEstimatedTrackSizeBytes;
     int64_t mMaxWriteTimeUs;
     int32_t mTimeScale;
@@ -163,6 +168,12 @@
 
     void getCodecSpecificDataFromInputFormatIfPossible();
 
+    // Determine the track time scale
+    // If it is an audio track, try to use the sampling rate as
+    // the time scale; however, if user chooses the overwrite
+    // value, the user-supplied time scale will be used.
+    void setTimeScale();
+
     Track(const Track &);
     Track &operator=(const Track &);
 };
@@ -429,7 +440,7 @@
     mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
     mMoovBoxBufferOffset = 0;
     CHECK(mMoovBoxBuffer != NULL);
-    int32_t duration = (maxDurationUs * mTimeScale) / 1E6;
+    int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6;
 
     beginBox("moov");
 
@@ -744,10 +755,6 @@
       mReachedEOS(false) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
-    if (!mMeta->findInt32(kKeyTimeScale, &mTimeScale)) {
-        mTimeScale = 1000;
-    }
-
     const char *mime;
     mMeta->findCString(kKeyMIMEType, &mime);
     mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
@@ -755,6 +762,28 @@
     mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
 
+    setTimeScale();
+}
+
+void MPEG4Writer::Track::setTimeScale() {
+    LOGV("setTimeScale");
+    // Default time scale
+    mTimeScale = 90000;
+
+    if (mIsAudio) {
+        // Use the sampling rate as the default time scale for audio track.
+        int32_t sampleRate;
+        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
+        CHECK(success);
+        mTimeScale = sampleRate;
+    }
+
+    // If someone would like to overwrite the timescale, use user-supplied value.
+    int32_t timeScale;
+    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
+        mTimeScale = timeScale;
+    }
+
     CHECK(mTimeScale > 0);
 }
 
@@ -940,6 +969,7 @@
 
     mDone = false;
     mIsFirstChunk = true;
+    mDriftTimeUs = 0;
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
         ChunkInfo info;
@@ -967,6 +997,14 @@
         startTimeUs = 0;
     }
 
+    mIsRealTimeRecording = true;
+    {
+        int32_t isNotRealTime;
+        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
+            mIsRealTimeRecording = (isNotRealTime == 0);
+        }
+    }
+
     initTrackingProgressStatus(params);
 
     sp<MetaData> meta = new MetaData;
@@ -1322,10 +1360,16 @@
     int32_t nZeroLengthFrames = 0;
     int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
     int64_t lastDurationUs = 0;   // Between the previous two samples in ms
+    int64_t currDurationTicks = 0;  // Timescale based ticks
+    int64_t lastDurationTicks = 0;  // Timescale based ticks
     int32_t sampleCount = 1;      // Sample count in the current stts table entry
     uint32_t previousSampleSize = 0;  // Size of the previous sample
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs;
+
+    int64_t wallClockTimeUs = 0;
+    int64_t lastWallClockTimeUs = 0;
+
     sp<MetaData> meta_data;
     bool collectStats = collectStatisticalData();
 
@@ -1429,6 +1473,33 @@
         }
 
         timestampUs -= previousPausedDurationUs;
+        if (mIsRealTimeRecording && !mIsAudio) {
+            // The minor adjustment on the timestamp is heuristic/experimental
+            // We are adjusting the timestamp to reduce the fluctuation of the duration
+            // of neighboring samples. This in turn helps reduce the track header size,
+            // especially, the number of entries in the "stts" box.
+            if (mNumSamples > 1) {
+                int64_t durationUs = timestampUs + mOwner->getDriftTimeUs() - lastTimestampUs;
+                int64_t diffUs = (durationUs > lastDurationUs)
+                            ? durationUs - lastDurationUs
+                            : lastDurationUs - durationUs;
+                if (diffUs <= 5000) {  // XXX: Magic number 5ms
+                    timestampUs = lastTimestampUs + lastDurationUs;
+                } else {
+                    timestampUs += mOwner->getDriftTimeUs();
+                }
+            }
+        }
+        CHECK(timestampUs >= 0);
+        if (mNumSamples > 1) {
+            if (timestampUs <= lastTimestampUs) {
+                LOGW("Drop a frame, since it arrives too late!");
+                copy->release();
+                copy = NULL;
+                continue;
+            }
+        }
+
         LOGV("time stamp: %lld and previous paused duration %lld",
                 timestampUs, previousPausedDurationUs);
         if (timestampUs > mTrackDurationUs) {
@@ -1438,7 +1509,16 @@
         mSampleSizes.push_back(sampleSize);
         ++mNumSamples;
         if (mNumSamples > 2) {
-            if (lastDurationUs != timestampUs - lastTimestampUs) {
+            // We need to use the time scale based ticks, rather than the
+            // timestamp itself to determine whether we have to use a new
+            // stts entry, since we may have rounding errors.
+            // The calculation is intended to reduce the accumulated
+            // rounding errors.
+            currDurationTicks =
+                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
+                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+
+            if (currDurationTicks != lastDurationTicks) {
                 SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
                 mSttsTableEntries.push_back(sttsEntry);
                 sampleCount = 1;
@@ -1453,7 +1533,16 @@
             previousSampleSize = sampleSize;
         }
         lastDurationUs = timestampUs - lastTimestampUs;
+        lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
+        if (mIsRealTimeRecording && mIsAudio) {
+            wallClockTimeUs = systemTime() / 1000;
+            int64_t wallClockDurationUs = wallClockTimeUs - lastWallClockTimeUs;
+            if (mNumSamples > 2) {
+                mOwner->addDriftTimeUs(lastDurationUs - wallClockDurationUs);
+            }
+            lastWallClockTimeUs = wallClockTimeUs;
+        }
 
         if (isSync != 0) {
             mStssTableEntries.push_back(mNumSamples);
@@ -1679,6 +1768,18 @@
     }
 }
 
+void MPEG4Writer::addDriftTimeUs(int64_t driftTimeUs) {
+    LOGV("addDriftTimeUs: %lld us", driftTimeUs);
+    Mutex::Autolock autolock(mLock);
+    mDriftTimeUs += driftTimeUs;
+}
+
+int64_t MPEG4Writer::getDriftTimeUs() {
+    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
+    Mutex::Autolock autolock(mLock);
+    return mDriftTimeUs;
+}
+
 void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
     LOGV("bufferChunk");
 
@@ -1709,7 +1810,6 @@
     LOGV("%s track time scale: %d",
         mIsAudio? "Audio": "Video", mTimeScale);
 
-
     time_t now = time(NULL);
     int32_t mvhdTimeScale = mOwner->getTimeScale();
     int64_t trakDurationUs = getDurationUs();
@@ -1956,11 +2056,11 @@
                   mOwner->writeInt16(0x18);        // depth
                   mOwner->writeInt16(-1);          // predefined
 
-                  CHECK(mCodecSpecificData);
-                  CHECK(mCodecSpecificDataSize > 0);
                   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
@@ -2024,10 +2124,18 @@
           mOwner->beginBox("stts");
             mOwner->writeInt32(0);  // version=0, flags=0
             mOwner->writeInt32(mSttsTableEntries.size());
+            int64_t prevTimestampUs = 0;
             for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
                  it != mSttsTableEntries.end(); ++it) {
                 mOwner->writeInt32(it->sampleCount);
-                int32_t dur = (it->sampleDurationUs * mTimeScale + 5E5) / 1E6;
+
+                // Make sure that we are calculating the sample duration the exactly
+                // same way as we made decision on how to create stts entries.
+                int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
+                int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
+                               (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
+                prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
+
                 mOwner->writeInt32(dur);
             }
           mOwner->endBox();  // stts
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index b699d8f..9630092 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -158,7 +158,7 @@
     ReadOptions::SeekMode mode;
     if (options && options->getSeekTo(&seekTimeUs, &mode)) {
         off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
-        LOGI("seeking to offset %ld", pos);
+        LOGV("seeking to offset %ld", pos);
 
         if (mExtractor->mImpl->seekToOffset(pos) != OK) {
             return ERROR_END_OF_STREAM;
@@ -267,7 +267,7 @@
     uint8_t header[27];
     if (mSource->readAt(offset, header, sizeof(header))
             < (ssize_t)sizeof(header)) {
-        LOGE("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
+        LOGV("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
 
         return ERROR_IO;
     }
@@ -384,7 +384,7 @@
                     packetSize);
 
             if (n < (ssize_t)packetSize) {
-                LOGE("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
+                LOGV("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
                 return ERROR_IO;
             }
 
@@ -418,7 +418,7 @@
                 buffer = NULL;
             }
 
-            LOGE("readPage returned %ld", n);
+            LOGV("readPage returned %ld", n);
 
             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
         }
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index 6e74279..389180c 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -98,6 +98,7 @@
     : mSource(source),
       mMeta(meta),
       mNumInputFrames(-1),
+      mPrevTimestampUs(-1),
       mStarted(false),
       mInputBuffer(NULL),
       mInputFrameData(NULL),
@@ -391,8 +392,6 @@
         if (err != OK) {
             LOGE("Failed to read input video frame: %d", err);
             outputBuffer->release();
-            mInputBuffer->release();
-            mInputBuffer = NULL;
             return err;
         }
 
@@ -407,6 +406,22 @@
         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 1bef0e9..a011137 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -69,6 +69,7 @@
       mMeta(meta),
       mNumInputFrames(-1),
       mNextModTimeUs(0),
+      mPrevTimestampUs(-1),
       mStarted(false),
       mInputBuffer(NULL),
       mInputFrameData(NULL),
@@ -292,8 +293,6 @@
     if (OK != mSource->read(&mInputBuffer, options)) {
         LOGE("Failed to read from data source");
         outputBuffer->release();
-        mInputBuffer->release();
-        mInputBuffer = NULL;
         return UNKNOWN_ERROR;
     }
 
@@ -306,8 +305,13 @@
 
     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();
@@ -315,6 +319,10 @@
         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 @@
     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 @@
     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 @@
         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 395cd28..224b4bf 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -376,7 +376,7 @@
 void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
     int32_t damaged;
     if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
-        LOG(INFO) << "discarding damaged AU";
+        LOG(VERBOSE) << "discarding damaged AU";
         return;
     }
 
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 @@
 #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);
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 9bfd00f..27dc796 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -325,9 +325,12 @@
         else
             break;
     }
-    putUInt8(count);
+    putUInt8(count > 0 ? count + 1 : 0);
     for (int i = 0; i < count; i++)
         putUInt16(string[i]);
+    // only terminate with zero if string is not empty
+    if (count > 0)
+        putUInt16(0);
 }
 
 #ifdef MTP_DEVICE 
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index b458286..1467aab 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -83,7 +83,7 @@
     void                putString(const MtpStringBuffer& string);
     void                putString(const char* string);
     void                putString(const uint16_t* string);
-    inline void         putEmptyString() { putUInt16(0); }
+    inline void         putEmptyString() { putUInt8(0); }
     inline void         putEmptyArray() { putUInt32(0); }
 
 
diff --git a/media/mtp/MtpStringBuffer.cpp b/media/mtp/MtpStringBuffer.cpp
index 2d3cf69..8bf6731 100644
--- a/media/mtp/MtpStringBuffer.cpp
+++ b/media/mtp/MtpStringBuffer.cpp
@@ -112,7 +112,7 @@
 void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const {
     int count = mCharCount;
     const uint8_t* src = mBuffer;
-    packet->putUInt8(count);
+    packet->putUInt8(count > 0 ? count + 1 : 0);
 
     // expand utf8 to 16 bit chars
     for (int i = 0; i < count; i++) {
@@ -133,6 +133,9 @@
         }
         packet->putUInt16(ch);
     }
+    // only terminate with zero if string is not empty
+    if (count > 0)
+        packet->putUInt16(0);
 }
 
 }  // namespace android
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1c7faa4..6e7633e 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1675,6 +1675,9 @@
     float masterVolume = mMasterVolume;
     bool  masterMute = mMasterMute;
 
+    if (masterMute) {
+        masterVolume = 0;
+    }
 #ifdef LVMX
     bool tracksConnectedChanged = false;
     bool stateChanged = false;
@@ -1696,10 +1699,7 @@
     // Delegate master volume control to effect in output mix effect chain if needed
     sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX);
     if (chain != 0) {
-        uint32_t v = 0;
-        if (!masterMute) {
-            v = (uint32_t)(masterVolume * (1 << 24));
-        }
+        uint32_t v = (uint32_t)(masterVolume * (1 << 24));
         chain->setVolume_l(&v, &v);
         masterVolume = (float)((v + (1 << 23)) >> 24);
         chain.clear();