Merge change 21745 into eclair

* changes:
  Refactored "stagefright" commandline app, split off JPEGSource.
This commit is contained in:
Android (Google) Code Review
2009-08-18 12:52:29 -07:00
5 changed files with 419 additions and 293 deletions

View File

@@ -2,7 +2,8 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
LOCAL_SRC_FILES:= \
JPEGSource.cpp \
stagefright.cpp
LOCAL_SHARED_LIBRARIES := \

View File

@@ -0,0 +1,235 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// #define LOG_NDEBUG 0
#define LOG_TAG "JPEGSource"
#include <utils/Log.h>
#include "JPEGSource.h"
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#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
namespace android {
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;
}
if (mSource->getSize(&mSize) != OK) {
return UNKNOWN_ERROR;
}
mGroup = new MediaBufferGroup;
mGroup->add_buffer(new MediaBuffer(mSize));
mOffset = 0;
mStarted = true;
return OK;
}
status_t JPEGSource::stop() {
if (!mStarted) {
return UNKNOWN_ERROR;
}
delete mGroup;
mGroup = NULL;
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;
}
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;
}
buffer->set_range(0, n);
mOffset += n;
*out = buffer;
return OK;
}
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;
}
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;
}
} // namespace android

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef JPEG_SOURCE_H_
#define JPEG_SOURCE_H_
#include <media/stagefright/MediaSource.h>
namespace android {
class DataSource;
class MediaBufferGroup;
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 &);
};
} // namespace android
#endif // JPEG_SOURCE_H_

View File

@@ -16,18 +16,13 @@
#include <sys/time.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CachingDataSource.h>
#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>
@@ -38,245 +33,11 @@
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/OMXDecoder.h>
#include "WaveWriter.h"
#include "JPEGSource.h"
using namespace android;
////////////////////////////////////////////////////////////////////////////////
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;
}
if (mSource->getSize(&mSize) != OK) {
return UNKNOWN_ERROR;
}
mGroup = new MediaBufferGroup;
mGroup->add_buffer(new MediaBuffer(mSize));
mOffset = 0;
mStarted = true;
return OK;
}
status_t JPEGSource::stop() {
if (!mStarted) {
return UNKNOWN_ERROR;
}
delete mGroup;
mGroup = NULL;
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;
}
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;
}
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;
}
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;
}
////////////////////////////////////////////////////////////////////////////////
static long gNumRepetitions;
static int64_t getNowUs() {
struct timeval tv;
@@ -304,20 +65,38 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
decoder->start();
int n = 0;
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);
long numIterationsLeft = gNumRepetitions;
MediaSource::ReadOptions options;
while (numIterationsLeft-- > 0) {
MediaBuffer *buffer;
for (;;) {
status_t err = decoder->read(&buffer, &options);
options.clearSeekTo();
if (err != OK) {
CHECK_EQ(buffer, NULL);
break;
}
if ((n++ % 16) == 0) {
printf(".");
fflush(stdout);
}
buffer->release();
buffer = NULL;
}
buffer->release();
buffer = NULL;
printf("$");
fflush(stdout);
options.setSeekTo(0);
}
decoder->stop();
printf("\n");
@@ -327,11 +106,64 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
printf("decoded a total of %d frame(s).\n", n);
}
static void usage(const char *me) {
fprintf(stderr, "usage: %s\n", me);
fprintf(stderr, " -h(elp)\n");
fprintf(stderr, " -a(udio)\n");
fprintf(stderr, " -n repetitions\n");
fprintf(stderr, " -l(ist) components\n");
}
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
bool audioOnly = false;
if (argc > 1 && !strcmp(argv[1], "--list")) {
bool listComponents = false;
gNumRepetitions = 1;
int res;
while ((res = getopt(argc, argv, "han:l")) >= 0) {
switch (res) {
case 'a':
{
audioOnly = true;
break;
}
case 'l':
{
listComponents = true;
break;
}
case 'n':
{
char *end;
long x = strtol(optarg, &end, 10);
if (*end != '\0' || end == optarg || x <= 0) {
x = 1;
}
gNumRepetitions = x;
break;
}
case '?':
case 'h':
default:
{
usage(argv[0]);
exit(1);
break;
}
}
}
argc -= optind;
argv += optind;
if (listComponents) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.player"));
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
@@ -348,12 +180,6 @@ int main(int argc, char **argv) {
it != list.end(); ++it) {
printf("%s\n", (*it).string());
}
return 0;
} else if (argc > 1 && !strcmp(argv[1], "--audio")) {
audioOnly = true;
++argv;
--argc;
}
DataSource::RegisterDefaultSniffers();
@@ -361,45 +187,49 @@ int main(int argc, char **argv) {
OMXClient client;
status_t err = client.connect();
sp<MmapSource> dataSource = new MmapSource(argv[1]);
for (int k = 0; k < argc; ++k) {
const char *filename = argv[k];
bool isJPEG = false;
sp<MmapSource> dataSource = new MmapSource(filename);
size_t len = strlen(argv[1]);
if (len >= 4 && !strcasecmp(argv[1] + len - 4, ".jpg")) {
isJPEG = true;
}
bool isJPEG = false;
sp<MediaSource> mediaSource;
if (isJPEG) {
mediaSource = new JPEGSource(dataSource);
} else {
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
size_t numTracks = extractor->countTracks();
sp<MetaData> meta;
size_t i;
for (i = 0; i < numTracks; ++i) {
meta = extractor->getTrackMetaData(i);
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
break;
}
if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
break;
}
size_t len = strlen(filename);
if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) {
isJPEG = true;
}
mediaSource = extractor->getTrack(i);
}
sp<MediaSource> mediaSource;
playSource(&client, mediaSource);
if (isJPEG) {
mediaSource = new JPEGSource(dataSource);
} else {
sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
size_t numTracks = extractor->countTracks();
sp<MetaData> meta;
size_t i;
for (i = 0; i < numTracks; ++i) {
meta = extractor->getTrackMetaData(i);
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
if (audioOnly && !strncasecmp(mime, "audio/", 6)) {
break;
}
if (!audioOnly && !strncasecmp(mime, "video/", 6)) {
break;
}
}
mediaSource = extractor->getTrack(i);
}
playSource(&client, mediaSource);
}
client.disconnect();

View File

@@ -18,6 +18,7 @@
#define MEDIA_BUFFER_GROUP_H_
#include <media/stagefright/MediaBuffer.h>
#include <utils/Errors.h>
#include <utils/threads.h>