diff options
author | Andreas Huber <andih@google.com> | 2009-08-14 14:37:10 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2009-08-17 10:24:50 -0700 |
commit | 693d271e62a3726689ff68f4505ba49228eb94b2 (patch) | |
tree | dcc952183cfd766d385c25665571be967926cf89 /cmds/stagefright | |
parent | 59ecb64c9629ab02329f8240c85b820ee0c98a2e (diff) | |
download | frameworks_av-693d271e62a3726689ff68f4505ba49228eb94b2.zip frameworks_av-693d271e62a3726689ff68f4505ba49228eb94b2.tar.gz frameworks_av-693d271e62a3726689ff68f4505ba49228eb94b2.tar.bz2 |
Squashed commit of the following:
commit 5bb012f0065f7ffaaeb4f569d71f0e3a8d6b19c3
Author: Andreas Huber <andih@google.com>
Date: Fri Aug 14 10:40:08 2009 -0700
An attempt at fixing export using the qcom encoders. More quirks.
commit 0690e76bfa48118a68287ccf1bbfa82febaa620c
Author: Andreas Huber <andih@google.com>
Date: Fri Aug 14 09:08:28 2009 -0700
Callbacks are now dispatched from a separate thread in OMX.
commit c6571a039526df29b6343f9a1971dbc019088c61
Author: Andreas Huber <andih@google.com>
Date: Thu Aug 13 15:42:25 2009 -0700
Massive API changes throughout stagefright, smart pointers everywhere.
commit 900612af6a0555664d9ba195112cd859491265f4
Author: Andreas Huber <andih@google.com>
Date: Thu Aug 13 13:33:12 2009 -0700
OMXCodecs now properly shutdown.
commit 96732f05e1b0603dcd1b11f16a23512592eeb4f5
Author: Andreas Huber <andih@google.com>
Date: Thu Aug 13 12:04:04 2009 -0700
More work on JPEG decoding using the hardware OMX component.
commit 63839a073ac393e3a130434ba467969053b694ad
Author: Andreas Huber <andih@google.com>
Date: Wed Aug 12 13:13:31 2009 -0700
An attempt to drive the JPEG decoder OMX node.
commit 3ac2fe5ab2926eda81b2123610b2434c645294ff
Author: Andreas Huber <andih@google.com>
Date: Tue Aug 11 16:38:21 2009 -0700
Renamed StateMachine to OMXCodec and put it in its proper place.
commit 247da75a96bf8881956413023dd49a84d5b4f5b2
Author: Andreas Huber <andih@google.com>
Date: Tue Aug 11 16:06:19 2009 -0700
Statemachine is now a full-fledged MediaSource.
commit 045244f6771fa0b9b329495c953afda900a84b71
Author: Andreas Huber <andih@google.com>
Date: Fri Aug 7 09:16:54 2009 -0700
Properly setup the input format when exporting to AMR audio.
commit 271b984cb32c5cd9e46e3f90ae121f334e4b8da9
Author: Andreas Huber <andih@google.com>
Date: Thu Aug 6 09:59:38 2009 -0700
Added some code to test audio encoding to the OMX harness.
commit 79af4748e4af33bd66d3fbac606e332a69741cf4
Author: Andreas Huber <andih@google.com>
Date: Wed Aug 5 14:36:22 2009 -0700
Merge the old OMXDecoder and the new, shiny, StateMachine code.
commit 91cf5dd77a8762bc10a0b2ffce35e3bbeb262231
Author: Andreas Huber <andih@google.com>
Date: Tue Aug 4 17:41:43 2009 -0700
A new harness to test OMX node compliance (and quirks).
Diffstat (limited to 'cmds/stagefright')
-rw-r--r-- | cmds/stagefright/Android.mk | 9 | ||||
-rw-r--r-- | cmds/stagefright/record.cpp | 135 | ||||
-rw-r--r-- | cmds/stagefright/stagefright.cpp | 372 |
3 files changed, 375 insertions, 141 deletions
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index e6d0503..4576b8e 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -10,8 +10,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/base/media/libstagefright \ - $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \ - $(TOP)/external/opencore/android + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include LOCAL_CFLAGS += -Wno-multichar @@ -31,8 +30,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES:= \ frameworks/base/media/libstagefright \ - $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \ - $(TOP)/external/opencore/android + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include LOCAL_CFLAGS += -Wno-multichar @@ -52,8 +50,7 @@ include $(BUILD_EXECUTABLE) # # LOCAL_C_INCLUDES:= \ # frameworks/base/media/libstagefright \ -# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \ -# $(TOP)/external/opencore/android +# $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include # # LOCAL_CFLAGS += -Wno-multichar # diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index cd54958..cf2962b 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -25,6 +25,7 @@ #include <media/stagefright/MPEG4Writer.h> #include <media/stagefright/MmapSource.h> #include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> #include <media/stagefright/OMXDecoder.h> using namespace android; @@ -32,18 +33,38 @@ using namespace android; class DummySource : public MediaSource { public: DummySource(int width, int height) - : mSize((width * height * 3) / 2) { + : mWidth(width), + mHeight(height), + mSize((width * height * 3) / 2) { mGroup.add_buffer(new MediaBuffer(mSize)); } - virtual ::status_t getMaxSampleSize(size_t *max_size) { + virtual sp<MetaData> getFormat() { + sp<MetaData> meta = new MetaData; + meta->setInt32(kKeyWidth, mWidth); + meta->setInt32(kKeyHeight, mHeight); + meta->setCString(kKeyMIMEType, "video/raw"); + + return meta; + } + + virtual status_t getMaxSampleSize(size_t *max_size) { *max_size = mSize; - return ::OK; + return OK; + } + + virtual status_t start(MetaData *params) { + return OK; + } + + virtual status_t stop() { + return OK; } - virtual ::status_t read(MediaBuffer **buffer) { - ::status_t err = mGroup.acquire_buffer(buffer); - if (err != ::OK) { + virtual status_t read( + MediaBuffer **buffer, const MediaSource::ReadOptions *options) { + status_t err = mGroup.acquire_buffer(buffer); + if (err != OK) { return err; } @@ -51,34 +72,34 @@ public: memset((*buffer)->data(), x, mSize); (*buffer)->set_range(0, mSize); - return ::OK; + return OK; } +protected: + virtual ~DummySource() {} + private: MediaBufferGroup mGroup; + int mWidth, mHeight; size_t mSize; DummySource(const DummySource &); DummySource &operator=(const DummySource &); }; -int main(int argc, char **argv) { - android::ProcessState::self()->startThreadPool(); +#define USE_OMX_CODEC 1 -#if 1 - if (argc != 2) { - fprintf(stderr, "usage: %s filename\n", argv[0]); - return 1; - } +sp<MediaSource> createSource(const char *filename) { + sp<MediaSource> source; - MPEG4Extractor extractor(new MmapSource(argv[1])); - int num_tracks; - assert(extractor.countTracks(&num_tracks) == ::OK); + sp<MPEG4Extractor> extractor = + new MPEG4Extractor(new MmapSource(filename)); + + size_t num_tracks = extractor->countTracks(); - MediaSource *source = NULL; sp<MetaData> meta; - for (int i = 0; i < num_tracks; ++i) { - meta = extractor.getTrackMetaData(i); + for (size_t i = 0; i < num_tracks; ++i) { + meta = extractor->getTrackMetaData(i); assert(meta.get() != NULL); const char *mime; @@ -90,48 +111,75 @@ int main(int argc, char **argv) { continue; } - if (extractor.getTrack(i, &source) != ::OK) { - source = NULL; - continue; - } + source = extractor->getTrack(i); break; } - if (source == NULL) { - fprintf(stderr, "Unable to find a suitable video track.\n"); + return source; +} + +int main(int argc, char **argv) { + android::ProcessState::self()->startThreadPool(); + +#if 1 + if (argc != 2) { + fprintf(stderr, "usage: %s filename\n", argv[0]); return 1; } OMXClient client; assert(client.connect() == android::OK); - OMXDecoder *decoder = OMXDecoder::Create(&client, meta); - decoder->setSource(source); +#if 0 + sp<MediaSource> source = createSource(argv[1]); + + if (source == NULL) { + fprintf(stderr, "Unable to find a suitable video track.\n"); + return 1; + } + + sp<MetaData> meta = source->getFormat(); + +#if USE_OMX_CODEC + sp<OMXCodec> decoder = OMXCodec::Create( + client.interface(), meta, false /* createEncoder */, source); +#else + sp<OMXDecoder> decoder = OMXDecoder::Create( + &client, meta, false /* createEncoder */, source); +#endif int width, height; bool success = meta->findInt32(kKeyWidth, &width); success = success && meta->findInt32(kKeyHeight, &height); assert(success); +#else + int width = 320; + int height = 240; + sp<MediaSource> decoder = new DummySource(width, height); +#endif sp<MetaData> enc_meta = new MetaData; - enc_meta->setCString(kKeyMIMEType, "video/3gpp"); - // enc_meta->setCString(kKeyMIMEType, "video/mp4v-es"); + // enc_meta->setCString(kKeyMIMEType, "video/3gpp"); + enc_meta->setCString(kKeyMIMEType, "video/mp4v-es"); enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyHeight, height); - OMXDecoder *encoder = - OMXDecoder::Create(&client, enc_meta, true /* createEncoder */); - - encoder->setSource(decoder); - // encoder->setSource(meta, new DummySource(width, height)); +#if USE_OMX_CODEC + sp<OMXCodec> encoder = + OMXCodec::Create( + client.interface(), enc_meta, true /* createEncoder */, decoder); +#else + sp<OMXDecoder> encoder = OMXDecoder::Create( + &client, enc_meta, true /* createEncoder */, decoder); +#endif #if 1 - MPEG4Writer writer("/sdcard/output.mp4"); - writer.addSource(enc_meta, encoder); - writer.start(); + sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4"); + writer->addSource(enc_meta, encoder); + writer->start(); sleep(20); printf("stopping now.\n"); - writer.stop(); + writer->stop(); #else encoder->start(); @@ -146,16 +194,7 @@ int main(int argc, char **argv) { encoder->stop(); #endif - delete encoder; - encoder = NULL; - - delete decoder; - decoder = NULL; - client.disconnect(); - - delete source; - source = NULL; #endif #if 0 diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index 7e23574..b2de67a 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -16,9 +16,6 @@ #include <sys/time.h> -#undef NDEBUG -#include <assert.h> - #include <pthread.h> #include <stdlib.h> @@ -30,12 +27,15 @@ #include <media/stagefright/ESDS.h> #include <media/stagefright/FileSource.h> #include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaPlayerImpl.h> #include <media/stagefright/MediaExtractor.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/MmapSource.h> #include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> #include <media/stagefright/OMXDecoder.h> #include "WaveWriter.h" @@ -44,50 +44,236 @@ using namespace android; //////////////////////////////////////////////////////////////////////////////// -static bool convertToWav( - OMXClient *client, const sp<MetaData> &meta, MediaSource *source) { - printf("convertToWav\n"); +struct JPEGSource : public MediaSource { + // Assumes ownership of "source". + JPEGSource(const sp<DataSource> &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 = NULL); + +protected: + virtual ~JPEGSource(); + +private: + sp<DataSource> mSource; + MediaBufferGroup *mGroup; + bool mStarted; + off_t mSize; + int32_t mWidth, mHeight; + off_t mOffset; + + status_t parseJPEG(); + + JPEGSource(const JPEGSource &); + JPEGSource &operator=(const JPEGSource &); +}; + +JPEGSource::JPEGSource(const sp<DataSource> &source) + : mSource(source), + mGroup(NULL), + mStarted(false), + mSize(0), + mWidth(0), + mHeight(0), + mOffset(0) { + CHECK_EQ(parseJPEG(), OK); +} + +JPEGSource::~JPEGSource() { + if (mStarted) { + stop(); + } +} + +status_t JPEGSource::start(MetaData *) { + if (mStarted) { + return UNKNOWN_ERROR; + } - OMXDecoder *decoder = OMXDecoder::Create(client, meta); + if (mSource->getSize(&mSize) != OK) { + return UNKNOWN_ERROR; + } - int32_t sampleRate; - bool success = meta->findInt32(kKeySampleRate, &sampleRate); - assert(success); + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(mSize)); - int32_t numChannels; - success = meta->findInt32(kKeyChannelCount, &numChannels); - assert(success); + mOffset = 0; - const char *mime; - success = meta->findCString(kKeyMIMEType, &mime); - assert(success); + mStarted = true; + + return OK; +} - if (!strcasecmp("audio/3gpp", mime)) { - numChannels = 1; // XXX +status_t JPEGSource::stop() { + if (!mStarted) { + return UNKNOWN_ERROR; } - WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate); + delete mGroup; + mGroup = NULL; - decoder->setSource(source); - for (int i = 0; i < 100; ++i) { - MediaBuffer *buffer; + mStarted = false; - ::status_t err = decoder->read(&buffer); - if (err != ::OK) { - break; - } + return OK; +} + +sp<MetaData> JPEGSource::getFormat() { + sp<MetaData> meta = new MetaData; + meta->setCString(kKeyMIMEType, "image/jpeg"); + meta->setInt32(kKeyWidth, mWidth); + meta->setInt32(kKeyHeight, mHeight); + + return meta; +} + +status_t JPEGSource::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; - writer.Append((const char *)buffer->data() + buffer->range_offset(), - buffer->range_length()); + int64_t seekTimeUs; + if (options != NULL && options->getSeekTo(&seekTimeUs)) { + return UNKNOWN_ERROR; + } + + MediaBuffer *buffer; + mGroup->acquire_buffer(&buffer); + + ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset); + if (n <= 0) { buffer->release(); buffer = NULL; + + return UNKNOWN_ERROR; + } + + buffer->set_range(0, n); + + mOffset += n; + + *out = buffer; + + return OK; +} + +#define JPEG_SOF0 0xC0 /* nStart Of Frame N*/ +#define JPEG_SOF1 0xC1 /* N indicates which compression process*/ +#define JPEG_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use*/ +#define JPEG_SOF3 0xC3 +#define JPEG_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers*/ +#define JPEG_SOF6 0xC6 +#define JPEG_SOF7 0xC7 +#define JPEG_SOF9 0xC9 +#define JPEG_SOF10 0xCA +#define JPEG_SOF11 0xCB +#define JPEG_SOF13 0xCD +#define JPEG_SOF14 0xCE +#define JPEG_SOF15 0xCF +#define JPEG_SOI 0xD8 /* nStart Of Image (beginning of datastream)*/ +#define JPEG_EOI 0xD9 /* End Of Image (end of datastream)*/ +#define JPEG_SOS 0xDA /* nStart Of Scan (begins compressed data)*/ +#define JPEG_JFIF 0xE0 /* Jfif marker*/ +#define JPEG_EXIF 0xE1 /* Exif marker*/ +#define JPEG_COM 0xFE /* COMment */ +#define JPEG_DQT 0xDB +#define JPEG_DHT 0xC4 +#define JPEG_DRI 0xDD + +status_t JPEGSource::parseJPEG() { + mWidth = 0; + mHeight = 0; + + off_t i = 0; + + uint16_t soi; + if (!mSource->getUInt16(i, &soi)) { + return ERROR_IO; } - delete decoder; - decoder = NULL; + i += 2; + + if (soi != 0xffd8) { + return UNKNOWN_ERROR; + } + + for (;;) { + uint8_t marker; + if (mSource->read_at(i++, &marker, 1) != 1) { + return ERROR_IO; + } + + CHECK_EQ(marker, 0xff); + + if (mSource->read_at(i++, &marker, 1) != 1) { + return ERROR_IO; + } + + CHECK(marker != 0xff); + + uint16_t chunkSize; + if (!mSource->getUInt16(i, &chunkSize)) { + return ERROR_IO; + } + + i += 2; + + if (chunkSize < 2) { + return UNKNOWN_ERROR; + } + + switch (marker) { + case JPEG_SOS: + { + return (mWidth > 0 && mHeight > 0) ? OK : UNKNOWN_ERROR; + } + + case JPEG_EOI: + { + return UNKNOWN_ERROR; + } + + case JPEG_SOF0: + case JPEG_SOF1: + case JPEG_SOF3: + case JPEG_SOF5: + case JPEG_SOF6: + case JPEG_SOF7: + case JPEG_SOF9: + case JPEG_SOF10: + case JPEG_SOF11: + case JPEG_SOF13: + case JPEG_SOF14: + case JPEG_SOF15: + { + uint16_t width, height; + if (!mSource->getUInt16(i + 1, &height) + || !mSource->getUInt16(i + 3, &width)) { + return ERROR_IO; + } + + mWidth = width; + mHeight = height; + + i += chunkSize - 2; + break; + } + + default: + { + // Skip chunk + + i += chunkSize - 2; + + break; + } + } + } - return true; + return OK; } //////////////////////////////////////////////////////////////////////////////// @@ -99,6 +285,48 @@ static int64_t getNowUs() { return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; } +#define USE_OMX_CODEC 1 + +static void playSource(OMXClient *client, const sp<MediaSource> &source) { + sp<MetaData> meta = source->getFormat(); + +#if !USE_OMX_CODEC + sp<OMXDecoder> decoder = OMXDecoder::Create( + client, meta, false /* createEncoder */, source); +#else + sp<OMXCodec> decoder = OMXCodec::Create( + client->interface(), meta, false /* createEncoder */, source); +#endif + + if (decoder == NULL) { + return; + } + + decoder->start(); + + int64_t startTime = getNowUs(); + + int n = 0; + MediaBuffer *buffer; + status_t err; + while ((err = decoder->read(&buffer)) == OK) { + if ((++n % 16) == 0) { + printf("."); + fflush(stdout); + } + + buffer->release(); + buffer = NULL; + } + decoder->stop(); + printf("\n"); + + int64_t delay = getNowUs() - startTime; + printf("avg. %.2f fps\n", n * 1E6 / delay); + + printf("decoded a total of %d frame(s).\n", n); +} + int main(int argc, char **argv) { android::ProcessState::self()->startThreadPool(); @@ -108,10 +336,10 @@ int main(int argc, char **argv) { sp<IBinder> binder = sm->getService(String16("media.player")); sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); - assert(service.get() != NULL); + CHECK(service.get() != NULL); sp<IOMX> omx = service->createOMX(); - assert(omx.get() != NULL); + CHECK(omx.get() != NULL); List<String8> list; omx->list_nodes(&list); @@ -128,82 +356,52 @@ int main(int argc, char **argv) { --argc; } -#if 0 - MediaPlayerImpl player(argv[1]); - player.play(); - - sleep(10000); -#else DataSource::RegisterDefaultSniffers(); OMXClient client; status_t err = client.connect(); - MmapSource *dataSource = new MmapSource(argv[1]); - MediaExtractor *extractor = MediaExtractor::Create(dataSource); - dataSource = NULL; - - int numTracks; - err = extractor->countTracks(&numTracks); - - sp<MetaData> meta; - int i; - for (i = 0; i < numTracks; ++i) { - meta = extractor->getTrackMetaData(i); + sp<MmapSource> dataSource = new MmapSource(argv[1]); - const char *mime; - meta->findCString(kKeyMIMEType, &mime); - - if (audioOnly && !strncasecmp(mime, "audio/", 6)) { - break; - } + bool isJPEG = false; - if (!audioOnly && !strncasecmp(mime, "video/", 6)) { - break; - } + size_t len = strlen(argv[1]); + if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) { + isJPEG = true; } - OMXDecoder *decoder = OMXDecoder::Create(&client, meta); + sp<MediaSource> mediaSource; - if (decoder != NULL) { - MediaSource *source; - err = extractor->getTrack(i, &source); + if (isJPEG) { + mediaSource = new JPEGSource(dataSource); + } else { + sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); - decoder->setSource(source); + size_t numTracks = extractor->countTracks(); - decoder->start(); + sp<MetaData> meta; + size_t i; + for (i = 0; i < numTracks; ++i) { + meta = extractor->getTrackMetaData(i); - int64_t startTime = getNowUs(); + const char *mime; + meta->findCString(kKeyMIMEType, &mime); - int n = 0; - MediaBuffer *buffer; - while ((err = decoder->read(&buffer)) == OK) { - if ((++n % 16) == 0) { - printf("."); - fflush(stdout); + if (audioOnly && !strncasecmp(mime, "audio/", 6)) { + break; } - buffer->release(); - buffer = NULL; + if (!audioOnly && !strncasecmp(mime, "video/", 6)) { + break; + } } - decoder->stop(); - printf("\n"); - - int64_t delay = getNowUs() - startTime; - printf("avg. %.2f fps\n", n * 1E6 / delay); - delete decoder; - decoder = NULL; - - delete source; - source = NULL; + mediaSource = extractor->getTrack(i); } - delete extractor; - extractor = NULL; + playSource(&client, mediaSource); client.disconnect(); -#endif return 0; } |