Merge "Revert "stop using a deprecated SurfaceTextureClient ctor""
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index e02f111..c30c122 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -44,7 +44,7 @@
     fprintf(stderr, "       -p encoder profile. see omx il header (default: encoder specific)\n");
     fprintf(stderr, "       -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n");
     fprintf(stderr, "       -s(oftware) prefer software codec\n");
-    fprintf(stderr, "The output file is /sdcard/output.mp4\n");
+    fprintf(stderr, "       -o filename: output file (default: /sdcard/output.mp4)\n");
     exit(1);
 }
 
@@ -162,12 +162,12 @@
     int level = -1;        // Encoder specific default
     int profile = -1;      // Encoder specific default
     int codec = 0;
-    const char *fileName = "/sdcard/output.mp4";
+    char *fileName = "/sdcard/output.mp4";
     bool preferSoftwareCodec = false;
 
     android::ProcessState::self()->startThreadPool();
     int res;
-    while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:hs")) >= 0) {
+    while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:o:hs")) >= 0) {
         switch (res) {
             case 'b':
             {
@@ -235,6 +235,12 @@
                 break;
             }
 
+            case 'o':
+            {
+                fileName = optarg;
+                break;
+            }
+
             case 's':
             {
                 preferSoftwareCodec = true;
diff --git a/media/libstagefright/mp4/FragmentedMP4Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
index 54c3d63..7aa5be9 100644
--- a/media/libstagefright/mp4/FragmentedMP4Parser.cpp
+++ b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
@@ -319,8 +319,7 @@
         off_t totalOffset = mFirstMoofOffset;
         for (int i = 0; i < numSidxEntries; i++) {
             const SidxEntry *se = &info->mSidx[i];
-            totalTime += se->mDurationUs;
-            if (totalTime > position) {
+            if (totalTime + se->mDurationUs > position) {
                 mBuffer->setRange(0,0);
                 mBufferPos = totalOffset;
                 if (mFinalResult == ERROR_END_OF_STREAM) {
@@ -329,9 +328,10 @@
                     resumeIfNecessary();
                 }
                 info->mFragments.clear();
-                info->mDecodingTime = position * info->mMediaTimeScale / 1000000ll;
+                info->mDecodingTime = totalTime * info->mMediaTimeScale / 1000000ll;
                 return OK;
             }
+            totalTime += se->mDurationUs;
             totalOffset += se->mSize;
         }
     }
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 37e39a0..aaa5333 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -103,6 +103,8 @@
 
 public:
     void triggerEvents(AudioSystem::sync_event_t type);
+    void invalidate();
+    bool isInvalid() const { return mIsInvalid; }
     virtual bool isTimedTrack() const { return false; }
     bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
     virtual bool isOut() const;
@@ -143,6 +145,7 @@
     volatile float      mCachedVolume;  // combined master volume and stream type volume;
                                         // 'volatile' means accessed without lock or
                                         // barrier, but is read/written atomically
+    bool                mIsInvalid; // non-resettable latch, set by invalidate()
 };  // end of Track
 
 class TimedTrack : public Track {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a285e6c..d2b2931 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1524,8 +1524,7 @@
 
     for (size_t i = 0; i < mTracks.size(); ++i) {
         sp<Track> track = mTracks[i];
-        if (sessionId == track->sessionId() &&
-                !(track->mCblk->flags & CBLK_INVALID)) {
+        if (sessionId == track->sessionId() && !track->isInvalid()) {
             result |= TRACK_SESSION;
             break;
         }
@@ -1543,8 +1542,7 @@
     }
     for (size_t i = 0; i < mTracks.size(); i++) {
         sp<Track> track = mTracks[i];
-        if (sessionId == track->sessionId() &&
-                !(track->mCblk->flags & CBLK_INVALID)) {
+        if (sessionId == track->sessionId() && !track->isInvalid()) {
             return AudioSystem::getStrategyForStream(track->streamType());
         }
     }
@@ -1721,8 +1719,7 @@
     for (size_t i = 0; i < size; i++) {
         sp<Track> t = mTracks[i];
         if (t->streamType() == streamType) {
-            android_atomic_or(CBLK_INVALID, &t->mCblk->flags);
-            t->mCblk->cv.signal();
+            t->invalidate();
         }
     }
 }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e8ca5ee..9b611d2 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -323,7 +323,8 @@
     mFlags(flags),
     mFastIndex(-1),
     mUnderrunCount(0),
-    mCachedVolume(1.0)
+    mCachedVolume(1.0),
+    mIsInvalid(false)
 {
     if (mCblk != NULL) {
         // to avoid leaking a track name, do not allocate one unless there is an mCblk
@@ -834,6 +835,14 @@
     return true;
 }
 
+void AudioFlinger::PlaybackThread::Track::invalidate()
+{
+    // FIXME should use proxy
+    android_atomic_or(CBLK_INVALID, &mCblk->flags);
+    mCblk->cv.signal();
+    mIsInvalid = true;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<AudioFlinger::PlaybackThread::TimedTrack>