Loading cmds/stagefright/Android.mk +3 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 # Loading cmds/stagefright/record.cpp +87 −48 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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; sp<MPEG4Extractor> extractor = new MPEG4Extractor(new MmapSource(filename)); MPEG4Extractor extractor(new MmapSource(argv[1])); int num_tracks; assert(extractor.countTracks(&num_tracks) == ::OK); 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; Loading @@ -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(); Loading @@ -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 Loading cmds/stagefright/stagefright.cpp +285 −87 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ #include <sys/time.h> #undef NDEBUG #include <assert.h> #include <pthread.h> #include <stdlib.h> Loading @@ -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" Loading @@ -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(); } } OMXDecoder *decoder = OMXDecoder::Create(client, meta); status_t JPEGSource::start(MetaData *) { if (mStarted) { return UNKNOWN_ERROR; } int32_t sampleRate; bool success = meta->findInt32(kKeySampleRate, &sampleRate); assert(success); if (mSource->getSize(&mSize) != OK) { return UNKNOWN_ERROR; } int32_t numChannels; success = meta->findInt32(kKeyChannelCount, &numChannels); assert(success); mGroup = new MediaBufferGroup; mGroup->add_buffer(new MediaBuffer(mSize)); const char *mime; success = meta->findCString(kKeyMIMEType, &mime); assert(success); mOffset = 0; if (!strcasecmp("audio/3gpp", mime)) { numChannels = 1; // XXX mStarted = true; return OK; } WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate); status_t JPEGSource::stop() { if (!mStarted) { return UNKNOWN_ERROR; } decoder->setSource(source); for (int i = 0; i < 100; ++i) { MediaBuffer *buffer; delete mGroup; mGroup = NULL; ::status_t err = decoder->read(&buffer); if (err != ::OK) { break; mStarted = false; 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; } writer.Append((const char *)buffer->data() + buffer->range_offset(), buffer->range_length()); status_t JPEGSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; 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; } delete decoder; decoder = NULL; 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; } i += 2; if (soi != 0xffd8) { return UNKNOWN_ERROR; } return true; 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 OK; } //////////////////////////////////////////////////////////////////////////////// Loading @@ -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(); Loading @@ -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); Loading @@ -128,26 +356,31 @@ 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; sp<MmapSource> dataSource = new MmapSource(argv[1]); int numTracks; err = extractor->countTracks(&numTracks); bool isJPEG = false; size_t len = strlen(argv[1]); if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) { isJPEG = true; } sp<MediaSource> mediaSource; if (isJPEG) { mediaSource = new JPEGSource(dataSource); } else { sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); size_t numTracks = extractor->countTracks(); sp<MetaData> meta; int i; size_t i; for (i = 0; i < numTracks; ++i) { meta = extractor->getTrackMetaData(i); Loading @@ -163,47 +396,12 @@ int main(int argc, char **argv) { } } OMXDecoder *decoder = OMXDecoder::Create(&client, meta); if (decoder != NULL) { MediaSource *source; err = extractor->getTrack(i, &source); decoder->setSource(source); decoder->start(); int64_t startTime = getNowUs(); int n = 0; MediaBuffer *buffer; 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); delete decoder; decoder = NULL; delete source; source = NULL; mediaSource = extractor->getTrack(i); } delete extractor; extractor = NULL; playSource(&client, mediaSource); client.disconnect(); #endif return 0; } include/media/IOMX.h +15 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,14 @@ public: node_id node, OMX_INDEXTYPE index, const void *params, size_t size) = 0; virtual status_t get_config( node_id node, OMX_INDEXTYPE index, void *params, size_t size) = 0; virtual status_t set_config( node_id node, OMX_INDEXTYPE index, const void *params, size_t size) = 0; virtual status_t use_buffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, buffer_id *buffer) = 0; Loading @@ -82,6 +90,11 @@ public: OMX_U32 range_offset, OMX_U32 range_length, OMX_U32 flags, OMX_TICKS timestamp) = 0; virtual status_t get_extension_index( node_id node, const char *parameter_name, OMX_INDEXTYPE *index) = 0; virtual sp<IOMXRenderer> createRenderer( const sp<ISurface> &surface, const char *componentName, Loading Loading @@ -114,10 +127,11 @@ struct omx_message { QUIT_OBSERVER, } type; IOMX::node_id node; union { // if type == EVENT struct { IOMX::node_id node; OMX_EVENTTYPE event; OMX_U32 data1; OMX_U32 data2; Loading @@ -126,13 +140,11 @@ struct omx_message { // if type == EMPTY_BUFFER_DONE || type == FILL_BUFFER // || type == INITIAL_FILL_BUFFER struct { IOMX::node_id node; IOMX::buffer_id buffer; } buffer_data; // if type == EMPTY_BUFFER || type == FILL_BUFFER_DONE struct { IOMX::node_id node; IOMX::buffer_id buffer; OMX_U32 range_offset; OMX_U32 range_length; Loading @@ -143,7 +155,6 @@ struct omx_message { // if type == SEND_COMMAND struct { IOMX::node_id node; OMX_COMMANDTYPE cmd; OMX_S32 param; } send_command_data; Loading include/media/stagefright/AudioPlayer.h +3 −3 Original line number Diff line number Diff line Loading @@ -31,10 +31,10 @@ class AudioTrack; class AudioPlayer : public TimeSource { public: AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink); ~AudioPlayer(); virtual ~AudioPlayer(); // Caller retains ownership of "source". void setSource(MediaSource *source); void setSource(const sp<MediaSource> &source); // Return time in us. virtual int64_t getRealTimeUs(); Loading @@ -56,7 +56,7 @@ public: status_t seekTo(int64_t time_us); private: MediaSource *mSource; sp<MediaSource> mSource; AudioTrack *mAudioTrack; MediaBuffer *mInputBuffer; Loading Loading
cmds/stagefright/Android.mk +3 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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 # Loading
cmds/stagefright/record.cpp +87 −48 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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; sp<MPEG4Extractor> extractor = new MPEG4Extractor(new MmapSource(filename)); MPEG4Extractor extractor(new MmapSource(argv[1])); int num_tracks; assert(extractor.countTracks(&num_tracks) == ::OK); 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; Loading @@ -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(); Loading @@ -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 Loading
cmds/stagefright/stagefright.cpp +285 −87 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ #include <sys/time.h> #undef NDEBUG #include <assert.h> #include <pthread.h> #include <stdlib.h> Loading @@ -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" Loading @@ -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(); } } OMXDecoder *decoder = OMXDecoder::Create(client, meta); status_t JPEGSource::start(MetaData *) { if (mStarted) { return UNKNOWN_ERROR; } int32_t sampleRate; bool success = meta->findInt32(kKeySampleRate, &sampleRate); assert(success); if (mSource->getSize(&mSize) != OK) { return UNKNOWN_ERROR; } int32_t numChannels; success = meta->findInt32(kKeyChannelCount, &numChannels); assert(success); mGroup = new MediaBufferGroup; mGroup->add_buffer(new MediaBuffer(mSize)); const char *mime; success = meta->findCString(kKeyMIMEType, &mime); assert(success); mOffset = 0; if (!strcasecmp("audio/3gpp", mime)) { numChannels = 1; // XXX mStarted = true; return OK; } WaveWriter writer("/sdcard/Music/shoutcast.wav", numChannels, sampleRate); status_t JPEGSource::stop() { if (!mStarted) { return UNKNOWN_ERROR; } decoder->setSource(source); for (int i = 0; i < 100; ++i) { MediaBuffer *buffer; delete mGroup; mGroup = NULL; ::status_t err = decoder->read(&buffer); if (err != ::OK) { break; mStarted = false; 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; } writer.Append((const char *)buffer->data() + buffer->range_offset(), buffer->range_length()); status_t JPEGSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; 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; } delete decoder; decoder = NULL; 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; } i += 2; if (soi != 0xffd8) { return UNKNOWN_ERROR; } return true; 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 OK; } //////////////////////////////////////////////////////////////////////////////// Loading @@ -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(); Loading @@ -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); Loading @@ -128,26 +356,31 @@ 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; sp<MmapSource> dataSource = new MmapSource(argv[1]); int numTracks; err = extractor->countTracks(&numTracks); bool isJPEG = false; size_t len = strlen(argv[1]); if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) { isJPEG = true; } sp<MediaSource> mediaSource; if (isJPEG) { mediaSource = new JPEGSource(dataSource); } else { sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); size_t numTracks = extractor->countTracks(); sp<MetaData> meta; int i; size_t i; for (i = 0; i < numTracks; ++i) { meta = extractor->getTrackMetaData(i); Loading @@ -163,47 +396,12 @@ int main(int argc, char **argv) { } } OMXDecoder *decoder = OMXDecoder::Create(&client, meta); if (decoder != NULL) { MediaSource *source; err = extractor->getTrack(i, &source); decoder->setSource(source); decoder->start(); int64_t startTime = getNowUs(); int n = 0; MediaBuffer *buffer; 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); delete decoder; decoder = NULL; delete source; source = NULL; mediaSource = extractor->getTrack(i); } delete extractor; extractor = NULL; playSource(&client, mediaSource); client.disconnect(); #endif return 0; }
include/media/IOMX.h +15 −4 Original line number Diff line number Diff line Loading @@ -56,6 +56,14 @@ public: node_id node, OMX_INDEXTYPE index, const void *params, size_t size) = 0; virtual status_t get_config( node_id node, OMX_INDEXTYPE index, void *params, size_t size) = 0; virtual status_t set_config( node_id node, OMX_INDEXTYPE index, const void *params, size_t size) = 0; virtual status_t use_buffer( node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms, buffer_id *buffer) = 0; Loading @@ -82,6 +90,11 @@ public: OMX_U32 range_offset, OMX_U32 range_length, OMX_U32 flags, OMX_TICKS timestamp) = 0; virtual status_t get_extension_index( node_id node, const char *parameter_name, OMX_INDEXTYPE *index) = 0; virtual sp<IOMXRenderer> createRenderer( const sp<ISurface> &surface, const char *componentName, Loading Loading @@ -114,10 +127,11 @@ struct omx_message { QUIT_OBSERVER, } type; IOMX::node_id node; union { // if type == EVENT struct { IOMX::node_id node; OMX_EVENTTYPE event; OMX_U32 data1; OMX_U32 data2; Loading @@ -126,13 +140,11 @@ struct omx_message { // if type == EMPTY_BUFFER_DONE || type == FILL_BUFFER // || type == INITIAL_FILL_BUFFER struct { IOMX::node_id node; IOMX::buffer_id buffer; } buffer_data; // if type == EMPTY_BUFFER || type == FILL_BUFFER_DONE struct { IOMX::node_id node; IOMX::buffer_id buffer; OMX_U32 range_offset; OMX_U32 range_length; Loading @@ -143,7 +155,6 @@ struct omx_message { // if type == SEND_COMMAND struct { IOMX::node_id node; OMX_COMMANDTYPE cmd; OMX_S32 param; } send_command_data; Loading
include/media/stagefright/AudioPlayer.h +3 −3 Original line number Diff line number Diff line Loading @@ -31,10 +31,10 @@ class AudioTrack; class AudioPlayer : public TimeSource { public: AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink); ~AudioPlayer(); virtual ~AudioPlayer(); // Caller retains ownership of "source". void setSource(MediaSource *source); void setSource(const sp<MediaSource> &source); // Return time in us. virtual int64_t getRealTimeUs(); Loading @@ -56,7 +56,7 @@ public: status_t seekTo(int64_t time_us); private: MediaSource *mSource; sp<MediaSource> mSource; AudioTrack *mAudioTrack; MediaBuffer *mInputBuffer; Loading