summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmds/stagefright/SineSource.cpp4
-rw-r--r--cmds/stagefright/record.cpp49
-rw-r--r--cmds/stagefright/stagefright.cpp50
-rw-r--r--include/media/stagefright/CachingDataSource.h4
-rw-r--r--include/media/stagefright/CameraSource.h26
-rw-r--r--include/media/stagefright/ColorConverter.h67
-rw-r--r--include/media/stagefright/DataSource.h4
-rw-r--r--include/media/stagefright/FileSource.h8
-rw-r--r--include/media/stagefright/HTTPDataSource.h15
-rw-r--r--include/media/stagefright/MediaDefs.h1
-rw-r--r--include/media/stagefright/MediaErrors.h3
-rw-r--r--include/media/stagefright/MediaExtractor.h10
-rw-r--r--include/media/stagefright/MediaSource.h3
-rw-r--r--include/media/stagefright/MetaData.h20
-rw-r--r--include/media/stagefright/MmapSource.h9
-rw-r--r--include/media/stagefright/OMXCodec.h19
-rw-r--r--include/media/stagefright/ShoutcastSource.h4
-rw-r--r--media/libmedia/IOMX.cpp4
-rw-r--r--media/libmediaplayerservice/Android.mk5
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp35
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp21
-rw-r--r--media/libmediaplayerservice/StagefrightMetadataRetriever.cpp197
-rw-r--r--media/libmediaplayerservice/StagefrightMetadataRetriever.h53
-rw-r--r--media/libmediaplayerservice/TestPlayerStub.cpp2
-rw-r--r--media/libstagefright/AMRExtractor.cpp16
-rw-r--r--media/libstagefright/Android.mk8
-rw-r--r--media/libstagefright/AudioPlayer.cpp10
-rw-r--r--media/libstagefright/CachingDataSource.cpp8
-rw-r--r--media/libstagefright/CameraSource.cpp200
-rw-r--r--media/libstagefright/DataSource.cpp11
-rw-r--r--media/libstagefright/ESDS.cpp2
-rw-r--r--media/libstagefright/FileSource.cpp4
-rw-r--r--media/libstagefright/HTTPDataSource.cpp51
-rw-r--r--media/libstagefright/HTTPStream.cpp3
-rw-r--r--media/libstagefright/JPEGSource.cpp6
-rw-r--r--media/libstagefright/MP3Extractor.cpp55
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp90
-rw-r--r--media/libstagefright/MPEG4Writer.cpp14
-rw-r--r--media/libstagefright/MediaBuffer.cpp4
-rw-r--r--media/libstagefright/MediaDefs.cpp1
-rw-r--r--media/libstagefright/MediaExtractor.cpp36
-rw-r--r--media/libstagefright/MediaPlayerImpl.cpp89
-rw-r--r--media/libstagefright/MetaData.cpp19
-rw-r--r--media/libstagefright/MmapSource.cpp11
-rw-r--r--media/libstagefright/OMXCodec.cpp403
-rw-r--r--media/libstagefright/SampleTable.cpp88
-rw-r--r--media/libstagefright/ShoutcastSource.cpp5
-rw-r--r--media/libstagefright/TimedEventQueue.cpp3
-rw-r--r--media/libstagefright/WAVExtractor.cpp317
-rw-r--r--media/libstagefright/include/AMRExtractor.h (renamed from include/media/stagefright/AMRExtractor.h)2
-rw-r--r--media/libstagefright/include/ESDS.h (renamed from include/media/stagefright/ESDS.h)0
-rw-r--r--media/libstagefright/include/HTTPStream.h (renamed from include/media/stagefright/HTTPStream.h)3
-rw-r--r--media/libstagefright/include/MP3Extractor.h (renamed from include/media/stagefright/MP3Extractor.h)2
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h (renamed from include/media/stagefright/MPEG4Extractor.h)3
-rw-r--r--media/libstagefright/include/OMX.h2
-rw-r--r--media/libstagefright/include/SampleTable.h (renamed from include/media/stagefright/SampleTable.h)12
-rw-r--r--media/libstagefright/include/SoftwareRenderer.h (renamed from include/media/stagefright/SoftwareRenderer.h)11
-rw-r--r--media/libstagefright/include/TimedEventQueue.h (renamed from include/media/stagefright/TimedEventQueue.h)0
-rw-r--r--media/libstagefright/include/WAVExtractor.h61
-rw-r--r--media/libstagefright/include/stagefright_string.h (renamed from include/media/stagefright/stagefright_string.h)6
-rw-r--r--media/libstagefright/omx/Android.mk1
-rw-r--r--media/libstagefright/omx/ColorConverter.cpp297
-rw-r--r--media/libstagefright/omx/OMX.cpp4
-rw-r--r--media/libstagefright/omx/SoftwareRenderer.cpp275
-rw-r--r--media/libstagefright/string.cpp (renamed from media/libstagefright/stagefright_string.cpp)2
65 files changed, 2007 insertions, 741 deletions
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index e5a6ccb..e272a65 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -86,8 +86,8 @@ status_t SineSource::read(
x += k;
}
- buffer->meta_data()->setInt32(kKeyTimeUnits, mPhase);
- buffer->meta_data()->setInt32(kKeyTimeScale, mSampleRate);
+ buffer->meta_data()->setInt64(
+ kKeyTime, ((int64_t)mPhase * 1000000) / mSampleRate);
mPhase += numFramesPerBuffer;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 323d448..8c25d85 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -23,7 +23,7 @@
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MPEG4Extractor.h>
+#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MmapSource.h>
#include <media/stagefright/OMXClient.h>
@@ -32,8 +32,10 @@
using namespace android;
-#if 0
+#if 1
class DummySource : public MediaSource {
+ static const int32_t kFramerate = 24; // fps
+
public:
DummySource(int width, int height)
: mWidth(width),
@@ -52,6 +54,7 @@ public:
}
virtual status_t start(MetaData *params) {
+ mNumFramesOutput = 0;
return OK;
}
@@ -61,6 +64,12 @@ public:
virtual status_t read(
MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
+ if (mNumFramesOutput == kFramerate * 10) {
+ // Stop returning data after 10 secs.
+ return ERROR_END_OF_STREAM;
+ }
+
+ // printf("DummySource::read\n");
status_t err = mGroup.acquire_buffer(buffer);
if (err != OK) {
return err;
@@ -69,7 +78,13 @@ public:
char x = (char)((double)rand() / RAND_MAX * 255);
memset((*buffer)->data(), x, mSize);
(*buffer)->set_range(0, mSize);
+ (*buffer)->meta_data()->clear();
+ (*buffer)->meta_data()->setInt64(
+ kKeyTime, (mNumFramesOutput * 1000000) / kFramerate);
+ ++mNumFramesOutput;
+ // printf("DummySource::read - returning buffer\n");
+ // LOGI("DummySource::read - returning buffer");
return OK;
}
@@ -80,6 +95,7 @@ private:
MediaBufferGroup mGroup;
int mWidth, mHeight;
size_t mSize;
+ int64_t mNumFramesOutput;;
DummySource(const DummySource &);
DummySource &operator=(const DummySource &);
@@ -88,8 +104,8 @@ private:
sp<MediaSource> createSource(const char *filename) {
sp<MediaSource> source;
- sp<MPEG4Extractor> extractor =
- new MPEG4Extractor(new MmapSource(filename));
+ sp<MediaExtractor> extractor =
+ MediaExtractor::Create(new MmapSource(filename));
size_t num_tracks = extractor->countTracks();
@@ -117,6 +133,8 @@ sp<MediaSource> createSource(const char *filename) {
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
+ DataSource::RegisterDefaultSniffers();
+
#if 1
if (argc != 2) {
fprintf(stderr, "usage: %s filename\n", argv[0]);
@@ -126,7 +144,7 @@ int main(int argc, char **argv) {
OMXClient client;
CHECK_EQ(client.connect(), OK);
-#if 0
+#if 1
sp<MediaSource> source = createSource(argv[1]);
if (source == NULL) {
@@ -144,8 +162,8 @@ int main(int argc, char **argv) {
success = success && meta->findInt32(kKeyHeight, &height);
CHECK(success);
#else
- int width = 320;
- int height = 240;
+ int width = 800;
+ int height = 480;
sp<MediaSource> decoder = new DummySource(width, height);
#endif
@@ -159,19 +177,26 @@ int main(int argc, char **argv) {
OMXCodec::Create(
client.interface(), enc_meta, true /* createEncoder */, decoder);
-#if 0
+#if 1
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
- writer->addSource(enc_meta, encoder);
+ writer->addSource(encoder);
writer->start();
- sleep(20);
- printf("stopping now.\n");
+ while (!writer->reachedEOS()) {
+ usleep(100000);
+ }
writer->stop();
#else
encoder->start();
MediaBuffer *buffer;
while (encoder->read(&buffer) == OK) {
- printf("got an output frame of size %d\n", buffer->range_length());
+ int32_t isSync;
+ if (!buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)) {
+ isSync = false;
+ }
+
+ printf("got an output frame of size %d%s\n", buffer->range_length(),
+ isSync ? " (SYNC)" : "");
buffer->release();
buffer = NULL;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 4ffc8e4..d26e558 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -52,21 +52,26 @@ static int64_t getNowUs() {
static void playSource(OMXClient *client, const sp<MediaSource> &source) {
sp<MetaData> meta = source->getFormat();
- int32_t durationUnits;
- int32_t timeScale;
- CHECK(meta->findInt32(kKeyDuration, &durationUnits));
- CHECK(meta->findInt32(kKeyTimeScale, &timeScale));
+ int64_t durationUs;
+ CHECK(meta->findInt64(kKeyDuration, &durationUs));
- int64_t durationUs = ((int64_t)durationUnits * 1000000) / timeScale;
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
- sp<OMXCodec> decoder = OMXCodec::Create(
+ sp<MediaSource> rawSource;
+ if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
+ rawSource = source;
+ } else {
+ rawSource = OMXCodec::Create(
client->interface(), meta, false /* createEncoder */, source);
- if (decoder == NULL) {
- return;
+ if (rawSource == NULL) {
+ fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
+ return;
+ }
}
- decoder->start();
+ rawSource->start();
if (gReproduceBug >= 3 && gReproduceBug <= 5) {
status_t err;
@@ -74,24 +79,28 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
MediaSource::ReadOptions options;
int64_t seekTimeUs = -1;
for (;;) {
- err = decoder->read(&buffer, &options);
+ err = rawSource->read(&buffer, &options);
options.clearSeekTo();
bool shouldSeek = false;
- if (err != OK) {
+ if (err == INFO_FORMAT_CHANGED) {
+ CHECK_EQ(buffer, NULL);
+
+ printf("format changed.\n");
+ continue;
+ } else if (err != OK) {
printf("reached EOF.\n");
shouldSeek = true;
} else {
- int32_t timestampUnits;
- CHECK(buffer->meta_data()->findInt32(kKeyTimeUnits, &timestampUnits));
-
- int64_t timestampUs = ((int64_t)timestampUnits * 1000000) / timeScale;
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
bool failed = false;
if (seekTimeUs >= 0) {
int64_t diff = timestampUs - seekTimeUs;
+
if (diff < 0) {
diff = -diff;
}
@@ -134,7 +143,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
}
}
- decoder->stop();
+ rawSource->stop();
return;
}
@@ -151,12 +160,17 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
MediaBuffer *buffer;
for (;;) {
- status_t err = decoder->read(&buffer, &options);
+ status_t err = rawSource->read(&buffer, &options);
options.clearSeekTo();
if (err != OK) {
CHECK_EQ(buffer, NULL);
+ if (err == INFO_FORMAT_CHANGED) {
+ printf("format changed.\n");
+ continue;
+ }
+
break;
}
@@ -188,7 +202,7 @@ static void playSource(OMXClient *client, const sp<MediaSource> &source) {
options.setSeekTo(0);
}
- decoder->stop();
+ rawSource->stop();
printf("\n");
int64_t delay = getNowUs() - startTime;
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
index e35e19e..b0fc4b2 100644
--- a/include/media/stagefright/CachingDataSource.h
+++ b/include/media/stagefright/CachingDataSource.h
@@ -29,9 +29,9 @@ public:
CachingDataSource(
const sp<DataSource> &source, size_t pageSize, int numPages);
- status_t InitCheck() const;
+ virtual status_t initCheck() const;
- virtual ssize_t read_at(off_t offset, void *data, size_t size);
+ virtual ssize_t readAt(off_t offset, void *data, size_t size);
protected:
virtual ~CachingDataSource();
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 7042e1a..ff3ea05 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -26,12 +26,11 @@
namespace android {
-class ICamera;
-class ICameraClient;
class IMemory;
+class ISurface;
+class Camera;
-class CameraSource : public MediaSource,
- public MediaBufferObserver {
+class CameraSource : public MediaSource {
public:
static CameraSource *Create();
@@ -45,24 +44,25 @@ public:
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
- virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
- virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
-
- virtual void signalBufferReturned(MediaBuffer *buffer);
-
private:
- CameraSource(const sp<ICamera> &camera, const sp<ICameraClient> &client);
+ friend class CameraSourceListener;
- sp<ICamera> mCamera;
- sp<ICameraClient> mCameraClient;
+ sp<Camera> mCamera;
Mutex mLock;
Condition mFrameAvailableCondition;
List<sp<IMemory> > mFrames;
+ List<int64_t> mFrameTimes;
- int mNumFrames;
+ int mWidth, mHeight;
+ int64_t mFirstFrameTimeUs;
+ int32_t mNumFrames;
bool mStarted;
+ CameraSource(const sp<Camera> &camera);
+
+ void dataCallback(int32_t msgType, const sp<IMemory> &data);
+
CameraSource(const CameraSource &);
CameraSource &operator=(const CameraSource &);
};
diff --git a/include/media/stagefright/ColorConverter.h b/include/media/stagefright/ColorConverter.h
new file mode 100644
index 0000000..1e341b9
--- /dev/null
+++ b/include/media/stagefright/ColorConverter.h
@@ -0,0 +1,67 @@
+/*
+ * 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 COLOR_CONVERTER_H_
+
+#define COLOR_CONVERTER_H_
+
+#include <sys/types.h>
+
+#include <stdint.h>
+
+#include <OMX_Video.h>
+
+namespace android {
+
+struct ColorConverter {
+ ColorConverter(OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to);
+ ~ColorConverter();
+
+ bool isValid() const;
+
+ void convert(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip);
+
+private:
+ OMX_COLOR_FORMATTYPE mSrcFormat, mDstFormat;
+ uint8_t *mClip;
+
+ uint8_t *initClip();
+
+ void convertCbYCrY(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip);
+
+ void convertYUV420Planar(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip);
+
+ void convertQCOMYUV420SemiPlanar(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip);
+
+ ColorConverter(const ColorConverter &);
+ ColorConverter &operator=(const ColorConverter &);
+};
+
+} // namespace android
+
+#endif // COLOR_CONVERTER_H_
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index f46f0af..b843cd9 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -33,7 +33,9 @@ class DataSource : public RefBase {
public:
DataSource() {}
- virtual ssize_t read_at(off_t offset, void *data, size_t size) = 0;
+ virtual status_t initCheck() const = 0;
+
+ virtual ssize_t readAt(off_t offset, void *data, size_t size) = 0;
// Convenience methods:
bool getUInt16(off_t offset, uint16_t *x);
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index ccbe0ef..d7b42c3 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -29,11 +29,13 @@ namespace android {
class FileSource : public DataSource {
public:
FileSource(const char *filename);
- virtual ~FileSource();
- status_t InitCheck() const;
+ virtual status_t initCheck() const;
+
+ virtual ssize_t readAt(off_t offset, void *data, size_t size);
- virtual ssize_t read_at(off_t offset, void *data, size_t size);
+protected:
+ virtual ~FileSource();
private:
FILE *mFile;
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index 0587c7c..d5dc9e6 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -19,28 +19,29 @@
#define HTTP_DATASOURCE_H_
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/HTTPStream.h>
namespace android {
+class HTTPStream;
+
class HTTPDataSource : public DataSource {
public:
HTTPDataSource(const char *host, int port, const char *path);
HTTPDataSource(const char *uri);
- virtual ~HTTPDataSource();
+ virtual status_t initCheck() const;
- // XXXandih
- status_t InitCheck() const { return OK; }
+ virtual ssize_t readAt(off_t offset, void *data, size_t size);
- virtual ssize_t read_at(off_t offset, void *data, size_t size);
+protected:
+ virtual ~HTTPDataSource();
private:
enum {
kBufferSize = 64 * 1024
};
- HTTPStream mHttp;
+ HTTPStream *mHttp;
char *mHost;
int mPort;
char *mPath;
@@ -49,6 +50,8 @@ private:
size_t mBufferLength;
off_t mBufferOffset;
+ status_t mInitCheck;
+
HTTPDataSource(const HTTPDataSource &);
HTTPDataSource &operator=(const HTTPDataSource &);
};
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index feb66e3..1efeb92 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -34,6 +34,7 @@ extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
+extern const char *MEDIA_MIMETYPE_CONTAINER_WAV;
} // namespace android
diff --git a/include/media/stagefright/MediaErrors.h b/include/media/stagefright/MediaErrors.h
index 2bb0ed6..73d0f77 100644
--- a/include/media/stagefright/MediaErrors.h
+++ b/include/media/stagefright/MediaErrors.h
@@ -36,6 +36,9 @@ enum {
ERROR_BUFFER_TOO_SMALL = MEDIA_ERROR_BASE - 9,
ERROR_UNSUPPORTED = MEDIA_ERROR_BASE - 10,
ERROR_END_OF_STREAM = MEDIA_ERROR_BASE - 11,
+
+ // Not technically an error.
+ INFO_FORMAT_CHANGED = MEDIA_ERROR_BASE - 12,
};
} // namespace android
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 67e45bd..d56d4b3 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -31,9 +31,17 @@ public:
static sp<MediaExtractor> Create(
const sp<DataSource> &source, const char *mime = NULL);
+ static sp<MediaExtractor> CreateFromURI(
+ const char *uri, const char *mime = NULL);
+
virtual size_t countTracks() = 0;
virtual sp<MediaSource> getTrack(size_t index) = 0;
- virtual sp<MetaData> getTrackMetaData(size_t index) = 0;
+
+ enum GetTrackMetaDataFlags {
+ kIncludeExtensiveMetaData = 1
+ };
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags = 0) = 0;
protected:
MediaExtractor() {}
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index d1fa114..96d57e7 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -51,6 +51,9 @@ struct MediaSource : public RefBase {
// buffer is available, an error is encountered of the end of the stream
// is reached.
// End of stream is signalled by a result of ERROR_END_OF_STREAM.
+ // A result of INFO_FORMAT_CHANGED indicates that the format of this
+ // MediaSource has changed mid-stream, the client can continue reading
+ // but should be prepared for buffers of the new configuration.
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index abb45a9..c2d8f98 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -27,25 +27,26 @@
namespace android {
+// The following keys map to int32_t data unless indicated otherwise.
enum {
- kKeyMIMEType = 'mime',
+ kKeyMIMEType = 'mime', // cstring
kKeyWidth = 'widt',
kKeyHeight = 'heig',
kKeyChannelCount = '#chn',
kKeySampleRate = 'srte',
kKeyBitRate = 'brte',
- kKeyESDS = 'esds',
- kKeyAVCC = 'avcc',
- kKeyTimeUnits = '#tim',
- kKeyTimeScale = 'scal',
+ kKeyESDS = 'esds', // raw data
+ kKeyAVCC = 'avcc', // raw data
kKeyWantsNALFragments = 'NALf',
kKeyIsSyncFrame = 'sync',
- kKeyDuration = 'dura',
+ kKeyTime = 'time', // int64_t (usecs)
+ kKeyDuration = 'dura', // int64_t (usecs)
kKeyColorFormat = 'colf',
- kKeyPlatformPrivate = 'priv',
- kKeyDecoderComponent = 'decC',
+ kKeyPlatformPrivate = 'priv', // pointer
+ kKeyDecoderComponent = 'decC', // cstring
kKeyBufferID = 'bfID',
kKeyMaxInputSize = 'inpS',
+ kKeyThumbnailTime = 'thbT', // int64_t (usecs)
};
enum {
@@ -62,6 +63,7 @@ public:
TYPE_NONE = 'none',
TYPE_C_STRING = 'cstr',
TYPE_INT32 = 'in32',
+ TYPE_INT64 = 'in64',
TYPE_FLOAT = 'floa',
TYPE_POINTER = 'ptr ',
};
@@ -71,11 +73,13 @@ public:
bool setCString(uint32_t key, const char *value);
bool setInt32(uint32_t key, int32_t value);
+ bool setInt64(uint32_t key, int64_t value);
bool setFloat(uint32_t key, float value);
bool setPointer(uint32_t key, void *value);
bool findCString(uint32_t key, const char **value);
bool findInt32(uint32_t key, int32_t *value);
+ bool findInt64(uint32_t key, int64_t *value);
bool findFloat(uint32_t key, float *value);
bool findPointer(uint32_t key, void **value);
diff --git a/include/media/stagefright/MmapSource.h b/include/media/stagefright/MmapSource.h
index a8bd57f..1b39d53 100644
--- a/include/media/stagefright/MmapSource.h
+++ b/include/media/stagefright/MmapSource.h
@@ -30,13 +30,14 @@ public:
// Assumes ownership of "fd".
MmapSource(int fd, int64_t offset, int64_t length);
- virtual ~MmapSource();
-
- status_t InitCheck() const;
+ virtual status_t initCheck() const;
- virtual ssize_t read_at(off_t offset, void *data, size_t size);
+ virtual ssize_t readAt(off_t offset, void *data, size_t size);
virtual status_t getSize(off_t *size);
+protected:
+ virtual ~MmapSource();
+
private:
int mFd;
void *mBase;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 3f3dcf9..7890883 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -30,11 +30,15 @@ struct OMXCodecObserver;
struct OMXCodec : public MediaSource,
public MediaBufferObserver {
+ enum CreationFlags {
+ kPreferSoftwareCodecs = 1,
+ };
static sp<OMXCodec> Create(
const sp<IOMX> &omx,
const sp<MetaData> &meta, bool createEncoder,
const sp<MediaSource> &source,
- const char *matchComponentName = NULL);
+ const char *matchComponentName = NULL,
+ uint32_t flags = 0);
static void setComponentRole(
const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
@@ -90,7 +94,6 @@ private:
kRequiresFlushCompleteEmulation = 16,
kRequiresAllocateBufferOnOutputPorts = 32,
kRequiresFlushBeforeShutdown = 64,
- kOutputDimensionsAre16Aligned = 128,
};
struct BufferInfo {
@@ -107,7 +110,6 @@ private:
sp<IOMX> mOMX;
IOMX::node_id mNode;
- sp<OMXCodecObserver> mObserver;
uint32_t mQuirks;
bool mIsEncoder;
char *mMIME;
@@ -125,6 +127,7 @@ private:
bool mInitialBufferSubmit;
bool mSignalledEOS;
bool mNoMoreOutputData;
+ bool mOutputPortSettingsHaveChanged;
int64_t mSeekTimeUs;
Mutex mLock;
@@ -155,6 +158,8 @@ private:
void setVideoInputFormat(
const char *mime, OMX_U32 width, OMX_U32 height);
+ status_t setupMPEG4EncoderParameters();
+
void setVideoOutputFormat(
const char *mime, OMX_U32 width, OMX_U32 height);
@@ -208,6 +213,14 @@ private:
void dumpPortStatus(OMX_U32 portIndex);
+ static uint32_t getComponentQuirks(const char *componentName);
+
+ static void findMatchingCodecs(
+ const char *mime,
+ bool createEncoder, const char *matchComponentName,
+ uint32_t flags,
+ Vector<String8> *matchingCodecs);
+
OMXCodec(const OMXCodec &);
OMXCodec &operator=(const OMXCodec &);
};
diff --git a/include/media/stagefright/ShoutcastSource.h b/include/media/stagefright/ShoutcastSource.h
index 352857a..bc67156 100644
--- a/include/media/stagefright/ShoutcastSource.h
+++ b/include/media/stagefright/ShoutcastSource.h
@@ -31,7 +31,6 @@ class ShoutcastSource : public MediaSource {
public:
// Assumes ownership of "http".
ShoutcastSource(HTTPStream *http);
- virtual ~ShoutcastSource();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -41,6 +40,9 @@ public:
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
+protected:
+ virtual ~ShoutcastSource();
+
private:
HTTPStream *mHttp;
size_t mMetaDataOffset;
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 88a7064..76a9e7d 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -284,7 +284,7 @@ public:
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeIntPtr((intptr_t)node);
data.writeIntPtr((intptr_t)buffer);
- remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ remote()->transact(FILL_BUFFER, data, &reply);
return reply.readInt32();
}
@@ -302,7 +302,7 @@ public:
data.writeInt32(range_length);
data.writeInt32(flags);
data.writeInt64(timestamp);
- remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
+ remote()->transact(EMPTY_BUFFER, data, &reply);
return reply.readInt32();
}
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index fb569da..6fc9fa2 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -18,8 +18,9 @@ LOCAL_SRC_FILES:= \
ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
-LOCAL_SRC_FILES += \
- StagefrightPlayer.cpp
+LOCAL_SRC_FILES += \
+ StagefrightPlayer.cpp \
+ StagefrightMetadataRetriever.cpp
LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 0a6c365..b81684b 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -366,11 +366,44 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
extern "C" void free_malloc_leak_info(uint8_t* info);
+// Use the String-class below instead of String8 to allocate all memory
+// beforehand and not reenter the heap while we are examining it...
+struct MyString8 {
+ static const size_t MAX_SIZE = 256 * 1024;
+
+ MyString8()
+ : mPtr((char *)malloc(MAX_SIZE)) {
+ *mPtr = '\0';
+ }
+
+ ~MyString8() {
+ free(mPtr);
+ }
+
+ void append(const char *s) {
+ strcat(mPtr, s);
+ }
+
+ const char *string() const {
+ return mPtr;
+ }
+
+ size_t size() const {
+ return strlen(mPtr);
+ }
+
+private:
+ char *mPtr;
+
+ MyString8(const MyString8 &);
+ MyString8 &operator=(const MyString8 &);
+};
+
void memStatus(int fd, const Vector<String16>& args)
{
const size_t SIZE = 256;
char buffer[SIZE];
- String8 result;
+ MyString8 result;
typedef struct {
size_t size;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 2cdc351..866c7bd 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -38,6 +38,7 @@
#include "VorbisMetadataRetriever.h"
#include "MidiMetadataRetriever.h"
#include "MetadataRetrieverClient.h"
+#include "StagefrightMetadataRetriever.h"
/* desktop Linux needs a little help with gettid() */
#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
@@ -118,9 +119,15 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
LOGV("create midi metadata retriever");
p = new MidiMetadataRetriever();
break;
+#if BUILD_WITH_FULL_STAGEFRIGHT
+ case STAGEFRIGHT_PLAYER:
+ LOGV("create StagefrightMetadataRetriever");
+ p = new StagefrightMetadataRetriever;
+ break;
+#endif
default:
// TODO:
- // support for STAGEFRIGHT_PLAYER and TEST_PLAYER
+ // support for TEST_PLAYER
LOGE("player type %d is not supported", playerType);
break;
}
@@ -138,12 +145,6 @@ status_t MetadataRetrieverClient::setDataSource(const char *url)
return UNKNOWN_ERROR;
}
player_type playerType = getPlayerType(url);
-#if !defined(NO_OPENCORE) && defined(BUILD_WITH_FULL_STAGEFRIGHT)
- if (playerType == STAGEFRIGHT_PLAYER) {
- // Stagefright doesn't support metadata in this branch yet.
- playerType = PV_PLAYER;
- }
-#endif
LOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) return NO_INIT;
@@ -182,12 +183,6 @@ status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t
}
player_type playerType = getPlayerType(fd, offset, length);
-#if !defined(NO_OPENCORE) && defined(BUILD_WITH_FULL_STAGEFRIGHT)
- if (playerType == STAGEFRIGHT_PLAYER) {
- // Stagefright doesn't support metadata in this branch yet.
- playerType = PV_PLAYER;
- }
-#endif
LOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) {
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
new file mode 100644
index 0000000..7a3aee8
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -0,0 +1,197 @@
+/*
+**
+** Copyright 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 "StagefrightMetadataRetriever"
+#include <utils/Log.h>
+
+#include "StagefrightMetadataRetriever.h"
+
+#include <media/stagefright/CachingDataSource.h>
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MmapSource.h>
+#include <media/stagefright/OMXCodec.h>
+
+namespace android {
+
+StagefrightMetadataRetriever::StagefrightMetadataRetriever() {
+ LOGV("StagefrightMetadataRetriever()");
+
+ DataSource::RegisterDefaultSniffers();
+ CHECK_EQ(mClient.connect(), OK);
+}
+
+StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
+ LOGV("~StagefrightMetadataRetriever()");
+ mClient.disconnect();
+}
+
+status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
+ LOGV("setDataSource(%s)", uri);
+
+ mExtractor = MediaExtractor::CreateFromURI(uri);
+
+ return mExtractor.get() != NULL ? OK : UNKNOWN_ERROR;
+}
+
+status_t StagefrightMetadataRetriever::setDataSource(
+ int fd, int64_t offset, int64_t length) {
+ LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+
+ mExtractor = MediaExtractor::Create(
+ new MmapSource(fd, offset, length));
+
+ return OK;
+}
+
+VideoFrame *StagefrightMetadataRetriever::captureFrame() {
+ LOGV("captureFrame");
+
+ if (mExtractor.get() == NULL) {
+ LOGV("no extractor.");
+ return NULL;
+ }
+
+ size_t n = mExtractor->countTracks();
+ size_t i;
+ for (i = 0; i < n; ++i) {
+ sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strncasecmp(mime, "video/", 6)) {
+ break;
+ }
+ }
+
+ if (i == n) {
+ LOGV("no video track found.");
+ return NULL;
+ }
+
+ sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
+ i, MediaExtractor::kIncludeExtensiveMetaData);
+
+ sp<MediaSource> source = mExtractor->getTrack(i);
+
+ if (source.get() == NULL) {
+ LOGV("unable to instantiate video track.");
+ return NULL;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ sp<MediaSource> decoder =
+ OMXCodec::Create(
+ mClient.interface(), meta, false, source,
+ NULL, OMXCodec::kPreferSoftwareCodecs);
+
+ if (decoder.get() == NULL) {
+ LOGV("unable to instantiate video decoder.");
+
+ return NULL;
+ }
+
+ decoder->start();
+
+ // Read one output buffer, ignore format change notifications
+ // and spurious empty buffers.
+
+ MediaSource::ReadOptions options;
+ int64_t thumbNailTime;
+ if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
+ options.setSeekTo(thumbNailTime);
+ }
+
+ MediaBuffer *buffer = NULL;
+ status_t err;
+ do {
+ if (buffer != NULL) {
+ buffer->release();
+ buffer = NULL;
+ }
+ err = decoder->read(&buffer, &options);
+ options.clearSeekTo();
+ } while (err == INFO_FORMAT_CHANGED
+ || (buffer != NULL && buffer->range_length() == 0));
+
+ if (err != OK) {
+ CHECK_EQ(buffer, NULL);
+
+ LOGV("decoding frame failed.");
+ decoder->stop();
+
+ return NULL;
+ }
+
+ LOGV("successfully decoded video frame.");
+
+ meta = decoder->getFormat();
+
+ int32_t width, height;
+ CHECK(meta->findInt32(kKeyWidth, &width));
+ CHECK(meta->findInt32(kKeyHeight, &height));
+
+ VideoFrame *frame = new VideoFrame;
+ frame->mWidth = width;
+ frame->mHeight = height;
+ frame->mDisplayWidth = width;
+ frame->mDisplayHeight = height;
+ frame->mSize = width * height * 2;
+ frame->mData = new uint8_t[frame->mSize];
+
+ int32_t srcFormat;
+ CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
+
+ ColorConverter converter(
+ (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
+ CHECK(converter.isValid());
+
+ converter.convert(
+ width, height,
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ 0,
+ frame->mData, width * 2);
+
+ buffer->release();
+ buffer = NULL;
+
+ decoder->stop();
+
+ return frame;
+}
+
+MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
+ LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
+
+ return NULL;
+}
+
+const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
+ LOGV("extractMetadata %d (extractor: %s)",
+ keyCode, mExtractor.get() != NULL ? "YES" : "NO");
+
+ return NULL;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.h b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
new file mode 100644
index 0000000..16127d7
--- /dev/null
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.h
@@ -0,0 +1,53 @@
+/*
+**
+** Copyright 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 STAGEFRIGHT_METADATA_RETRIEVER_H_
+
+#define STAGEFRIGHT_METADATA_RETRIEVER_H_
+
+#include <media/MediaMetadataRetrieverInterface.h>
+
+#include <media/stagefright/OMXClient.h>
+
+namespace android {
+
+class MediaExtractor;
+
+struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface {
+ StagefrightMetadataRetriever();
+ virtual ~StagefrightMetadataRetriever();
+
+ virtual status_t setDataSource(const char *url);
+ virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
+
+ virtual VideoFrame *captureFrame();
+ virtual MediaAlbumArt *extractAlbumArt();
+ virtual const char *extractMetadata(int keyCode);
+
+private:
+ OMXClient mClient;
+ sp<MediaExtractor> mExtractor;
+
+ StagefrightMetadataRetriever(const StagefrightMetadataRetriever &);
+
+ StagefrightMetadataRetriever &operator=(
+ const StagefrightMetadataRetriever &);
+};
+
+} // namespace android
+
+#endif // STAGEFRIGHT_METADATA_RETRIEVER_H_
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
index 8627708..aa49429 100644
--- a/media/libmediaplayerservice/TestPlayerStub.cpp
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -176,7 +176,7 @@ status_t TestPlayerStub::resetInternal()
mContentUrl = NULL;
if (mPlayer) {
- LOG_ASSERT(mDeletePlayer != NULL);
+ LOG_ASSERT(mDeletePlayer != NULL, "mDeletePlayer is null");
(*mDeletePlayer)(mPlayer);
mPlayer = NULL;
}
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 8d85ce2..1e3c5a4 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -18,7 +18,8 @@
#define LOG_TAG "AMRExtractor"
#include <utils/Log.h>
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
@@ -86,7 +87,7 @@ sp<MediaSource> AMRExtractor::getTrack(size_t index) {
return new AMRSource(mDataSource, mIsWide);
}
-sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) {
+sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -155,7 +156,7 @@ status_t AMRSource::read(
*out = NULL;
uint8_t header;
- ssize_t n = mDataSource->read_at(mOffset, &header, 1);
+ ssize_t n = mDataSource->readAt(mOffset, &header, 1);
if (n < 1) {
return ERROR_IO;
@@ -191,7 +192,7 @@ status_t AMRSource::read(
// Round up bits to bytes and add 1 for the header byte.
frameSize = (frameSize + 7) / 8 + 1;
- n = mDataSource->read_at(mOffset, buffer->data(), frameSize);
+ n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
if (n != (ssize_t)frameSize) {
buffer->release();
@@ -201,10 +202,7 @@ status_t AMRSource::read(
}
buffer->set_range(0, frameSize);
- buffer->meta_data()->setInt32(
- kKeyTimeUnits, (mCurrentTimeUs + 500) / 1000);
- buffer->meta_data()->setInt32(
- kKeyTimeScale, 1000);
+ buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
mOffset += frameSize;
mCurrentTimeUs += 20000; // Each frame is 20ms
@@ -220,7 +218,7 @@ bool SniffAMR(
const sp<DataSource> &source, String8 *mimeType, float *confidence) {
char header[9];
- if (source->read_at(0, header, sizeof(header)) != sizeof(header)) {
+ if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
return false;
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 9f71dae..c36e769 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -16,24 +16,26 @@ ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
LOCAL_SRC_FILES += \
AMRExtractor.cpp \
+ AudioPlayer.cpp \
CachingDataSource.cpp \
+ CameraSource.cpp \
DataSource.cpp \
FileSource.cpp \
HTTPDataSource.cpp \
HTTPStream.cpp \
JPEGSource.cpp \
- MediaExtractor.cpp \
MP3Extractor.cpp \
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
+ MediaExtractor.cpp \
MediaPlayerImpl.cpp \
MmapSource.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
- AudioPlayer.cpp \
- stagefright_string.cpp
+ WAVExtractor.cpp \
+ string.cpp
endif
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 538facb..d7e3f66 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -210,15 +210,9 @@ void AudioPlayer::fillBuffer(void *data, size_t size) {
break;
}
- int32_t units, scale;
- bool success =
- mInputBuffer->meta_data()->findInt32(kKeyTimeUnits, &units);
- success = success &&
- mInputBuffer->meta_data()->findInt32(kKeyTimeScale, &scale);
- CHECK(success);
-
Mutex::Autolock autoLock(mLock);
- mPositionTimeMediaUs = (int64_t)units * 1000000 / scale;
+ CHECK(mInputBuffer->meta_data()->findInt64(
+ kKeyTime, &mPositionTimeMediaUs));
mPositionTimeRealUs =
((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
index fd00576..23f4897 100644
--- a/media/libstagefright/CachingDataSource.cpp
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -61,11 +61,11 @@ CachingDataSource::~CachingDataSource() {
mData = NULL;
}
-status_t CachingDataSource::InitCheck() const {
- return OK;
+status_t CachingDataSource::initCheck() const {
+ return mSource->initCheck();
}
-ssize_t CachingDataSource::read_at(off_t offset, void *data, size_t size) {
+ssize_t CachingDataSource::readAt(off_t offset, void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
size_t total = 0;
@@ -82,7 +82,7 @@ ssize_t CachingDataSource::read_at(off_t offset, void *data, size_t size) {
if (page == NULL) {
page = allocate_page();
page->mOffset = offset - offset % mPageSize;
- ssize_t n = mSource->read_at(page->mOffset, page->mData, mPageSize);
+ ssize_t n = mSource->readAt(page->mOffset, page->mData, mPageSize);
if (n < 0) {
page->mLength = 0;
} else {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 596ab67..e9d8557 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -21,120 +21,142 @@
#include <binder/IServiceManager.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
-#include <ui/ICameraClient.h>
-#include <ui/ICameraService.h>
+#include <ui/Camera.h>
+#include <ui/CameraParameters.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/ISurface.h>
#include <ui/Overlay.h>
-#include <utils/String16.h>
+#include <utils/String8.h>
namespace android {
-class CameraBuffer : public MediaBuffer {
-public:
- CameraBuffer(const sp<IMemory> &frame)
- : MediaBuffer(frame->pointer(), frame->size()),
- mFrame(frame) {
- }
+static int64_t getNowUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
- sp<IMemory> releaseFrame() {
- sp<IMemory> frame = mFrame;
- mFrame.clear();
- return frame;
- }
+ return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
+}
-private:
- sp<IMemory> mFrame;
-};
+struct DummySurface : public BnSurface {
+ DummySurface() {}
-class CameraSourceClient : public BnCameraClient {
-public:
- CameraSourceClient()
- : mSource(NULL) {
+ virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) {
+ return NULL;
}
- virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
- CHECK(mSource != NULL);
- mSource->notifyCallback(msgType, ext1, ext2);
+ virtual status_t registerBuffers(const BufferHeap &buffers) {
+ return OK;
}
- virtual void dataCallback(int32_t msgType, const sp<IMemory> &data) {
- CHECK(mSource != NULL);
- mSource->dataCallback(msgType, data);
- }
+ virtual void postBuffer(ssize_t offset) {}
+ virtual void unregisterBuffers() {}
- void setCameraSource(CameraSource *source) {
- mSource = source;
+ virtual sp<OverlayRef> createOverlay(
+ uint32_t w, uint32_t h, int32_t format) {
+ return NULL;
}
+protected:
+ virtual ~DummySurface() {}
+
+ DummySurface(const DummySurface &);
+ DummySurface &operator=(const DummySurface &);
+};
+
+struct CameraSourceListener : public CameraListener {
+ CameraSourceListener(const sp<CameraSource> &source);
+
+ virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
+ virtual void postData(int32_t msgType, const sp<IMemory> &dataPtr);
+
+ virtual void postDataTimestamp(
+ nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+
+protected:
+ virtual ~CameraSourceListener();
+
private:
- CameraSource *mSource;
+ wp<CameraSource> mSource;
+
+ CameraSourceListener(const CameraSourceListener &);
+ CameraSourceListener &operator=(const CameraSourceListener &);
};
-class DummySurface : public BnSurface {
-public:
- DummySurface() {}
+CameraSourceListener::CameraSourceListener(const sp<CameraSource> &source)
+ : mSource(source) {
+}
- virtual status_t registerBuffers(const BufferHeap &buffers) {
- return OK;
- }
+CameraSourceListener::~CameraSourceListener() {
+}
- virtual void postBuffer(ssize_t offset) {
- }
+void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
+ LOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
+}
- virtual void unregisterBuffers() {
- }
-
- virtual sp<OverlayRef> createOverlay(
- uint32_t w, uint32_t h, int32_t format) {
- return NULL;
+void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) {
+ LOGV("postData(%d, ptr:%p, size:%d)",
+ msgType, dataPtr->pointer(), dataPtr->size());
+
+ sp<CameraSource> source = mSource.promote();
+ if (source.get() != NULL) {
+ source->dataCallback(msgType, dataPtr);
}
-};
+}
+
+void CameraSourceListener::postDataTimestamp(
+ nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
+ LOGV("postDataTimestamp(%lld, %d, ptr:%p, size:%d)",
+ timestamp, msgType, dataPtr->pointer(), dataPtr->size());
+}
// static
CameraSource *CameraSource::Create() {
- sp<IServiceManager> sm = defaultServiceManager();
-
- sp<ICameraService> service =
- interface_cast<ICameraService>(
- sm->getService(String16("media.camera")));
+ sp<Camera> camera = Camera::connect();
- sp<CameraSourceClient> client = new CameraSourceClient;
- sp<ICamera> camera = service->connect(client);
-
- CameraSource *source = new CameraSource(camera, client);
- client->setCameraSource(source);
+ if (camera.get() == NULL) {
+ return NULL;
+ }
- return source;
+ return new CameraSource(camera);
}
-CameraSource::CameraSource(
- const sp<ICamera> &camera, const sp<ICameraClient> &client)
+CameraSource::CameraSource(const sp<Camera> &camera)
: mCamera(camera),
- mCameraClient(client),
+ mWidth(0),
+ mHeight(0),
+ mFirstFrameTimeUs(0),
mNumFrames(0),
mStarted(false) {
- printf("params: \"%s\"\n", mCamera->getParameters().string());
+ String8 s = mCamera->getParameters();
+ printf("params: \"%s\"\n", s.string());
+
+ CameraParameters params(s);
+ params.getPreviewSize(&mWidth, &mHeight);
}
CameraSource::~CameraSource() {
if (mStarted) {
stop();
}
-
- mCamera->disconnect();
}
status_t CameraSource::start(MetaData *) {
CHECK(!mStarted);
- status_t err = mCamera->lock();
- CHECK_EQ(err, OK);
+ mCamera->setListener(new CameraSourceListener(this));
- err = mCamera->setPreviewDisplay(new DummySurface);
+ sp<ISurface> dummy = new DummySurface;
+ status_t err = mCamera->setPreviewDisplay(dummy);
CHECK_EQ(err, OK);
- mCamera->setPreviewCallbackFlag(1);
- mCamera->startPreview();
+
+ mCamera->setPreviewCallbackFlags(
+ FRAME_CALLBACK_FLAG_ENABLE_MASK
+ | FRAME_CALLBACK_FLAG_COPY_OUT_MASK);
+
+ err = mCamera->startPreview();
CHECK_EQ(err, OK);
mStarted = true;
@@ -146,7 +168,6 @@ status_t CameraSource::stop() {
CHECK(mStarted);
mCamera->stopPreview();
- mCamera->unlock();
mStarted = false;
@@ -157,8 +178,8 @@ sp<MetaData> CameraSource::getFormat() {
sp<MetaData> meta = new MetaData;
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
- meta->setInt32(kKeyWidth, 480);
- meta->setInt32(kKeyHeight, 320);
+ meta->setInt32(kKeyWidth, mWidth);
+ meta->setInt32(kKeyHeight, mHeight);
return meta;
}
@@ -175,6 +196,7 @@ status_t CameraSource::read(
}
sp<IMemory> frame;
+ int64_t frameTime;
{
Mutex::Autolock autoLock(mLock);
@@ -184,41 +206,33 @@ status_t CameraSource::read(
frame = *mFrames.begin();
mFrames.erase(mFrames.begin());
- }
- int count = mNumFrames++;
+ frameTime = *mFrameTimes.begin();
+ mFrameTimes.erase(mFrameTimes.begin());
+ }
- *buffer = new CameraBuffer(frame);
+ *buffer = new MediaBuffer(frame->size());
+ memcpy((*buffer)->data(), frame->pointer(), frame->size());
+ (*buffer)->set_range(0, frame->size());
(*buffer)->meta_data()->clear();
- (*buffer)->meta_data()->setInt32(kKeyTimeScale, 15);
- (*buffer)->meta_data()->setInt32(kKeyTimeUnits, count);
-
- (*buffer)->add_ref();
- (*buffer)->setObserver(this);
+ (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
return OK;
}
-void CameraSource::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
- printf("notifyCallback %d, %d, %d\n", msgType, ext1, ext2);
-}
-
void CameraSource::dataCallback(int32_t msgType, const sp<IMemory> &data) {
Mutex::Autolock autoLock(mLock);
+ int64_t nowUs = getNowUs();
+ if (mNumFrames == 0) {
+ mFirstFrameTimeUs = nowUs;
+ }
+ ++mNumFrames;
+
mFrames.push_back(data);
+ mFrameTimes.push_back(nowUs - mFirstFrameTimeUs);
mFrameAvailableCondition.signal();
}
-void CameraSource::signalBufferReturned(MediaBuffer *_buffer) {
- CameraBuffer *buffer = static_cast<CameraBuffer *>(_buffer);
-
- mCamera->releaseRecordingFrame(buffer->releaseFrame());
-
- buffer->setObserver(NULL);
- buffer->release();
- buffer = NULL;
-}
-
} // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index daac539..2a6dbc4 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+#include "include/MP3Extractor.h"
+#include "include/MPEG4Extractor.h"
+#include "include/WAVExtractor.h"
+
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MP3Extractor.h>
-#include <media/stagefright/MPEG4Extractor.h>
#include <utils/String8.h>
namespace android {
@@ -27,7 +29,7 @@ bool DataSource::getUInt16(off_t offset, uint16_t *x) {
*x = 0;
uint8_t byte[2];
- if (read_at(offset, byte, 2) != 2) {
+ if (readAt(offset, byte, 2) != 2) {
return false;
}
@@ -86,6 +88,7 @@ void DataSource::RegisterDefaultSniffers() {
RegisterSniffer(SniffMP3);
RegisterSniffer(SniffMPEG4);
RegisterSniffer(SniffAMR);
+ RegisterSniffer(SniffWAV);
}
} // namespace android
diff --git a/media/libstagefright/ESDS.cpp b/media/libstagefright/ESDS.cpp
index 53b92a0..28d338c 100644
--- a/media/libstagefright/ESDS.cpp
+++ b/media/libstagefright/ESDS.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/ESDS.h>
+#include "include/ESDS.h"
#include <string.h>
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index f6b90b2..f318ee3 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -30,11 +30,11 @@ FileSource::~FileSource() {
}
}
-status_t FileSource::InitCheck() const {
+status_t FileSource::initCheck() const {
return mFile != NULL ? OK : NO_INIT;
}
-ssize_t FileSource::read_at(off_t offset, void *data, size_t size) {
+ssize_t FileSource::readAt(off_t offset, void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
int err = fseeko(mFile, offset, SEEK_SET);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 4dedebd..5536801 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -14,17 +14,19 @@
* limitations under the License.
*/
+#include "include/stagefright_string.h"
+#include "include/HTTPStream.h"
+
#include <stdlib.h>
#include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/HTTPStream.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/stagefright_string.h>
namespace android {
HTTPDataSource::HTTPDataSource(const char *uri)
- : mHost(NULL),
+ : mHttp(new HTTPStream),
+ mHost(NULL),
mPort(0),
mPath(NULL),
mBuffer(malloc(kBufferSize)),
@@ -65,33 +67,40 @@ HTTPDataSource::HTTPDataSource(const char *uri)
mPort = port;
mPath = strdup(path.c_str());
- status_t err = mHttp.connect(mHost, mPort);
- CHECK_EQ(err, OK);
+ mInitCheck = mHttp->connect(mHost, mPort);
}
HTTPDataSource::HTTPDataSource(const char *host, int port, const char *path)
- : mHost(strdup(host)),
+ : mHttp(new HTTPStream),
+ mHost(strdup(host)),
mPort(port),
mPath(strdup(path)),
mBuffer(malloc(kBufferSize)),
mBufferLength(0),
mBufferOffset(0) {
- status_t err = mHttp.connect(mHost, mPort);
- CHECK_EQ(err, OK);
+ mInitCheck = mHttp->connect(mHost, mPort);
+}
+
+status_t HTTPDataSource::initCheck() const {
+ return mInitCheck;
}
HTTPDataSource::~HTTPDataSource() {
- mHttp.disconnect();
+ mHttp->disconnect();
free(mBuffer);
mBuffer = NULL;
free(mPath);
mPath = NULL;
+
+ delete mHttp;
+ mHttp = NULL;
}
-ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
- if (offset >= mBufferOffset && offset < mBufferOffset + mBufferLength) {
+ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
+ if (offset >= mBufferOffset
+ && offset < (off_t)(mBufferOffset + mBufferLength)) {
size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
size_t copy = num_bytes_available;
@@ -119,19 +128,19 @@ ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
status_t err;
int attempt = 1;
for (;;) {
- if ((err = mHttp.send("GET ")) != OK
- || (err = mHttp.send(mPath)) != OK
- || (err = mHttp.send(" HTTP/1.1\r\n")) != OK
- || (err = mHttp.send(host)) != OK
- || (err = mHttp.send(range)) != OK
- || (err = mHttp.send("\r\n")) != OK
- || (err = mHttp.receive_header(&http_status)) != OK) {
+ if ((err = mHttp->send("GET ")) != OK
+ || (err = mHttp->send(mPath)) != OK
+ || (err = mHttp->send(" HTTP/1.1\r\n")) != OK
+ || (err = mHttp->send(host)) != OK
+ || (err = mHttp->send(range)) != OK
+ || (err = mHttp->send("\r\n")) != OK
+ || (err = mHttp->receive_header(&http_status)) != OK) {
if (attempt == 3) {
return err;
}
- mHttp.connect(mHost, mPort);
+ mHttp->connect(mHost, mPort);
++attempt;
} else {
break;
@@ -143,14 +152,14 @@ ssize_t HTTPDataSource::read_at(off_t offset, void *data, size_t size) {
}
string value;
- if (!mHttp.find_header_value("Content-Length", &value)) {
+ if (!mHttp->find_header_value("Content-Length", &value)) {
return UNKNOWN_ERROR;
}
char *end;
unsigned long contentLength = strtoul(value.c_str(), &end, 10);
- ssize_t num_bytes_received = mHttp.receive(mBuffer, contentLength);
+ ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
if (num_bytes_received <= 0) {
return num_bytes_received;
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 6af7df9..02f9439 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "include/HTTPStream.h"
+
#include <sys/socket.h>
#include <arpa/inet.h>
@@ -25,7 +27,6 @@
#include <string.h>
#include <unistd.h>
-#include <media/stagefright/HTTPStream.h>
#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index d1dfd83..a4be2dd 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -119,7 +119,7 @@ status_t JPEGSource::read(
MediaBuffer *buffer;
mGroup->acquire_buffer(&buffer);
- ssize_t n = mSource->read_at(mOffset, buffer->data(), mSize - mOffset);
+ ssize_t n = mSource->readAt(mOffset, buffer->data(), mSize - mOffset);
if (n <= 0) {
buffer->release();
@@ -156,13 +156,13 @@ status_t JPEGSource::parseJPEG() {
for (;;) {
uint8_t marker;
- if (mSource->read_at(i++, &marker, 1) != 1) {
+ if (mSource->readAt(i++, &marker, 1) != 1) {
return ERROR_IO;
}
CHECK_EQ(marker, 0xff);
- if (mSource->read_at(i++, &marker, 1) != 1) {
+ if (mSource->readAt(i++, &marker, 1) != 1) {
return ERROR_IO;
}
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 7fd699f..8dd8ea9 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -18,8 +18,9 @@
#define LOG_TAG "MP3Extractor"
#include <utils/Log.h>
+#include "include/MP3Extractor.h"
+
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MP3Extractor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
@@ -147,7 +148,12 @@ static bool get_mp3_frame_size(
*out_bitrate = bitrate;
}
- *frame_size = 144000 * bitrate / sampling_rate + padding;
+ if (version == 3 /* V1 */) {
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ } else {
+ // V2 or V2.5
+ *frame_size = 72000 * bitrate / sampling_rate + padding;
+ }
}
if (out_sampling_rate) {
@@ -166,6 +172,33 @@ static bool get_mp3_frame_size(
static bool Resync(
const sp<DataSource> &source, uint32_t match_header,
off_t *inout_pos, uint32_t *out_header) {
+ if (*inout_pos == 0) {
+ // Skip an optional ID3 header if syncing at the very beginning
+ // of the datasource.
+
+ uint8_t id3header[10];
+ if (source->readAt(0, id3header, sizeof(id3header))
+ < (ssize_t)sizeof(id3header)) {
+ // If we can't even read these 10 bytes, we might as well bail out,
+ // even if there _were_ 10 bytes of valid mp3 audio data...
+ return false;
+ }
+
+ if (id3header[0] == 'I' && id3header[1] == 'D' && id3header[2] == '3') {
+ // Skip the ID3v2 header.
+
+ size_t len =
+ ((id3header[6] & 0x7f) << 21)
+ | ((id3header[7] & 0x7f) << 14)
+ | ((id3header[8] & 0x7f) << 7)
+ | (id3header[9] & 0x7f);
+
+ len += 10;
+
+ *inout_pos += len;
+ }
+ }
+
// Everything must match except for
// protection, bitrate, padding, private bits and mode extension.
const uint32_t kMask = 0xfffe0ccf;
@@ -195,7 +228,7 @@ static bool Resync(
buffer_length = buffer_length - buffer_offset;
buffer_offset = 0;
- ssize_t n = source->read_at(
+ ssize_t n = source->readAt(
pos, &buffer[buffer_length], kMaxFrameSize - buffer_length);
if (n <= 0) {
@@ -232,7 +265,7 @@ static bool Resync(
valid = true;
for (int j = 0; j < 3; ++j) {
uint8_t tmp[4];
- if (source->read_at(test_pos, tmp, 4) < 4) {
+ if (source->readAt(test_pos, tmp, 4) < 4) {
valid = false;
break;
}
@@ -338,10 +371,9 @@ MP3Extractor::MP3Extractor(const sp<DataSource> &source)
off_t fileSize;
if (mDataSource->getSize(&fileSize) == OK) {
- mMeta->setInt32(
+ mMeta->setInt64(
kKeyDuration,
- 8 * (fileSize - mFirstFramePos) / bitrate);
- mMeta->setInt32(kKeyTimeScale, 1000);
+ 8000LL * (fileSize - mFirstFramePos) / bitrate);
}
}
}
@@ -362,7 +394,7 @@ sp<MediaSource> MP3Extractor::getTrack(size_t index) {
mMeta, mDataSource, mFirstFramePos, mFixedHeader);
}
-sp<MetaData> MP3Extractor::getTrackMetaData(size_t index) {
+sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
if (mFirstFramePos < 0 || index != 0) {
return NULL;
}
@@ -448,7 +480,7 @@ status_t MP3Source::read(
size_t frame_size;
for (;;) {
- ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), 4);
+ ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), 4);
if (n < 4) {
buffer->release();
buffer = NULL;
@@ -482,7 +514,7 @@ status_t MP3Source::read(
CHECK(frame_size <= buffer->size());
- ssize_t n = mDataSource->read_at(mCurrentPos, buffer->data(), frame_size);
+ ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), frame_size);
if (n < (ssize_t)frame_size) {
buffer->release();
buffer = NULL;
@@ -492,8 +524,7 @@ status_t MP3Source::read(
buffer->set_range(0, frame_size);
- buffer->meta_data()->setInt32(kKeyTimeUnits, mCurrentTimeUs / 1000);
- buffer->meta_data()->setInt32(kKeyTimeScale, 1000);
+ buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
mCurrentPos += frame_size;
mCurrentTimeUs += 1152 * 1000000 / 44100;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 9174d19..9d17064 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -17,6 +17,9 @@
#define LOG_TAG "MPEG4Extractor"
#include <utils/Log.h>
+#include "include/MPEG4Extractor.h"
+#include "include/SampleTable.h"
+
#include <arpa/inet.h>
#include <ctype.h>
@@ -25,14 +28,12 @@
#include <string.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MPEG4Extractor.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
-#include <media/stagefright/SampleTable.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
@@ -43,6 +44,7 @@ public:
// Caller retains ownership of both "dataSource" and "sampleTable".
MPEG4Source(const sp<MetaData> &format,
const sp<DataSource> &dataSource,
+ int32_t timeScale,
const sp<SampleTable> &sampleTable);
virtual status_t start(MetaData *params = NULL);
@@ -177,7 +179,8 @@ size_t MPEG4Extractor::countTracks() {
return n;
}
-sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
+sp<MetaData> MPEG4Extractor::getTrackMetaData(
+ size_t index, uint32_t flags) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
@@ -197,6 +200,25 @@ sp<MetaData> MPEG4Extractor::getTrackMetaData(size_t index) {
return NULL;
}
+ if ((flags & kIncludeExtensiveMetaData)
+ && !track->includes_expensive_metadata) {
+ track->includes_expensive_metadata = true;
+
+ const char *mime;
+ CHECK(track->meta->findCString(kKeyMIMEType, &mime));
+ if (!strncasecmp("video/", mime, 6)) {
+ uint32_t sampleIndex;
+ uint32_t sampleTime;
+ if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
+ && track->sampleTable->getDecodingTime(
+ sampleIndex, &sampleTime) == OK) {
+ track->meta->setInt64(
+ kKeyThumbnailTime,
+ ((int64_t)sampleTime * 1000000) / track->timescale);
+ }
+ }
+ }
+
return track->meta;
}
@@ -227,7 +249,7 @@ static void MakeFourCCString(uint32_t x, char *s) {
status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
uint32_t hdr[2];
- if (mDataSource->read_at(*offset, hdr, 8) < 8) {
+ if (mDataSource->readAt(*offset, hdr, 8) < 8) {
return ERROR_IO;
}
uint64_t chunk_size = ntohl(hdr[0]);
@@ -235,7 +257,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
off_t data_offset = *offset + 8;
if (chunk_size == 1) {
- if (mDataSource->read_at(*offset + 8, &chunk_size, 8) < 8) {
+ if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
return ERROR_IO;
}
chunk_size = ntoh64(chunk_size);
@@ -252,7 +274,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
char buffer[256];
if (chunk_size <= sizeof(buffer)) {
- if (mDataSource->read_at(*offset, buffer, chunk_size) < chunk_size) {
+ if (mDataSource->readAt(*offset, buffer, chunk_size) < chunk_size) {
return ERROR_IO;
}
@@ -298,7 +320,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
CHECK(chunk_data_size >= 4);
uint8_t version;
- if (mDataSource->read_at(data_offset, &version, 1) < 1) {
+ if (mDataSource->readAt(data_offset, &version, 1) < 1) {
return ERROR_IO;
}
@@ -312,7 +334,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
uint8_t buffer[36 + 60];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -329,7 +351,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
uint8_t buffer[24 + 60];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -351,6 +373,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
mLastTrack = track;
track->meta = new MetaData;
+ track->includes_expensive_metadata = false;
track->timescale = 0;
track->sampleTable = new SampleTable(mDataSource);
track->meta->setCString(kKeyMIMEType, "application/octet-stream");
@@ -366,7 +389,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
uint8_t version;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, &version, sizeof(version))
< (ssize_t)sizeof(version)) {
return ERROR_IO;
@@ -383,18 +406,17 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
uint32_t timescale;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
timescale_offset, &timescale, sizeof(timescale))
< (ssize_t)sizeof(timescale)) {
return ERROR_IO;
}
mLastTrack->timescale = ntohl(timescale);
- mLastTrack->meta->setInt32(kKeyTimeScale, mLastTrack->timescale);
int64_t duration;
if (version == 1) {
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
timescale_offset + 4, &duration, sizeof(duration))
< (ssize_t)sizeof(duration)) {
return ERROR_IO;
@@ -402,14 +424,15 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
duration = ntoh64(duration);
} else {
int32_t duration32;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
timescale_offset + 4, &duration32, sizeof(duration32))
< (ssize_t)sizeof(duration32)) {
return ERROR_IO;
}
duration = ntohl(duration32);
}
- mLastTrack->meta->setInt32(kKeyDuration, duration);
+ mLastTrack->meta->setInt64(
+ kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
*offset += chunk_size;
break;
@@ -422,7 +445,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
uint8_t buffer[24];
- if (mDataSource->read_at(data_offset, buffer, 24) < 24) {
+ if (mDataSource->readAt(data_offset, buffer, 24) < 24) {
return ERROR_IO;
}
@@ -449,7 +472,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
uint8_t buffer[8];
CHECK(chunk_data_size >= (off_t)sizeof(buffer));
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, 8) < 8) {
return ERROR_IO;
}
@@ -492,7 +515,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return ERROR_MALFORMED;
}
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -544,7 +567,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return ERROR_MALFORMED;
}
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -655,7 +678,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return ERROR_BUFFER_TOO_SMALL;
}
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
@@ -679,7 +702,7 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return ERROR_BUFFER_TOO_SMALL;
}
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, buffer, chunk_data_size) < chunk_data_size) {
return ERROR_IO;
}
@@ -722,7 +745,7 @@ sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
}
return new MPEG4Source(
- track->meta, mDataSource, track->sampleTable);
+ track->meta, mDataSource, track->timescale, track->sampleTable);
}
////////////////////////////////////////////////////////////////////////////////
@@ -730,10 +753,11 @@ sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
MPEG4Source::MPEG4Source(
const sp<MetaData> &format,
const sp<DataSource> &dataSource,
+ int32_t timeScale,
const sp<SampleTable> &sampleTable)
: mFormat(format),
mDataSource(dataSource),
- mTimescale(0),
+ mTimescale(timeScale),
mSampleTable(sampleTable),
mCurrentSampleIndex(0),
mIsAVC(false),
@@ -746,9 +770,6 @@ MPEG4Source::MPEG4Source(
bool success = mFormat->findCString(kKeyMIMEType, &mime);
CHECK(success);
- success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
- CHECK(success);
-
mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
}
@@ -868,7 +889,7 @@ status_t MPEG4Source::read(
if (!mIsAVC || mWantsNALFragments) {
if (newBuffer) {
ssize_t num_bytes_read =
- mDataSource->read_at(offset, (uint8_t *)mBuffer->data(), size);
+ mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
@@ -879,8 +900,8 @@ status_t MPEG4Source::read(
mBuffer->set_range(0, size);
mBuffer->meta_data()->clear();
- mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
- mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ mBuffer->meta_data()->setInt64(
+ kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
++mCurrentSampleIndex;
}
@@ -923,7 +944,7 @@ status_t MPEG4Source::read(
// the start code (0x00 00 00 01).
ssize_t num_bytes_read =
- mDataSource->read_at(offset, mSrcBuffer, size);
+ mDataSource->readAt(offset, mSrcBuffer, size);
if (num_bytes_read < (ssize_t)size) {
mBuffer->release();
@@ -959,8 +980,8 @@ status_t MPEG4Source::read(
mBuffer->set_range(0, dstOffset);
mBuffer->meta_data()->clear();
- mBuffer->meta_data()->setInt32(kKeyTimeUnits, dts);
- mBuffer->meta_data()->setInt32(kKeyTimeScale, mTimescale);
+ mBuffer->meta_data()->setInt64(
+ kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
++mCurrentSampleIndex;
*out = mBuffer;
@@ -974,13 +995,14 @@ bool SniffMPEG4(
const sp<DataSource> &source, String8 *mimeType, float *confidence) {
uint8_t header[8];
- ssize_t n = source->read_at(4, header, sizeof(header));
+ ssize_t n = source->readAt(4, header, sizeof(header));
if (n < (ssize_t)sizeof(header)) {
return false;
}
if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
- || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)) {
+ || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
+ || !memcmp(header, "ftypM4A ", 8)) {
*mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
*confidence = 0.1;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index fa35768..9a7a873 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -399,15 +399,11 @@ void MPEG4Writer::Track::threadEntry() {
info.size = buffer->range_length();
info.offset = offset;
- int32_t units, scale;
- bool success =
- buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
- CHECK(success);
- success =
- buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
- CHECK(success);
-
- info.timestamp = (int64_t)units * 1000 / scale;
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
+
+ // Our timestamp is in ms.
+ info.timestamp = (timestampUs + 500) / 1000;
mSampleInfos.push_back(info);
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index f3c0e73..b973745 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -108,10 +108,10 @@ size_t MediaBuffer::range_length() const {
}
void MediaBuffer::set_range(size_t offset, size_t length) {
- if (offset < 0 || offset + length > mSize) {
+ if (offset + length > mSize) {
LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
}
- CHECK(offset >= 0 && offset + length <= mSize);
+ CHECK(offset + length <= mSize);
mRangeOffset = offset;
mRangeLength = length;
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 87b5b24..04b1454 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -32,5 +32,6 @@ const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
+const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav";
} // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 8535f52..19a1f85 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -18,12 +18,17 @@
#define LOG_TAG "MediaExtractor"
#include <utils/Log.h>
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+#include "include/MP3Extractor.h"
+#include "include/MPEG4Extractor.h"
+#include "include/WAVExtractor.h"
+
+#include <media/stagefright/CachingDataSource.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/HTTPDataSource.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MP3Extractor.h>
-#include <media/stagefright/MPEG4Extractor.h>
#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MmapSource.h>
#include <utils/String8.h>
namespace android {
@@ -41,7 +46,7 @@ sp<MediaExtractor> MediaExtractor::Create(
}
mime = tmp.string();
- LOGI("Autodetected media content as '%s' with confidence %.2f",
+ LOGV("Autodetected media content as '%s' with confidence %.2f",
mime, confidence);
}
@@ -53,9 +58,32 @@ sp<MediaExtractor> MediaExtractor::Create(
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
return new AMRExtractor(source);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
+ return new WAVExtractor(source);
}
return NULL;
}
+// static
+sp<MediaExtractor> MediaExtractor::CreateFromURI(
+ const char *uri, const char *mime) {
+ sp<DataSource> source;
+ if (!strncasecmp("file://", uri, 7)) {
+ source = new MmapSource(uri + 7);
+ } else if (!strncasecmp("http://", uri, 7)) {
+ source = new HTTPDataSource(uri);
+ source = new CachingDataSource(source, 64 * 1024, 10);
+ } else {
+ // Assume it's a filename.
+ source = new MmapSource(uri);
+ }
+
+ if (source == NULL || source->initCheck() != OK) {
+ return NULL;
+ }
+
+ return Create(source, mime);
+}
+
} // namespace android
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 622ea7e..c1044a3 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -18,16 +18,17 @@
#define LOG_TAG "MediaPlayerImpl"
#include "utils/Log.h"
+#include "include/stagefright_string.h"
+#include "include/HTTPStream.h"
+
#include <OMX_Component.h>
#include <unistd.h>
#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/CachingDataSource.h>
// #include <media/stagefright/CameraSource.h>
-#include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/HTTPStream.h>
#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MediaPlayerImpl.h>
#include <media/stagefright/MetaData.h>
@@ -51,7 +52,7 @@ MediaPlayerImpl::MediaPlayerImpl(const char *uri)
mPlaying(false),
mPaused(false),
mSeeking(false) {
- LOGI("MediaPlayerImpl(%s)", uri);
+ LOGV("MediaPlayerImpl(%s)", uri);
DataSource::RegisterDefaultSniffers();
status_t err = mClient.connect();
@@ -69,18 +70,7 @@ MediaPlayerImpl::MediaPlayerImpl(const char *uri)
mVideoDecoder = CameraSource::Create();
#endif
} else {
- sp<DataSource> source;
- if (!strncasecmp("file://", uri, 7)) {
- source = new MmapSource(uri + 7);
- } else if (!strncasecmp("http://", uri, 7)) {
- source = new HTTPDataSource(uri);
- source = new CachingDataSource(source, 64 * 1024, 10);
- } else {
- // Assume it's a filename.
- source = new MmapSource(uri);
- }
-
- mExtractor = MediaExtractor::Create(source);
+ mExtractor = MediaExtractor::CreateFromURI(uri);
if (mExtractor == NULL) {
return;
@@ -103,7 +93,7 @@ MediaPlayerImpl::MediaPlayerImpl(int fd, int64_t offset, int64_t length)
mPlaying(false),
mPaused(false),
mSeeking(false) {
- LOGI("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
+ LOGV("MediaPlayerImpl(%d, %lld, %lld)", fd, offset, length);
DataSource::RegisterDefaultSniffers();
status_t err = mClient.connect();
@@ -140,7 +130,7 @@ MediaPlayerImpl::~MediaPlayerImpl() {
}
void MediaPlayerImpl::play() {
- LOGI("play");
+ LOGV("play");
if (mPlaying) {
if (mPaused) {
@@ -241,7 +231,7 @@ void MediaPlayerImpl::videoEntry() {
{
Mutex::Autolock autoLock(mLock);
if (mSeeking) {
- LOGI("seek-options to %lld", mSeekTimeUs);
+ LOGV("seek-options to %lld", mSeekTimeUs);
options.setSeekTo(mSeekTimeUs);
mSeeking = false;
@@ -258,6 +248,13 @@ void MediaPlayerImpl::videoEntry() {
status_t err = mVideoDecoder->read(&buffer, &options);
CHECK((err == OK && buffer != NULL) || (err != OK && buffer == NULL));
+ if (err == INFO_FORMAT_CHANGED) {
+ LOGV("format changed.");
+ depopulateISurface();
+ populateISurface();
+ continue;
+ }
+
if (err == ERROR_END_OF_STREAM || err != OK) {
eof = true;
continue;
@@ -269,15 +266,9 @@ void MediaPlayerImpl::videoEntry() {
continue;
}
- int32_t units, scale;
- bool success =
- buffer->meta_data()->findInt32(kKeyTimeUnits, &units);
- CHECK(success);
- success =
- buffer->meta_data()->findInt32(kKeyTimeScale, &scale);
- CHECK(success);
+ int64_t pts_us;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &pts_us));
- int64_t pts_us = (int64_t)units * 1000000 / scale;
{
Mutex::Autolock autoLock(mLock);
mVideoPosition = pts_us;
@@ -332,14 +323,14 @@ void MediaPlayerImpl::displayOrDiscardFrame(
if (delay_us < -15000) {
// We're late.
- LOGI("we're late by %lld ms, dropping a frame\n",
+ LOGV("we're late by %lld ms, dropping a frame\n",
-delay_us / 1000);
buffer->release();
buffer = NULL;
return;
} else if (delay_us > 100000) {
- LOGI("we're much too early (by %lld ms)\n",
+ LOGV("we're much too early (by %lld ms)\n",
delay_us / 1000);
usleep(100000);
continue;
@@ -391,12 +382,10 @@ void MediaPlayerImpl::init() {
sp<MediaSource> source = mExtractor->getTrack(i);
- int32_t units, scale;
- if (meta->findInt32(kKeyDuration, &units)
- && meta->findInt32(kKeyTimeScale, &scale)) {
- int64_t duration_us = (int64_t)units * 1000000 / scale;
- if (duration_us > mDuration) {
- mDuration = duration_us;
+ int64_t durationUs;
+ if (meta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > mDuration) {
+ mDuration = durationUs;
}
}
@@ -410,17 +399,24 @@ void MediaPlayerImpl::init() {
}
void MediaPlayerImpl::setAudioSource(const sp<MediaSource> &source) {
- LOGI("setAudioSource");
+ LOGV("setAudioSource");
mAudioSource = source;
sp<MetaData> meta = source->getFormat();
- mAudioDecoder = OMXCodec::Create(
- mClient.interface(), meta, false /* createEncoder */, source);
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
+ mAudioDecoder = source;
+ } else {
+ mAudioDecoder = OMXCodec::Create(
+ mClient.interface(), meta, false /* createEncoder */, source);
+ }
}
void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
- LOGI("setVideoSource");
+ LOGV("setVideoSource");
mVideoSource = source;
sp<MetaData> meta = source->getFormat();
@@ -441,7 +437,7 @@ void MediaPlayerImpl::setVideoSource(const sp<MediaSource> &source) {
}
void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
- LOGI("setSurface %p", surface.get());
+ LOGV("setSurface %p", surface.get());
Mutex::Autolock autoLock(mLock);
depopulateISurface();
@@ -455,7 +451,7 @@ void MediaPlayerImpl::setSurface(const sp<Surface> &surface) {
}
void MediaPlayerImpl::setISurface(const sp<ISurface> &isurface) {
- LOGI("setISurface %p", isurface.get());
+ LOGV("setISurface %p", isurface.get());
Mutex::Autolock autoLock(mLock);
depopulateISurface();
@@ -499,7 +495,7 @@ MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) {
host = string(host, 0, colon - host.c_str());
}
- LOGI("Connecting to host '%s', port %d, path '%s'",
+ LOGV("Connecting to host '%s', port %d, path '%s'",
host.c_str(), port, path.c_str());
HTTPStream *http = new HTTPStream;
@@ -533,7 +529,7 @@ MediaSource *MediaPlayerImpl::makeShoutcastSource(const char *uri) {
http->disconnect();
- LOGI("Redirecting to %s\n", location.c_str());
+ LOGV("Redirecting to %s\n", location.c_str());
host = string(location, 0, slashPos);
@@ -588,7 +584,7 @@ int64_t MediaPlayerImpl::getPosition() {
}
status_t MediaPlayerImpl::seekTo(int64_t time) {
- LOGI("seekTo %lld", time);
+ LOGV("seekTo %lld", time);
if (mPaused) {
return UNKNOWN_ERROR;
@@ -621,6 +617,9 @@ void MediaPlayerImpl::populateISurface() {
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
CHECK(success);
+ LOGV("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d",
+ mVideoWidth, mVideoHeight, decodedWidth, decodedHeight);
+
if (mSurface.get() != NULL) {
mVideoRenderer =
mClient.interface()->createRenderer(
@@ -651,7 +650,7 @@ void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
void MediaPlayerImpl::setAudioSink(
const sp<MediaPlayerBase::AudioSink> &audioSink) {
- LOGI("setAudioSink %p", audioSink.get());
+ LOGV("setAudioSink %p", audioSink.get());
mAudioSink = audioSink;
}
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 6b067cb..63b476e 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -58,6 +58,10 @@ bool MetaData::setInt32(uint32_t key, int32_t value) {
return setData(key, TYPE_INT32, &value, sizeof(value));
}
+bool MetaData::setInt64(uint32_t key, int64_t value) {
+ return setData(key, TYPE_INT64, &value, sizeof(value));
+}
+
bool MetaData::setFloat(uint32_t key, float value) {
return setData(key, TYPE_FLOAT, &value, sizeof(value));
}
@@ -94,6 +98,21 @@ bool MetaData::findInt32(uint32_t key, int32_t *value) {
return true;
}
+bool MetaData::findInt64(uint32_t key, int64_t *value) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
+ return false;
+ }
+
+ CHECK_EQ(size, sizeof(*value));
+
+ *value = *(int64_t *)data;
+
+ return true;
+}
+
bool MetaData::findFloat(uint32_t key, float *value) {
uint32_t type;
const void *data;
diff --git a/media/libstagefright/MmapSource.cpp b/media/libstagefright/MmapSource.cpp
index 47d95f9..42749cf 100644
--- a/media/libstagefright/MmapSource.cpp
+++ b/media/libstagefright/MmapSource.cpp
@@ -34,7 +34,10 @@ MmapSource::MmapSource(const char *filename)
mBase(NULL),
mSize(0) {
LOGV("MmapSource '%s'", filename);
- CHECK(mFd >= 0);
+
+ if (mFd < 0) {
+ return;
+ }
off_t size = lseek(mFd, 0, SEEK_END);
mSize = (size_t)size;
@@ -78,12 +81,12 @@ MmapSource::~MmapSource() {
}
}
-status_t MmapSource::InitCheck() const {
+status_t MmapSource::initCheck() const {
return mFd == -1 ? NO_INIT : OK;
}
-ssize_t MmapSource::read_at(off_t offset, void *data, size_t size) {
- LOGV("read_at offset:%ld data:%p size:%d", offset, data, size);
+ssize_t MmapSource::readAt(off_t offset, void *data, size_t size) {
+ LOGV("readAt offset:%ld data:%p size:%d", offset, data, size);
CHECK(offset >= 0);
size_t avail = 0;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index ebf1e0c..6c0367a 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,11 +18,12 @@
#define LOG_TAG "OMXCodec"
#include <utils/Log.h>
+#include "include/ESDS.h"
+
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
-#include <media/stagefright/ESDS.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
@@ -39,6 +40,8 @@
namespace android {
+static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
struct CodecInfo {
const char *mime;
const char *codec;
@@ -169,52 +172,37 @@ static void InitOMXParams(T *params) {
params->nVersion.s.nStep = 0;
}
-// static
-sp<OMXCodec> OMXCodec::Create(
- const sp<IOMX> &omx,
- const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
- const char *matchComponentName) {
- const char *mime;
- bool success = meta->findCString(kKeyMIMEType, &mime);
- CHECK(success);
-
- const char *componentName = NULL;
- sp<OMXCodecObserver> observer = new OMXCodecObserver;
- IOMX::node_id node = 0;
- for (int index = 0;; ++index) {
- if (createEncoder) {
- componentName = GetCodec(
- kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
- mime, index);
- } else {
- componentName = GetCodec(
- kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
- mime, index);
- }
+static bool IsSoftwareCodec(const char *componentName) {
+ if (!strncmp("OMX.PV.", componentName, 7)) {
+ return true;
+ }
- if (!componentName) {
- return NULL;
- }
+ return false;
+}
- // If a specific codec is requested, skip the non-matching ones.
- if (matchComponentName && strcmp(componentName, matchComponentName)) {
- continue;
- }
+static int CompareSoftwareCodecsFirst(
+ const String8 *elem1, const String8 *elem2) {
+ bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string());
+ bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string());
- LOGV("Attempting to allocate OMX node '%s'", componentName);
+ if (isSoftwareCodec1) {
+ if (isSoftwareCodec2) { return 0; }
+ return -1;
+ }
- status_t err = omx->allocateNode(componentName, observer, &node);
- if (err == OK) {
- LOGI("Successfully allocated OMX node '%s'", componentName);
- break;
- }
+ if (isSoftwareCodec2) {
+ return 1;
}
+ return 0;
+}
+
+// static
+uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
uint32_t quirks = 0;
+
if (!strcmp(componentName, "OMX.PV.avcdec")) {
quirks |= kWantsNALFragments;
- quirks |= kOutputDimensionsAre16Aligned;
}
if (!strcmp(componentName, "OMX.TI.MP3.decode")) {
quirks |= kNeedsFlushBeforeDisable;
@@ -222,20 +210,15 @@ sp<OMXCodec> OMXCodec::Create(
if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
quirks |= kNeedsFlushBeforeDisable;
quirks |= kRequiresFlushCompleteEmulation;
-
- // The following is currently necessary for proper shutdown
- // behaviour, but NOT enabled by default in order to make the
- // bug reproducible...
- // quirks |= kRequiresFlushBeforeShutdown;
}
if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
quirks |= kRequiresLoadedToIdleAfterAllocation;
quirks |= kRequiresAllocateBufferOnInputPorts;
+ quirks |= kRequiresAllocateBufferOnOutputPorts;
}
if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
// XXX Required on P....on only.
quirks |= kRequiresAllocateBufferOnOutputPorts;
- quirks |= kOutputDimensionsAre16Aligned;
}
if (!strncmp(componentName, "OMX.TI.", 7)) {
@@ -248,8 +231,94 @@ sp<OMXCodec> OMXCodec::Create(
quirks |= kRequiresAllocateBufferOnOutputPorts;
}
+ return quirks;
+}
+
+// static
+void OMXCodec::findMatchingCodecs(
+ const char *mime,
+ bool createEncoder, const char *matchComponentName,
+ uint32_t flags,
+ Vector<String8> *matchingCodecs) {
+ matchingCodecs->clear();
+
+ for (int index = 0;; ++index) {
+ const char *componentName;
+
+ if (createEncoder) {
+ componentName = GetCodec(
+ kEncoderInfo,
+ sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+ mime, index);
+ } else {
+ componentName = GetCodec(
+ kDecoderInfo,
+ sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+ mime, index);
+ }
+
+ if (!componentName) {
+ break;
+ }
+
+ // If a specific codec is requested, skip the non-matching ones.
+ if (matchComponentName && strcmp(componentName, matchComponentName)) {
+ continue;
+ }
+
+ matchingCodecs->push(String8(componentName));
+ }
+
+ if (flags & kPreferSoftwareCodecs) {
+ matchingCodecs->sort(CompareSoftwareCodecsFirst);
+ }
+}
+
+// static
+sp<OMXCodec> OMXCodec::Create(
+ const sp<IOMX> &omx,
+ const sp<MetaData> &meta, bool createEncoder,
+ const sp<MediaSource> &source,
+ const char *matchComponentName,
+ uint32_t flags) {
+ const char *mime;
+ bool success = meta->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+
+ Vector<String8> matchingCodecs;
+ findMatchingCodecs(
+ mime, createEncoder, matchComponentName, flags, &matchingCodecs);
+
+ if (matchingCodecs.isEmpty()) {
+ return NULL;
+ }
+
+ sp<OMXCodecObserver> observer = new OMXCodecObserver;
+ IOMX::node_id node = 0;
+ success = false;
+
+ const char *componentName;
+ for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+ componentName = matchingCodecs[i].string();
+
+ LOGV("Attempting to allocate OMX node '%s'", componentName);
+
+ status_t err = omx->allocateNode(componentName, observer, &node);
+ if (err == OK) {
+ LOGV("Successfully allocated OMX node '%s'", componentName);
+
+ success = true;
+ break;
+ }
+ }
+
+ if (!success) {
+ return NULL;
+ }
+
sp<OMXCodec> codec = new OMXCodec(
- omx, node, quirks, createEncoder, mime, componentName,
+ omx, node, getComponentQuirks(componentName),
+ createEncoder, mime, componentName,
source);
observer->setCodec(codec);
@@ -331,7 +400,7 @@ sp<OMXCodec> OMXCodec::Create(
size -= length;
}
- LOGI("AVC profile = %d (%s), level = %d",
+ LOGV("AVC profile = %d (%s), level = %d",
(int)profile, AVCProfileToString(profile), (int)level / 10);
if (!strcmp(componentName, "OMX.TI.Video.Decoder")
@@ -452,7 +521,7 @@ status_t OMXCodec::setVideoPortFormatType(
// CHECK_EQ(format.nIndex, index);
#if 1
- CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+ CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
portIndex,
index, format.eCompressionFormat, format.eColorFormat);
#endif
@@ -493,9 +562,25 @@ status_t OMXCodec::setVideoPortFormatType(
return err;
}
+static size_t getFrameSize(
+ OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) {
+ switch (colorFormat) {
+ case OMX_COLOR_FormatYCbYCr:
+ case OMX_COLOR_FormatCbYCrY:
+ return width * height * 2;
+
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ return (width * height * 3) / 2;
+
+ default:
+ CHECK(!"Should not be here. Unsupported color format.");
+ break;
+ }
+}
+
void OMXCodec::setVideoInputFormat(
const char *mime, OMX_U32 width, OMX_U32 height) {
- CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+ CODEC_LOGV("setVideoInputFormat width=%ld, height=%ld", width, height);
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
@@ -516,12 +601,13 @@ void OMXCodec::setVideoInputFormat(
colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
}
- setVideoPortFormatType(
+ CHECK_EQ(setVideoPortFormatType(
kPortIndexInput, OMX_VIDEO_CodingUnused,
- colorFormat);
+ colorFormat), OK);
- setVideoPortFormatType(
- kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
+ CHECK_EQ(setVideoPortFormatType(
+ kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
+ OK);
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
@@ -554,8 +640,8 @@ void OMXCodec::setVideoInputFormat(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
- def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
- CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
+ def.nBufferSize = getFrameSize(colorFormat, width, height);
+ CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
@@ -564,14 +650,108 @@ void OMXCodec::setVideoInputFormat(
video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
video_def->eColorFormat = colorFormat;
+ video_def->xFramerate = 24 << 16; // XXX crucial!
+
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
+
+ switch (compressionFormat) {
+ case OMX_VIDEO_CodingMPEG4:
+ {
+ CHECK_EQ(setupMPEG4EncoderParameters(), OK);
+ break;
+ }
+
+ case OMX_VIDEO_CodingH263:
+ break;
+
+ default:
+ CHECK(!"Support for this compressionFormat to be implemented.");
+ break;
+ }
+}
+
+status_t OMXCodec::setupMPEG4EncoderParameters() {
+ OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type;
+ InitOMXParams(&mpeg4type);
+ mpeg4type.nPortIndex = kPortIndexOutput;
+
+ status_t err = mOMX->getParameter(
+ mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
+ CHECK_EQ(err, OK);
+
+ mpeg4type.nSliceHeaderSpacing = 0;
+ mpeg4type.bSVH = OMX_FALSE;
+ mpeg4type.bGov = OMX_FALSE;
+
+ mpeg4type.nAllowedPictureTypes =
+ OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+
+ mpeg4type.nPFrames = 23;
+ mpeg4type.nBFrames = 0;
+
+ mpeg4type.nIDCVLCThreshold = 0;
+ mpeg4type.bACPred = OMX_TRUE;
+ mpeg4type.nMaxPacketSize = 256;
+ mpeg4type.nTimeIncRes = 1000;
+ mpeg4type.nHeaderExtension = 0;
+ mpeg4type.bReversibleVLC = OMX_FALSE;
+
+ mpeg4type.eProfile = OMX_VIDEO_MPEG4ProfileCore;
+ mpeg4type.eLevel = OMX_VIDEO_MPEG4Level2;
+
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
+ CHECK_EQ(err, OK);
+
+ // ----------------
+
+ OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
+ InitOMXParams(&bitrateType);
+ bitrateType.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->getParameter(
+ mNode, OMX_IndexParamVideoBitrate,
+ &bitrateType, sizeof(bitrateType));
+ CHECK_EQ(err, OK);
+
+ bitrateType.eControlRate = OMX_Video_ControlRateVariable;
+ bitrateType.nTargetBitrate = 1000000;
+
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamVideoBitrate,
+ &bitrateType, sizeof(bitrateType));
+ CHECK_EQ(err, OK);
+
+ // ----------------
+
+ OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType;
+ InitOMXParams(&errorCorrectionType);
+ errorCorrectionType.nPortIndex = kPortIndexOutput;
+
+ err = mOMX->getParameter(
+ mNode, OMX_IndexParamVideoErrorCorrection,
+ &errorCorrectionType, sizeof(errorCorrectionType));
+ CHECK_EQ(err, OK);
+
+ errorCorrectionType.bEnableHEC = OMX_FALSE;
+ errorCorrectionType.bEnableResync = OMX_TRUE;
+ errorCorrectionType.nResynchMarkerSpacing = 256;
+ errorCorrectionType.bEnableDataPartitioning = OMX_FALSE;
+ errorCorrectionType.bEnableRVLC = OMX_FALSE;
+
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamVideoErrorCorrection,
+ &errorCorrectionType, sizeof(errorCorrectionType));
+ CHECK_EQ(err, OK);
+
+ return OK;
}
void OMXCodec::setVideoOutputFormat(
const char *mime, OMX_U32 width, OMX_U32 height) {
- CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+ CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height);
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
@@ -639,6 +819,7 @@ void OMXCodec::setVideoOutputFormat(
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
+ video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
err = mOMX->setParameter(
@@ -687,6 +868,7 @@ OMXCodec::OMXCodec(
mInitialBufferSubmit(true),
mSignalledEOS(false),
mNoMoreOutputData(false),
+ mOutputPortSettingsHaveChanged(false),
mSeekTimeUs(-1) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
@@ -990,12 +1172,8 @@ void OMXCodec::on_message(const omx_message &msg) {
buffer->meta_data()->clear();
- buffer->meta_data()->setInt32(
- kKeyTimeUnits,
- (msg.u.extended_buffer_data.timestamp + 500) / 1000);
-
- buffer->meta_data()->setInt32(
- kKeyTimeScale, 1000);
+ buffer->meta_data()->setInt64(
+ kKeyTime, msg.u.extended_buffer_data.timestamp);
if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) {
buffer->meta_data()->setInt32(kKeyIsSyncFrame, true);
@@ -1064,6 +1242,71 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
}
}
+// Has the format changed in any way that the client would have to be aware of?
+static bool formatHasNotablyChanged(
+ const sp<MetaData> &from, const sp<MetaData> &to) {
+ if (from.get() == NULL && to.get() == NULL) {
+ return false;
+ }
+
+ if ((from.get() == NULL && to.get() != NULL)
+ || (from.get() != NULL && to.get() == NULL)) {
+ return true;
+ }
+
+ const char *mime_from, *mime_to;
+ CHECK(from->findCString(kKeyMIMEType, &mime_from));
+ CHECK(to->findCString(kKeyMIMEType, &mime_to));
+
+ if (strcasecmp(mime_from, mime_to)) {
+ return true;
+ }
+
+ if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) {
+ int32_t colorFormat_from, colorFormat_to;
+ CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from));
+ CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to));
+
+ if (colorFormat_from != colorFormat_to) {
+ return true;
+ }
+
+ int32_t width_from, width_to;
+ CHECK(from->findInt32(kKeyWidth, &width_from));
+ CHECK(to->findInt32(kKeyWidth, &width_to));
+
+ if (width_from != width_to) {
+ return true;
+ }
+
+ int32_t height_from, height_to;
+ CHECK(from->findInt32(kKeyHeight, &height_from));
+ CHECK(to->findInt32(kKeyHeight, &height_to));
+
+ if (height_from != height_to) {
+ return true;
+ }
+ } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) {
+ int32_t numChannels_from, numChannels_to;
+ CHECK(from->findInt32(kKeyChannelCount, &numChannels_from));
+ CHECK(to->findInt32(kKeyChannelCount, &numChannels_to));
+
+ if (numChannels_from != numChannels_to) {
+ return true;
+ }
+
+ int32_t sampleRate_from, sampleRate_to;
+ CHECK(from->findInt32(kKeySampleRate, &sampleRate_from));
+ CHECK(to->findInt32(kKeySampleRate, &sampleRate_to));
+
+ if (sampleRate_from != sampleRate_to) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
switch (cmd) {
case OMX_CommandStateSet:
@@ -1086,6 +1329,15 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
if (mState == RECONFIGURING) {
CHECK_EQ(portIndex, kPortIndexOutput);
+ sp<MetaData> oldOutputFormat = mOutputFormat;
+ initOutputFormat(mSource->getFormat());
+
+ // Don't notify clients if the output port settings change
+ // wasn't of importance to them, i.e. it may be that just the
+ // number of buffers has changed and nothing else.
+ mOutputPortSettingsHaveChanged =
+ formatHasNotablyChanged(oldOutputFormat, mOutputFormat);
+
enablePortAsync(portIndex);
status_t err = allocateBuffersOnPort(portIndex);
@@ -1443,7 +1695,7 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
}
OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
- OMX_TICKS timestamp = 0;
+ OMX_TICKS timestampUs = 0;
size_t srcLength = 0;
if (err != OK) {
@@ -1463,15 +1715,11 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
(const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
srcLength);
- int32_t units, scale;
- if (srcBuffer->meta_data()->findInt32(kKeyTimeUnits, &units)
- && srcBuffer->meta_data()->findInt32(kKeyTimeScale, &scale)) {
- timestamp = ((OMX_TICKS)units * 1000000) / scale;
-
- CODEC_LOGV("Calling empty_buffer on buffer %p (length %d)",
+ if (srcBuffer->meta_data()->findInt64(kKeyTime, &timestampUs)) {
+ CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d)",
info->mBuffer, srcLength);
- CODEC_LOGV("Calling empty_buffer with timestamp %lld us (%.2f secs)",
- timestamp, timestamp / 1E6);
+ CODEC_LOGV("Calling emptyBuffer with timestamp %lld us (%.2f secs)",
+ timestampUs, timestampUs / 1E6);
}
}
@@ -1482,7 +1730,7 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, srcLength,
- flags, timestamp);
+ flags, timestampUs);
if (err != OK) {
setState(ERROR);
@@ -1794,6 +2042,7 @@ status_t OMXCodec::start(MetaData *) {
mInitialBufferSubmit = true;
mSignalledEOS = false;
mNoMoreOutputData = false;
+ mOutputPortSettingsHaveChanged = false;
mSeekTimeUs = -1;
mFilledBuffers.clear();
@@ -1864,6 +2113,8 @@ status_t OMXCodec::stop() {
}
sp<MetaData> OMXCodec::getFormat() {
+ Mutex::Autolock autoLock(mLock);
+
return mOutputFormat;
}
@@ -1941,6 +2192,12 @@ status_t OMXCodec::read(
return ERROR_END_OF_STREAM;
}
+ if (mOutputPortSettingsHaveChanged) {
+ mOutputPortSettingsHaveChanged = false;
+
+ return INFO_FORMAT_CHANGED;
+ }
+
size_t index = *mFilledBuffers.begin();
mFilledBuffers.erase(mFilledBuffers.begin());
@@ -2041,8 +2298,6 @@ static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
- static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
-
if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
} else if (type < 0 || (size_t)type >= numNames) {
@@ -2410,7 +2665,7 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
CHECK(!"Unknown compression format.");
}
- if (mQuirks & kOutputDimensionsAre16Aligned) {
+ if (!strcmp(mComponentName, "OMX.PV.avcdec")) {
// This component appears to be lying to me.
mOutputFormat->setInt32(
kKeyWidth, (video_def->nFrameWidth + 15) & -16);
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 8efa7c7..4aec0e9 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -17,11 +17,12 @@
#define LOG_TAG "SampleTable"
#include <utils/Log.h>
+#include "include/SampleTable.h"
+
#include <arpa/inet.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SampleTable.h>
#include <media/stagefright/Utils.h>
namespace android {
@@ -54,7 +55,7 @@ SampleTable::~SampleTable() {
}
status_t SampleTable::setChunkOffsetParams(
- uint32_t type, off_t data_offset, off_t data_size) {
+ uint32_t type, off_t data_offset, size_t data_size) {
if (mChunkOffsetOffset >= 0) {
return ERROR_MALFORMED;
}
@@ -69,7 +70,7 @@ status_t SampleTable::setChunkOffsetParams(
}
uint8_t header[8];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return ERROR_IO;
}
@@ -95,7 +96,7 @@ status_t SampleTable::setChunkOffsetParams(
}
status_t SampleTable::setSampleToChunkParams(
- off_t data_offset, off_t data_size) {
+ off_t data_offset, size_t data_size) {
if (mSampleToChunkOffset >= 0) {
return ERROR_MALFORMED;
}
@@ -107,7 +108,7 @@ status_t SampleTable::setSampleToChunkParams(
}
uint8_t header[8];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return ERROR_IO;
}
@@ -127,7 +128,7 @@ status_t SampleTable::setSampleToChunkParams(
}
status_t SampleTable::setSampleSizeParams(
- uint32_t type, off_t data_offset, off_t data_size) {
+ uint32_t type, off_t data_offset, size_t data_size) {
if (mSampleSizeOffset >= 0) {
return ERROR_MALFORMED;
}
@@ -141,7 +142,7 @@ status_t SampleTable::setSampleSizeParams(
}
uint8_t header[12];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return ERROR_IO;
}
@@ -187,13 +188,13 @@ status_t SampleTable::setSampleSizeParams(
}
status_t SampleTable::setTimeToSampleParams(
- off_t data_offset, off_t data_size) {
+ off_t data_offset, size_t data_size) {
if (mTimeToSample != NULL || data_size < 8) {
return ERROR_MALFORMED;
}
uint8_t header[8];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return ERROR_IO;
}
@@ -207,7 +208,7 @@ status_t SampleTable::setTimeToSampleParams(
mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
return ERROR_IO;
}
@@ -219,7 +220,7 @@ status_t SampleTable::setTimeToSampleParams(
return OK;
}
-status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
+status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) {
if (mSyncSampleOffset >= 0 || data_size < 8) {
return ERROR_MALFORMED;
}
@@ -227,7 +228,7 @@ status_t SampleTable::setSyncSampleParams(off_t data_offset, off_t data_size) {
mSyncSampleOffset = data_offset;
uint8_t header[8];
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return ERROR_IO;
}
@@ -263,7 +264,7 @@ status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
if (mChunkOffsetType == kChunkOffsetType32) {
uint32_t offset32;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mChunkOffsetOffset + 8 + 4 * chunk_index,
&offset32,
sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
@@ -275,7 +276,7 @@ status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
CHECK_EQ(mChunkOffsetType, kChunkOffsetType64);
uint64_t offset64;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mChunkOffsetOffset + 8 + 8 * chunk_index,
&offset64,
sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
@@ -312,7 +313,7 @@ status_t SampleTable::getChunkForSample(
uint32_t index = 0;
while (index < mNumSampleToChunkOffsets) {
uint8_t buffer[12];
- if (mDataSource->read_at(mSampleToChunkOffset + 8 + index * 12,
+ if (mDataSource->readAt(mSampleToChunkOffset + 8 + index * 12,
buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
@@ -361,7 +362,7 @@ status_t SampleTable::getSampleSize(
switch (mSampleSizeFieldSize) {
case 32:
{
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mSampleSizeOffset + 12 + 4 * sample_index,
sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
return ERROR_IO;
@@ -374,7 +375,7 @@ status_t SampleTable::getSampleSize(
case 16:
{
uint16_t x;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mSampleSizeOffset + 12 + 2 * sample_index,
&x, sizeof(x)) < (ssize_t)sizeof(x)) {
return ERROR_IO;
@@ -387,7 +388,7 @@ status_t SampleTable::getSampleSize(
case 8:
{
uint8_t x;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mSampleSizeOffset + 12 + sample_index,
&x, sizeof(x)) < (ssize_t)sizeof(x)) {
return ERROR_IO;
@@ -402,7 +403,7 @@ status_t SampleTable::getSampleSize(
CHECK_EQ(mSampleSizeFieldSize, 4);
uint8_t x;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mSampleSizeOffset + 12 + sample_index / 2,
&x, sizeof(x)) < (ssize_t)sizeof(x)) {
return ERROR_IO;
@@ -553,7 +554,7 @@ status_t SampleTable::findClosestSyncSample(
uint32_t right = mNumSyncSamples;
while (left < right) {
uint32_t mid = (left + right) / 2;
- if (mDataSource->read_at(
+ if (mDataSource->readAt(
mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) {
return ERROR_IO;
}
@@ -574,5 +575,52 @@ status_t SampleTable::findClosestSyncSample(
return OK;
}
+status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
+ if (mSyncSampleOffset < 0) {
+ // All samples are sync-samples.
+ *sample_index = 0;
+ return OK;
+ }
+
+ uint32_t bestSampleIndex = 0;
+ size_t maxSampleSize = 0;
+
+ static const size_t kMaxNumSyncSamplesToScan = 20;
+
+ // Consider the first kMaxNumSyncSamplesToScan sync samples and
+ // pick the one with the largest (compressed) size as the thumbnail.
+
+ size_t numSamplesToScan = mNumSyncSamples;
+ if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
+ numSamplesToScan = kMaxNumSyncSamplesToScan;
+ }
+
+ for (size_t i = 0; i < numSamplesToScan; ++i) {
+ uint32_t x;
+ if (mDataSource->readAt(
+ mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
+ return ERROR_IO;
+ }
+ x = ntohl(x);
+ --x;
+
+ // Now x is a sample index.
+ size_t sampleSize;
+ status_t err = getSampleSize(x, &sampleSize);
+ if (err != OK) {
+ return err;
+ }
+
+ if (i == 0 || sampleSize > maxSampleSize) {
+ bestSampleIndex = x;
+ maxSampleSize = sampleSize;
+ }
+ }
+
+ *sample_index = bestSampleIndex;
+
+ return OK;
+}
+
} // namespace android
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
index 346b5aa..ec25430 100644
--- a/media/libstagefright/ShoutcastSource.cpp
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -14,16 +14,17 @@
* limitations under the License.
*/
+#include "include/stagefright_string.h"
+#include "include/HTTPStream.h"
+
#include <stdlib.h>
-#include <media/stagefright/HTTPStream.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/ShoutcastSource.h>
-#include <media/stagefright/stagefright_string.h>
namespace android {
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 3d85f75..dd8005c 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -22,10 +22,11 @@
#define LOG_TAG "TimedEventQueue"
#include <utils/Log.h>
+#include "include/TimedEventQueue.h"
+
#include <sys/time.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/TimedEventQueue.h>
namespace android {
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
new file mode 100644
index 0000000..542c764
--- /dev/null
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -0,0 +1,317 @@
+/*
+ * 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 "WAVExtractor"
+#include <utils/Log.h>
+
+#include "include/WAVExtractor.h"
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+namespace android {
+
+static uint16_t WAVE_FORMAT_PCM = 1;
+
+static uint32_t U32_LE_AT(const uint8_t *ptr) {
+ return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0];
+}
+
+static uint16_t U16_LE_AT(const uint8_t *ptr) {
+ return ptr[1] << 8 | ptr[0];
+}
+
+struct WAVSource : public MediaSource {
+ WAVSource(
+ const sp<DataSource> &dataSource,
+ int32_t sampleRate, int32_t numChannels,
+ off_t offset, size_t size);
+
+ 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 ~WAVSource();
+
+private:
+ static const size_t kMaxFrameSize;
+
+ sp<DataSource> mDataSource;
+ int32_t mSampleRate;
+ int32_t mNumChannels;
+ off_t mOffset;
+ size_t mSize;
+ bool mStarted;
+ MediaBufferGroup *mGroup;
+ off_t mCurrentPos;
+
+ WAVSource(const WAVSource &);
+ WAVSource &operator=(const WAVSource &);
+};
+
+WAVExtractor::WAVExtractor(const sp<DataSource> &source)
+ : mDataSource(source),
+ mValidFormat(false) {
+ mInitCheck = init();
+}
+
+WAVExtractor::~WAVExtractor() {
+}
+
+size_t WAVExtractor::countTracks() {
+ return mInitCheck == OK ? 1 : 0;
+}
+
+sp<MediaSource> WAVExtractor::getTrack(size_t index) {
+ if (mInitCheck != OK || index > 0) {
+ return NULL;
+ }
+
+ return new WAVSource(
+ mDataSource, mSampleRate, mNumChannels, mDataOffset, mDataSize);
+}
+
+sp<MetaData> WAVExtractor::getTrackMetaData(
+ size_t index, uint32_t flags) {
+ if (mInitCheck != OK || index > 0) {
+ return NULL;
+ }
+
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ meta->setInt32(kKeyChannelCount, mNumChannels);
+ meta->setInt32(kKeySampleRate, mSampleRate);
+
+ int64_t durationUs =
+ 1000000LL * (mDataSize / (mNumChannels * 2)) / mSampleRate;
+
+ meta->setInt64(kKeyDuration, durationUs);
+
+ return meta;
+}
+
+status_t WAVExtractor::init() {
+ uint8_t header[12];
+ if (mDataSource->readAt(
+ 0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return NO_INIT;
+ }
+
+ if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
+ return NO_INIT;
+ }
+
+ size_t totalSize = U32_LE_AT(&header[4]);
+
+ off_t offset = 12;
+ size_t remainingSize = totalSize;
+ while (remainingSize >= 8) {
+ uint8_t chunkHeader[8];
+ if (mDataSource->readAt(offset, chunkHeader, 8) < 8) {
+ return NO_INIT;
+ }
+
+ remainingSize -= 8;
+ offset += 8;
+
+ uint32_t chunkSize = U32_LE_AT(&chunkHeader[4]);
+
+ if (chunkSize > remainingSize) {
+ return NO_INIT;
+ }
+
+ if (!memcmp(chunkHeader, "fmt ", 4)) {
+ if (chunkSize < 16) {
+ return NO_INIT;
+ }
+
+ uint8_t formatSpec[16];
+ if (mDataSource->readAt(offset, formatSpec, 16) < 16) {
+ return NO_INIT;
+ }
+
+ uint16_t format = U16_LE_AT(formatSpec);
+ if (format != WAVE_FORMAT_PCM) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ mNumChannels = U16_LE_AT(&formatSpec[2]);
+ if (mNumChannels != 1 && mNumChannels != 2) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ mSampleRate = U32_LE_AT(&formatSpec[4]);
+
+ if (U16_LE_AT(&formatSpec[14]) != 16) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ mValidFormat = true;
+ } else if (!memcmp(chunkHeader, "data", 4)) {
+ if (mValidFormat) {
+ mDataOffset = offset;
+ mDataSize = chunkSize;
+
+ return OK;
+ }
+ }
+
+ offset += chunkSize;
+ }
+
+ return NO_INIT;
+}
+
+const size_t WAVSource::kMaxFrameSize = 32768;
+
+WAVSource::WAVSource(
+ const sp<DataSource> &dataSource,
+ int32_t sampleRate, int32_t numChannels,
+ off_t offset, size_t size)
+ : mDataSource(dataSource),
+ mSampleRate(sampleRate),
+ mNumChannels(numChannels),
+ mOffset(offset),
+ mSize(size),
+ mStarted(false),
+ mGroup(NULL) {
+}
+
+WAVSource::~WAVSource() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t WAVSource::start(MetaData *params) {
+ LOGV("WAVSource::start");
+
+ CHECK(!mStarted);
+
+ mGroup = new MediaBufferGroup;
+ mGroup->add_buffer(new MediaBuffer(kMaxFrameSize));
+
+ mCurrentPos = mOffset;
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t WAVSource::stop() {
+ LOGV("WAVSource::stop");
+
+ CHECK(mStarted);
+
+ delete mGroup;
+ mGroup = NULL;
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> WAVSource::getFormat() {
+ LOGV("WAVSource::getFormat");
+
+ sp<MetaData> meta = new MetaData;
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ meta->setInt32(kKeyChannelCount, mNumChannels);
+ meta->setInt32(kKeySampleRate, mSampleRate);
+
+ int64_t durationUs =
+ 1000000LL * (mSize / (mNumChannels * 2)) / mSampleRate;
+
+ meta->setInt64(kKeyDuration, durationUs);
+
+ return meta;
+}
+
+status_t WAVSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ if (options != NULL && options->getSeekTo(&seekTimeUs)) {
+ int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2;
+ if (pos > mSize) {
+ pos = mSize;
+ }
+ mCurrentPos = pos + mOffset;
+ }
+
+ MediaBuffer *buffer;
+ status_t err = mGroup->acquire_buffer(&buffer);
+ if (err != OK) {
+ return err;
+ }
+
+ ssize_t n = mDataSource->readAt(
+ mCurrentPos, buffer->data(), kMaxFrameSize);
+
+ if (n <= 0) {
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_END_OF_STREAM;
+ }
+
+ mCurrentPos += n;
+
+ buffer->set_range(0, n);
+ buffer->meta_data()->setInt64(
+ kKeyTime,
+ 1000000LL * (mCurrentPos - mOffset)
+ / (mNumChannels * 2) / mSampleRate);
+
+
+ *out = buffer;
+
+ return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffWAV(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+ char header[12];
+ if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) {
+ return false;
+ }
+
+ if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) {
+ return false;
+ }
+
+ *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
+ *confidence = 0.3f;
+
+ return true;
+}
+
+} // namespace android
+
diff --git a/include/media/stagefright/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index c8710d3..debf006 100644
--- a/include/media/stagefright/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -30,7 +30,7 @@ public:
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
- virtual sp<MetaData> getTrackMetaData(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
static sp<MetaData> makeAMRFormat(bool isWide);
diff --git a/include/media/stagefright/ESDS.h b/media/libstagefright/include/ESDS.h
index 01bcd18..01bcd18 100644
--- a/include/media/stagefright/ESDS.h
+++ b/media/libstagefright/include/ESDS.h
diff --git a/include/media/stagefright/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
index 72e796c..43ef614 100644
--- a/include/media/stagefright/HTTPStream.h
+++ b/media/libstagefright/include/HTTPStream.h
@@ -18,10 +18,11 @@
#define HTTP_STREAM_H_
+#include "stagefright_string.h"
+
#include <sys/types.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/stagefright_string.h>
#include <utils/KeyedVector.h>
namespace android {
diff --git a/include/media/stagefright/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index 11ba01d..074973b 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -32,7 +32,7 @@ public:
virtual size_t countTracks();
virtual sp<MediaSource> getTrack(size_t index);
- virtual sp<MetaData> getTrackMetaData(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
protected:
virtual ~MP3Extractor();
diff --git a/include/media/stagefright/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 932e30f..ce4736d 100644
--- a/include/media/stagefright/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -33,7 +33,7 @@ public:
size_t countTracks();
sp<MediaSource> getTrack(size_t index);
- sp<MetaData> getTrackMetaData(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
protected:
virtual ~MPEG4Extractor();
@@ -44,6 +44,7 @@ private:
sp<MetaData> meta;
uint32_t timescale;
sp<SampleTable> sampleTable;
+ bool includes_expensive_metadata;
};
sp<DataSource> mDataSource;
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index d0bd61e..a4b62b2 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -99,7 +99,7 @@ public:
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData);
-
+
OMX_ERRORTYPE OnEmptyBufferDone(
node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
diff --git a/include/media/stagefright/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 808d142..ead3431 100644
--- a/include/media/stagefright/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -35,17 +35,17 @@ public:
// type can be 'stco' or 'co64'.
status_t setChunkOffsetParams(
- uint32_t type, off_t data_offset, off_t data_size);
+ uint32_t type, off_t data_offset, size_t data_size);
- status_t setSampleToChunkParams(off_t data_offset, off_t data_size);
+ status_t setSampleToChunkParams(off_t data_offset, size_t data_size);
// type can be 'stsz' or 'stz2'.
status_t setSampleSizeParams(
- uint32_t type, off_t data_offset, off_t data_size);
+ uint32_t type, off_t data_offset, size_t data_size);
- status_t setTimeToSampleParams(off_t data_offset, off_t data_size);
+ status_t setTimeToSampleParams(off_t data_offset, size_t data_size);
- status_t setSyncSampleParams(off_t data_offset, off_t data_size);
+ status_t setSyncSampleParams(off_t data_offset, size_t data_size);
////////////////////////////////////////////////////////////////////////////
@@ -75,6 +75,8 @@ public:
status_t findClosestSyncSample(
uint32_t start_sample_index, uint32_t *sample_index);
+ status_t findThumbnailSample(uint32_t *sample_index);
+
protected:
~SampleTable();
diff --git a/include/media/stagefright/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 1545493..9eed089 100644
--- a/include/media/stagefright/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -18,7 +18,7 @@
#define SOFTWARE_RENDERER_H_
-#include <OMX_Video.h>
+#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/VideoRenderer.h>
#include <utils/RefBase.h>
@@ -41,13 +41,8 @@ public:
const void *data, size_t size, void *platformPrivate);
private:
- uint8_t *initClip();
-
- void renderCbYCrY(const void *data, size_t size);
- void renderYUV420Planar(const void *data, size_t size);
- void renderQCOMYUV420SemiPlanar(const void *data, size_t size);
-
OMX_COLOR_FORMATTYPE mColorFormat;
+ ColorConverter mConverter;
sp<ISurface> mISurface;
size_t mDisplayWidth, mDisplayHeight;
size_t mDecodedWidth, mDecodedHeight;
@@ -55,8 +50,6 @@ private:
sp<MemoryHeapBase> mMemoryHeap;
int mIndex;
- uint8_t *mClip;
-
SoftwareRenderer(const SoftwareRenderer &);
SoftwareRenderer &operator=(const SoftwareRenderer &);
};
diff --git a/include/media/stagefright/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
index a264421..a264421 100644
--- a/include/media/stagefright/TimedEventQueue.h
+++ b/media/libstagefright/include/TimedEventQueue.h
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
new file mode 100644
index 0000000..10b9700
--- /dev/null
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -0,0 +1,61 @@
+/*
+ * 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 WAV_EXTRACTOR_H_
+
+#define WAV_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class String8;
+
+class WAVExtractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ WAVExtractor(const sp<DataSource> &source);
+
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+protected:
+ virtual ~WAVExtractor();
+
+private:
+ sp<DataSource> mDataSource;
+ status_t mInitCheck;
+ bool mValidFormat;
+ uint16_t mNumChannels;
+ uint32_t mSampleRate;
+ off_t mDataOffset;
+ size_t mDataSize;
+
+ status_t init();
+
+ WAVExtractor(const WAVExtractor &);
+ WAVExtractor &operator=(const WAVExtractor &);
+};
+
+bool SniffWAV(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // WAV_EXTRACTOR_H_
+
diff --git a/include/media/stagefright/stagefright_string.h b/media/libstagefright/include/stagefright_string.h
index 1ed4c86..5dc7116 100644
--- a/include/media/stagefright/stagefright_string.h
+++ b/media/libstagefright/include/stagefright_string.h
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#ifndef STAGEFRIGHT_STRING_H_
+#ifndef STRING_H_
-#define STAGEFRIGHT_STRING_H_
+#define STRING_H_
#include <utils/String8.h>
@@ -51,4 +51,4 @@ private:
} // namespace android
-#endif // STAGEFRIGHT_STRING_H_
+#endif // STRING_H_
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 25da813..389c2c9 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -9,6 +9,7 @@ LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
+ ColorConverter.cpp \
OMX.cpp \
OMXNodeInstance.cpp \
SoftwareRenderer.cpp
diff --git a/media/libstagefright/omx/ColorConverter.cpp b/media/libstagefright/omx/ColorConverter.cpp
new file mode 100644
index 0000000..e74782f
--- /dev/null
+++ b/media/libstagefright/omx/ColorConverter.cpp
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+ColorConverter::ColorConverter(
+ OMX_COLOR_FORMATTYPE from, OMX_COLOR_FORMATTYPE to)
+ : mSrcFormat(from),
+ mDstFormat(to),
+ mClip(NULL) {
+}
+
+ColorConverter::~ColorConverter() {
+ delete[] mClip;
+ mClip = NULL;
+}
+
+bool ColorConverter::isValid() const {
+ if (mDstFormat != OMX_COLOR_Format16bitRGB565) {
+ return false;
+ }
+
+ switch (mSrcFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ case OMX_COLOR_FormatCbYCrY:
+ case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+void ColorConverter::convert(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip) {
+ CHECK_EQ(mDstFormat, OMX_COLOR_Format16bitRGB565);
+
+ switch (mSrcFormat) {
+ case OMX_COLOR_FormatYUV420Planar:
+ convertYUV420Planar(
+ width, height, srcBits, srcSkip, dstBits, dstSkip);
+ break;
+
+ case OMX_COLOR_FormatCbYCrY:
+ convertCbYCrY(
+ width, height, srcBits, srcSkip, dstBits, dstSkip);
+ break;
+
+ case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+ convertQCOMYUV420SemiPlanar(
+ width, height, srcBits, srcSkip, dstBits, dstSkip);
+ break;
+
+ default:
+ {
+ CHECK(!"Should not be here. Unknown color conversion.");
+ break;
+ }
+ }
+}
+
+void ColorConverter::convertCbYCrY(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip) {
+ CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats.
+ CHECK(dstSkip >= width * 2);
+ CHECK((dstSkip & 3) == 0);
+
+ uint8_t *kAdjustedClip = initClip();
+
+ uint32_t *dst_ptr = (uint32_t *)dstBits;
+
+ const uint8_t *src = (const uint8_t *)srcBits;
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; x += 2) {
+ signed y1 = (signed)src[2 * x + 1] - 16;
+ signed y2 = (signed)src[2 * x + 3] - 16;
+ signed u = (signed)src[2 * x] - 128;
+ signed v = (signed)src[2 * x + 2] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = (tmp1 + u_b) / 256;
+ signed g1 = (tmp1 + v_g + u_g) / 256;
+ signed r1 = (tmp1 + v_r) / 256;
+
+ signed tmp2 = y2 * 298;
+ signed b2 = (tmp2 + u_b) / 256;
+ signed g2 = (tmp2 + v_g + u_g) / 256;
+ signed r2 = (tmp2 + v_r) / 256;
+
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
+
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
+
+ dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ }
+
+ src += width * 2;
+ dst_ptr += dstSkip / 4;
+ }
+}
+
+void ColorConverter::convertYUV420Planar(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip) {
+ CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats.
+ CHECK(dstSkip >= width * 2);
+ CHECK((dstSkip & 3) == 0);
+
+ uint8_t *kAdjustedClip = initClip();
+
+ uint32_t *dst_ptr = (uint32_t *)dstBits;
+ const uint8_t *src_y = (const uint8_t *)srcBits;
+
+ const uint8_t *src_u =
+ (const uint8_t *)src_y + width * height;
+
+ const uint8_t *src_v =
+ (const uint8_t *)src_u + (width / 2) * (height / 2);
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; x += 2) {
+ // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
+ // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
+ // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
+
+ // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
+ // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
+ // R = .................. + 409/256 * (V - 128)
+
+ // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
+ // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
+ // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
+
+ // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
+ // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
+ // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
+
+ // clip range -278 .. 535
+
+ signed y1 = (signed)src_y[x] - 16;
+ signed y2 = (signed)src_y[x + 1] - 16;
+
+ signed u = (signed)src_u[x / 2] - 128;
+ signed v = (signed)src_v[x / 2] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = (tmp1 + u_b) / 256;
+ signed g1 = (tmp1 + v_g + u_g) / 256;
+ signed r1 = (tmp1 + v_r) / 256;
+
+ signed tmp2 = y2 * 298;
+ signed b2 = (tmp2 + u_b) / 256;
+ signed g2 = (tmp2 + v_g + u_g) / 256;
+ signed r2 = (tmp2 + v_r) / 256;
+
+ uint32_t rgb1 =
+ ((kAdjustedClip[r1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[b1] >> 3);
+
+ uint32_t rgb2 =
+ ((kAdjustedClip[r2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[b2] >> 3);
+
+ dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ }
+
+ src_y += width;
+
+ if (y & 1) {
+ src_u += width / 2;
+ src_v += width / 2;
+ }
+
+ dst_ptr += dstSkip / 4;
+ }
+}
+
+void ColorConverter::convertQCOMYUV420SemiPlanar(
+ size_t width, size_t height,
+ const void *srcBits, size_t srcSkip,
+ void *dstBits, size_t dstSkip) {
+ CHECK_EQ(srcSkip, 0); // Doesn't really make sense for YUV formats.
+ CHECK(dstSkip >= width * 2);
+ CHECK((dstSkip & 3) == 0);
+
+ uint8_t *kAdjustedClip = initClip();
+
+ uint32_t *dst_ptr = (uint32_t *)dstBits;
+ const uint8_t *src_y = (const uint8_t *)srcBits;
+
+ const uint8_t *src_u =
+ (const uint8_t *)src_y + width * height;
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; x += 2) {
+ signed y1 = (signed)src_y[x] - 16;
+ signed y2 = (signed)src_y[x + 1] - 16;
+
+ signed u = (signed)src_u[x & ~1] - 128;
+ signed v = (signed)src_u[(x & ~1) + 1] - 128;
+
+ signed u_b = u * 517;
+ signed u_g = -u * 100;
+ signed v_g = -v * 208;
+ signed v_r = v * 409;
+
+ signed tmp1 = y1 * 298;
+ signed b1 = (tmp1 + u_b) / 256;
+ signed g1 = (tmp1 + v_g + u_g) / 256;
+ signed r1 = (tmp1 + v_r) / 256;
+
+ signed tmp2 = y2 * 298;
+ signed b2 = (tmp2 + u_b) / 256;
+ signed g2 = (tmp2 + v_g + u_g) / 256;
+ signed r2 = (tmp2 + v_r) / 256;
+
+ uint32_t rgb1 =
+ ((kAdjustedClip[b1] >> 3) << 11)
+ | ((kAdjustedClip[g1] >> 2) << 5)
+ | (kAdjustedClip[r1] >> 3);
+
+ uint32_t rgb2 =
+ ((kAdjustedClip[b2] >> 3) << 11)
+ | ((kAdjustedClip[g2] >> 2) << 5)
+ | (kAdjustedClip[r2] >> 3);
+
+ dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ }
+
+ src_y += width;
+
+ if (y & 1) {
+ src_u += width;
+ }
+
+ dst_ptr += dstSkip / 4;
+ }
+}
+
+uint8_t *ColorConverter::initClip() {
+ static const signed kClipMin = -278;
+ static const signed kClipMax = 535;
+
+ if (mClip == NULL) {
+ mClip = new uint8_t[kClipMax - kClipMin + 1];
+
+ for (signed i = kClipMin; i <= kClipMax; ++i) {
+ mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
+ }
+ }
+
+ return &mClip[-kClipMin];
+}
+
+} // namespace android
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 4ccd4bd..5b3cc1b 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -24,10 +24,10 @@
#include "pv_omxcore.h"
#include "../include/OMXNodeInstance.h"
+#include "../include/SoftwareRenderer.h"
#include <binder/IMemory.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SoftwareRenderer.h>
#include <media/stagefright/VideoRenderer.h>
#include <OMX_Component.h>
@@ -233,7 +233,7 @@ status_t OMX::allocateNode(
&OMXNodeInstance::kCallbacks);
if (err != OMX_ErrorNone) {
- LOGE("FAILED to allocate omx component '%s'", name);
+ LOGV("FAILED to allocate omx component '%s'", name);
instance->onGetHandleFailed();
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 39de504..ef6ede0 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -17,21 +17,21 @@
#define LOG_TAG "SoftwareRenderer"
#include <utils/Log.h>
+#include "../include/SoftwareRenderer.h"
+
#include <binder/MemoryHeapBase.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/SoftwareRenderer.h>
#include <ui/ISurface.h>
namespace android {
-#define QCOM_YUV 0
-
SoftwareRenderer::SoftwareRenderer(
OMX_COLOR_FORMATTYPE colorFormat,
const sp<ISurface> &surface,
size_t displayWidth, size_t displayHeight,
size_t decodedWidth, size_t decodedHeight)
: mColorFormat(colorFormat),
+ mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
mISurface(surface),
mDisplayWidth(displayWidth),
mDisplayHeight(displayHeight),
@@ -39,12 +39,12 @@ SoftwareRenderer::SoftwareRenderer(
mDecodedHeight(decodedHeight),
mFrameSize(mDecodedWidth * mDecodedHeight * 2), // RGB565
mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
- mIndex(0),
- mClip(NULL) {
+ mIndex(0) {
CHECK(mISurface.get() != NULL);
CHECK(mDecodedWidth > 0);
CHECK(mDecodedHeight > 0);
CHECK(mMemoryHeap->heapID() >= 0);
+ CHECK(mConverter.isValid());
ISurface::BufferHeap bufferHeap(
mDisplayWidth, mDisplayHeight,
@@ -58,278 +58,19 @@ SoftwareRenderer::SoftwareRenderer(
SoftwareRenderer::~SoftwareRenderer() {
mISurface->unregisterBuffers();
-
- delete[] mClip;
- mClip = NULL;
}
void SoftwareRenderer::render(
const void *data, size_t size, void *platformPrivate) {
- static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
-
- switch (mColorFormat) {
- case OMX_COLOR_FormatYUV420Planar:
- return renderYUV420Planar(data, size);
-
- case OMX_COLOR_FormatCbYCrY:
- return renderCbYCrY(data, size);
-
- case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
- return renderQCOMYUV420SemiPlanar(data, size);
-
- default:
- {
- LOGW("Cannot render color format %d", mColorFormat);
- break;
- }
- }
-}
-
-void SoftwareRenderer::renderYUV420Planar(
- const void *data, size_t size) {
- if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
- LOGE("size is %d, expected %d",
- size, (mDecodedHeight * mDecodedWidth * 3) / 2);
- }
- CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
-
- uint8_t *kAdjustedClip = initClip();
-
size_t offset = mIndex * mFrameSize;
-
void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
- uint32_t *dst_ptr = (uint32_t *)dst;
-
- const uint8_t *src_y = (const uint8_t *)data;
-
- const uint8_t *src_u =
- (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
-
-#if !QCOM_YUV
- const uint8_t *src_v =
- (const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2);
-#endif
-
- for (size_t y = 0; y < mDecodedHeight; ++y) {
- for (size_t x = 0; x < mDecodedWidth; x += 2) {
- // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
- // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
- // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
-
- // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
- // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
- // R = .................. + 409/256 * (V - 128)
-
- // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
- // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
- // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
-
- // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
- // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
- // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
-
- // clip range -278 .. 535
-
- signed y1 = (signed)src_y[x] - 16;
- signed y2 = (signed)src_y[x + 1] - 16;
-
-#if QCOM_YUV
- signed u = (signed)src_u[x & ~1] - 128;
- signed v = (signed)src_u[(x & ~1) + 1] - 128;
-#else
- signed u = (signed)src_u[x / 2] - 128;
- signed v = (signed)src_v[x / 2] - 128;
-#endif
-
- signed u_b = u * 517;
- signed u_g = -u * 100;
- signed v_g = -v * 208;
- signed v_r = v * 409;
-
- signed tmp1 = y1 * 298;
- signed b1 = (tmp1 + u_b) / 256;
- signed g1 = (tmp1 + v_g + u_g) / 256;
- signed r1 = (tmp1 + v_r) / 256;
-
- signed tmp2 = y2 * 298;
- signed b2 = (tmp2 + u_b) / 256;
- signed g2 = (tmp2 + v_g + u_g) / 256;
- signed r2 = (tmp2 + v_r) / 256;
-
- uint32_t rgb1 =
- ((kAdjustedClip[r1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[b1] >> 3);
-
- uint32_t rgb2 =
- ((kAdjustedClip[r2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[b2] >> 3);
-
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
- }
-
- src_y += mDecodedWidth;
-
- if (y & 1) {
-#if QCOM_YUV
- src_u += mDecodedWidth;
-#else
- src_u += mDecodedWidth / 2;
- src_v += mDecodedWidth / 2;
-#endif
- }
-
- dst_ptr += mDecodedWidth / 2;
- }
-
- mISurface->postBuffer(offset);
- mIndex = 1 - mIndex;
-}
-
-void SoftwareRenderer::renderCbYCrY(
- const void *data, size_t size) {
- if (size != (mDecodedHeight * mDecodedWidth * 2)) {
- LOGE("size is %d, expected %d",
- size, (mDecodedHeight * mDecodedWidth * 2));
- }
- CHECK(size >= (mDecodedWidth * mDecodedHeight * 2));
-
- uint8_t *kAdjustedClip = initClip();
-
- size_t offset = mIndex * mFrameSize;
- void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
- uint32_t *dst_ptr = (uint32_t *)dst;
-
- const uint8_t *src = (const uint8_t *)data;
-
- for (size_t y = 0; y < mDecodedHeight; ++y) {
- for (size_t x = 0; x < mDecodedWidth; x += 2) {
- signed y1 = (signed)src[2 * x + 1] - 16;
- signed y2 = (signed)src[2 * x + 3] - 16;
- signed u = (signed)src[2 * x] - 128;
- signed v = (signed)src[2 * x + 2] - 128;
-
- signed u_b = u * 517;
- signed u_g = -u * 100;
- signed v_g = -v * 208;
- signed v_r = v * 409;
-
- signed tmp1 = y1 * 298;
- signed b1 = (tmp1 + u_b) / 256;
- signed g1 = (tmp1 + v_g + u_g) / 256;
- signed r1 = (tmp1 + v_r) / 256;
-
- signed tmp2 = y2 * 298;
- signed b2 = (tmp2 + u_b) / 256;
- signed g2 = (tmp2 + v_g + u_g) / 256;
- signed r2 = (tmp2 + v_r) / 256;
-
- uint32_t rgb1 =
- ((kAdjustedClip[r1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[b1] >> 3);
-
- uint32_t rgb2 =
- ((kAdjustedClip[r2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[b2] >> 3);
-
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
- }
-
- src += mDecodedWidth * 2;
- dst_ptr += mDecodedWidth / 2;
- }
-
- mISurface->postBuffer(offset);
- mIndex = 1 - mIndex;
-}
-
-void SoftwareRenderer::renderQCOMYUV420SemiPlanar(
- const void *data, size_t size) {
- if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
- LOGE("size is %d, expected %d",
- size, (mDecodedHeight * mDecodedWidth * 3) / 2);
- }
- CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
-
- uint8_t *kAdjustedClip = initClip();
-
- size_t offset = mIndex * mFrameSize;
-
- void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
-
- uint32_t *dst_ptr = (uint32_t *)dst;
-
- const uint8_t *src_y = (const uint8_t *)data;
-
- const uint8_t *src_u =
- (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
-
- for (size_t y = 0; y < mDecodedHeight; ++y) {
- for (size_t x = 0; x < mDecodedWidth; x += 2) {
- signed y1 = (signed)src_y[x] - 16;
- signed y2 = (signed)src_y[x + 1] - 16;
-
- signed u = (signed)src_u[x & ~1] - 128;
- signed v = (signed)src_u[(x & ~1) + 1] - 128;
-
- signed u_b = u * 517;
- signed u_g = -u * 100;
- signed v_g = -v * 208;
- signed v_r = v * 409;
-
- signed tmp1 = y1 * 298;
- signed b1 = (tmp1 + u_b) / 256;
- signed g1 = (tmp1 + v_g + u_g) / 256;
- signed r1 = (tmp1 + v_r) / 256;
-
- signed tmp2 = y2 * 298;
- signed b2 = (tmp2 + u_b) / 256;
- signed g2 = (tmp2 + v_g + u_g) / 256;
- signed r2 = (tmp2 + v_r) / 256;
-
- uint32_t rgb1 =
- ((kAdjustedClip[b1] >> 3) << 11)
- | ((kAdjustedClip[g1] >> 2) << 5)
- | (kAdjustedClip[r1] >> 3);
-
- uint32_t rgb2 =
- ((kAdjustedClip[b2] >> 3) << 11)
- | ((kAdjustedClip[g2] >> 2) << 5)
- | (kAdjustedClip[r2] >> 3);
-
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
- }
-
- src_y += mDecodedWidth;
-
- if (y & 1) {
- src_u += mDecodedWidth;
- }
-
- dst_ptr += mDecodedWidth / 2;
- }
+ mConverter.convert(
+ mDecodedWidth, mDecodedHeight,
+ data, 0, dst, 2 * mDecodedWidth);
mISurface->postBuffer(offset);
mIndex = 1 - mIndex;
}
-uint8_t *SoftwareRenderer::initClip() {
- static const signed kClipMin = -278;
- static const signed kClipMax = 535;
-
- if (mClip == NULL) {
- mClip = new uint8_t[kClipMax - kClipMin + 1];
-
- for (signed i = kClipMin; i <= kClipMax; ++i) {
- mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
- }
- }
-
- return &mClip[-kClipMin];
-}
-
} // namespace android
diff --git a/media/libstagefright/stagefright_string.cpp b/media/libstagefright/string.cpp
index 2aedb80..bd6204b 100644
--- a/media/libstagefright/stagefright_string.cpp
+++ b/media/libstagefright/string.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/stagefright_string.h>
+#include "include/stagefright_string.h"
namespace android {