OSDN Git Service

Proper sync-frame detection for sources that don't already provide it.
authorAndreas Huber <andih@google.com>
Thu, 23 Sep 2010 22:01:30 +0000 (15:01 -0700)
committerAndreas Huber <andih@google.com>
Thu, 23 Sep 2010 22:03:57 +0000 (15:03 -0700)
Change-Id: Iafeee847b015c5cf6bec6dd5fac22a8d3e8cb78e

cmds/stagefright/stagefright.cpp

index 8ab94ad..eb4b733 100644 (file)
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "stagefright"
+#include <media/stagefright/foundation/ADebug.h>
+
 #include <sys/time.h>
 
 #include <stdlib.h>
@@ -30,7 +34,6 @@
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/JPEGSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -43,6 +46,8 @@
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/MPEG4Writer.h>
 
+#include <fcntl.h>
+
 using namespace android;
 
 static long gNumRepetitions;
@@ -120,7 +125,7 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
 
             bool shouldSeek = false;
             if (err == INFO_FORMAT_CHANGED) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
 
                 printf("format changed.\n");
                 continue;
@@ -206,7 +211,7 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
             options.clearSeekTo();
 
             if (err != OK) {
-                CHECK_EQ(buffer, NULL);
+                CHECK(buffer == NULL);
 
                 if (err == INFO_FORMAT_CHANGED) {
                     printf("format changed.\n");
@@ -267,14 +272,98 @@ static void playSource(OMXClient *client, sp<MediaSource> &source) {
     }
 }
 
-static void writeSourceToMP4(const sp<MediaSource> &source) {
+////////////////////////////////////////////////////////////////////////////////
+
+struct DetectSyncSource : public MediaSource {
+    DetectSyncSource(const sp<MediaSource> &source);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+private:
+    sp<MediaSource> mSource;
+    bool mIsAVC;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
+};
+
+DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
+    : mSource(source),
+      mIsAVC(false) {
+    const char *mime;
+    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
+}
+
+status_t DetectSyncSource::start(MetaData *params) {
+    return mSource->start(params);
+}
+
+status_t DetectSyncSource::stop() {
+    return mSource->stop();
+}
+
+sp<MetaData> DetectSyncSource::getFormat() {
+    return mSource->getFormat();
+}
+
+static bool isIDRFrame(MediaBuffer *buffer) {
+    const uint8_t *data =
+        (const uint8_t *)buffer->data() + buffer->range_offset();
+    size_t size = buffer->range_length();
+    for (size_t i = 0; i + 3 < size; ++i) {
+        if (!memcmp("\x00\x00\x01", &data[i], 3)) {
+            uint8_t nalType = data[i + 3] & 0x1f;
+            if (nalType == 5) {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+status_t DetectSyncSource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    status_t err = mSource->read(buffer, options);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (mIsAVC && isIDRFrame(*buffer)) {
+        (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true);
+    } else {
+        (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, false);
+    }
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void writeSourceToMP4(
+        sp<MediaSource> &source, bool syncInfoPresent) {
+    if (!syncInfoPresent) {
+        source = new DetectSyncSource(source);
+    }
+
     sp<MPEG4Writer> writer =
         new MPEG4Writer(gWriteMP4Filename.string());
 
-    CHECK_EQ(writer->addSource(source), OK);
+    // at most one minute.
+    writer->setMaxFileDuration(60000000ll);
+
+    CHECK_EQ(writer->addSource(source), (status_t)OK);
 
     sp<MetaData> params = new MetaData;
-    CHECK_EQ(writer->start(), OK);
+    params->setInt32(kKeyNotRealTime, true);
+    CHECK_EQ(writer->start(params.get()), (status_t)OK);
 
     while (!writer->reachedEOS()) {
         usleep(100000);
@@ -283,7 +372,7 @@ static void writeSourceToMP4(const sp<MediaSource> &source) {
 }
 
 static void performSeekTest(const sp<MediaSource> &source) {
-    CHECK_EQ(OK, source->start());
+    CHECK_EQ((status_t)OK, source->start());
 
     int64_t durationUs;
     CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -335,7 +424,7 @@ static void performSeekTest(const sp<MediaSource> &source) {
         }
     }
 
-    CHECK_EQ(OK, source->stop());
+    CHECK_EQ((status_t)OK, source->stop());
 }
 
 static void usage(const char *me) {
@@ -481,10 +570,10 @@ int main(int argc, char **argv) {
         for (int k = 0; k < argc; ++k) {
             const char *filename = argv[k];
 
-            CHECK_EQ(retriever->setDataSource(filename), OK);
+            CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
             CHECK_EQ(retriever->setMode(
                         METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL),
-                     OK);
+                     (status_t)OK);
 
             sp<IMemory> mem = retriever->captureFrame();
 
@@ -530,7 +619,7 @@ int main(int argc, char **argv) {
             Vector<CodecCapabilities> results;
             CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
                                  true, // queryDecoders
-                                 &results), OK);
+                                 &results), (status_t)OK);
 
             for (size_t i = 0; i < results.size(); ++i) {
                 printf("  decoder '%s' supports ",
@@ -579,6 +668,8 @@ int main(int argc, char **argv) {
     status_t err = client.connect();
 
     for (int k = 0; k < argc; ++k) {
+        bool syncInfoPresent = true;
+
         const char *filename = argv[k];
 
         sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
@@ -625,6 +716,8 @@ int main(int argc, char **argv) {
                 }
 
                 extractor = rtspController.get();
+
+                syncInfoPresent = false;
             } else {
                 extractor = MediaExtractor::Create(dataSource);
                 if (extractor == NULL) {
@@ -674,7 +767,7 @@ int main(int argc, char **argv) {
         }
 
         if (gWriteMP4) {
-            writeSourceToMP4(mediaSource);
+            writeSourceToMP4(mediaSource, syncInfoPresent);
         } else if (seekTest) {
             performSeekTest(mediaSource);
         } else {