Transcoder: Add support for pausing transcoding on a sync frame.

- Added support for stopping transcoders on a sync frame.
- Refactored MediaTrackTranscoders and MediaSampleWriter to stop()
asynchronously.
- Fixed callback and error handling logic in MediaTranscoder.
- Added tests for pause and stopping on sync frame.

Bug: 162886306
Test: Unit tests.

Change-Id: If689a10dfee198c674c4c13b865a7c56a901e075
diff --git a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
index afa5021..389b941 100644
--- a/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
+++ b/media/libmediatranscoding/transcoder/MediaSampleWriter.cpp
@@ -79,7 +79,7 @@
 
 MediaSampleWriter::~MediaSampleWriter() {
     if (mState == STARTED) {
-        stop();  // Join thread.
+        stop();
     }
 }
 
@@ -169,38 +169,41 @@
     }
 
     mState = STARTED;
-    mThread = std::thread([this] {
-        media_status_t status = writeSamples();
+    std::thread([this] {
+        bool wasStopped = false;
+        media_status_t status = writeSamples(&wasStopped);
         if (auto callbacks = mCallbacks.lock()) {
-            callbacks->onFinished(this, status);
+            if (wasStopped && status == AMEDIA_OK) {
+                callbacks->onStopped(this);
+            } else {
+                callbacks->onFinished(this, status);
+            }
         }
-    });
+    }).detach();
     return true;
 }
 
-bool MediaSampleWriter::stop() {
+void MediaSampleWriter::stop() {
     {
         std::scoped_lock lock(mMutex);
         if (mState != STARTED) {
             LOG(ERROR) << "Sample writer is not started.";
-            return false;
+            return;
         }
         mState = STOPPED;
     }
 
     mSampleSignal.notify_all();
-    mThread.join();
-    return true;
 }
 
-media_status_t MediaSampleWriter::writeSamples() {
+media_status_t MediaSampleWriter::writeSamples(bool* wasStopped) {
     media_status_t muxerStatus = mMuxer->start();
     if (muxerStatus != AMEDIA_OK) {
         LOG(ERROR) << "Error starting muxer: " << muxerStatus;
         return muxerStatus;
     }
 
-    media_status_t writeStatus = runWriterLoop();
+    media_status_t writeStatus = runWriterLoop(wasStopped);
     if (writeStatus != AMEDIA_OK) {
         LOG(ERROR) << "Error writing samples: " << writeStatus;
     }
@@ -213,7 +216,7 @@
     return writeStatus != AMEDIA_OK ? writeStatus : muxerStatus;
 }
 
-media_status_t MediaSampleWriter::runWriterLoop() NO_THREAD_SAFETY_ANALYSIS {
+media_status_t MediaSampleWriter::runWriterLoop(bool* wasStopped) NO_THREAD_SAFETY_ANALYSIS {
     AMediaCodecBufferInfo bufferInfo;
     int32_t lastProgressUpdate = 0;
     int trackEosCount = 0;
@@ -242,8 +245,9 @@
                 mSampleSignal.wait(lock);
             }
 
-            if (mState != STARTED) {
-                return AMEDIA_ERROR_UNKNOWN;  // TODO(lnilsson): Custom error code.
+            if (mState == STOPPED) {
+                *wasStopped = true;
+                return AMEDIA_OK;
             }
 
             auto& topEntry = mSampleQueue.top();