summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/Ringtone.java16
-rw-r--r--media/java/android/media/ThumbnailUtil.java9
-rw-r--r--media/libmedia/IMediaPlayerService.cpp10
-rw-r--r--media/libmedia/IOMX.cpp107
-rw-r--r--media/libmediaplayerservice/Android.mk7
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp45
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h3
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp9
-rw-r--r--media/libmediaplayerservice/StagefrightMetadataRetriever.cpp197
-rw-r--r--media/libmediaplayerservice/StagefrightMetadataRetriever.h53
-rw-r--r--media/libstagefright/AMRExtractor.cpp16
-rw-r--r--media/libstagefright/Android.mk1
-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.cpp9
-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.cpp87
-rw-r--r--media/libstagefright/MPEG4Writer.cpp14
-rw-r--r--media/libstagefright/MediaBuffer.cpp4
-rw-r--r--media/libstagefright/MediaExtractor.cpp33
-rw-r--r--media/libstagefright/MediaPlayerImpl.cpp49
-rw-r--r--media/libstagefright/MetaData.cpp19
-rw-r--r--media/libstagefright/MmapSource.cpp11
-rw-r--r--media/libstagefright/OMXClient.cpp2
-rw-r--r--media/libstagefright/OMXCodec.cpp448
-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/include/AMRExtractor.h54
-rw-r--r--media/libstagefright/include/ESDS.h64
-rw-r--r--media/libstagefright/include/HTTPStream.h75
-rw-r--r--media/libstagefright/include/MP3Extractor.h55
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h69
-rw-r--r--media/libstagefright/include/OMX.h (renamed from media/libstagefright/omx/OMX.h)91
-rw-r--r--media/libstagefright/include/OMXNodeInstance.h125
-rw-r--r--media/libstagefright/include/QComHardwareRenderer.h57
-rw-r--r--media/libstagefright/include/SampleTable.h111
-rw-r--r--media/libstagefright/include/SoftwareRenderer.h59
-rw-r--r--media/libstagefright/include/TIHardwareRenderer.h59
-rw-r--r--media/libstagefright/include/TimedEventQueue.h106
-rw-r--r--media/libstagefright/include/stagefright_string.h54
-rw-r--r--media/libstagefright/omx/Android.mk2
-rw-r--r--media/libstagefright/omx/ColorConverter.cpp297
-rw-r--r--media/libstagefright/omx/OMX.cpp395
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp460
-rw-r--r--media/libstagefright/omx/QComHardwareRenderer.cpp3
-rw-r--r--media/libstagefright/omx/SoftwareRenderer.cpp275
-rw-r--r--media/libstagefright/omx/TIHardwareRenderer.cpp3
-rw-r--r--media/libstagefright/string.cpp2
55 files changed, 2925 insertions, 1075 deletions
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index e80d8aa..1713324 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -137,11 +137,17 @@ public class Ringtone {
cursor = res.query(uri, MEDIA_COLUMNS, null, null, null);
}
- if (cursor != null && cursor.getCount() == 1) {
- cursor.moveToFirst();
- return cursor.getString(2);
- } else {
- title = uri.getLastPathSegment();
+ try {
+ if (cursor != null && cursor.getCount() == 1) {
+ cursor.moveToFirst();
+ return cursor.getString(2);
+ } else {
+ title = uri.getLastPathSegment();
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
}
}
}
diff --git a/media/java/android/media/ThumbnailUtil.java b/media/java/android/media/ThumbnailUtil.java
index f9d69fb..7c6bca3 100644
--- a/media/java/android/media/ThumbnailUtil.java
+++ b/media/java/android/media/ThumbnailUtil.java
@@ -33,6 +33,7 @@ import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.media.MediaMetadataRetriever;
+import android.media.MediaFile.MediaFileType;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
@@ -305,8 +306,12 @@ public class ThumbnailUtil {
ThumbnailUtil.THUMBNAIL_TARGET_SIZE : ThumbnailUtil.MINI_THUMB_TARGET_SIZE;
int maxPixels = wantMini ?
ThumbnailUtil.THUMBNAIL_MAX_NUM_PIXELS : ThumbnailUtil.MINI_THUMB_MAX_NUM_PIXELS;
- byte[] thumbData = createThumbnailFromEXIF(filePath, targetSize);
+ byte[] thumbData = null;
Bitmap bitmap = null;
+ MediaFileType fileType = MediaFile.getFileType(filePath);
+ if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) {
+ thumbData = createThumbnailFromEXIF(filePath, targetSize);
+ }
if (thumbData != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -454,6 +459,7 @@ public class ThumbnailUtil {
Cursor c = cr.query(thumbUri, THUMB_PROJECTION,
Thumbnails.IMAGE_ID + "=?",
new String[]{String.valueOf(origId)}, null);
+ if (c == null) return null;
try {
if (c.moveToNext()) {
return ContentUris.withAppendedId(thumbUri, c.getLong(0));
@@ -482,6 +488,7 @@ public class ThumbnailUtil {
if (thumb == null) return false;
try {
Uri uri = getImageThumbnailUri(cr, origId, thumb.getWidth(), thumb.getHeight());
+ if (uri == null) return false;
OutputStream thumbOut = cr.openOutputStream(uri);
thumb.compress(Bitmap.CompressFormat.JPEG, 85, thumbOut);
thumbOut.close();
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 98f7ef1..cca3e9b 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -35,7 +35,7 @@ enum {
DECODE_FD,
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
- CREATE_OMX,
+ GET_OMX,
SNOOP
};
@@ -123,10 +123,10 @@ public:
return interface_cast<IMemory>(reply.readStrongBinder());
}
- virtual sp<IOMX> createOMX() {
+ virtual sp<IOMX> getOMX() {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
- remote()->transact(CREATE_OMX, data, &reply);
+ remote()->transact(GET_OMX, data, &reply);
return interface_cast<IOMX>(reply.readStrongBinder());
}
};
@@ -207,9 +207,9 @@ status_t BnMediaPlayerService::onTransact(
reply->writeStrongBinder(retriever->asBinder());
return NO_ERROR;
} break;
- case CREATE_OMX: {
+ case GET_OMX: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
- sp<IOMX> omx = createOMX();
+ sp<IOMX> omx = getOMX();
reply->writeStrongBinder(omx->asBinder());
return NO_ERROR;
} break;
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 0cec7bb..76a9e7d 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -24,7 +24,6 @@ enum {
ALLOC_BUFFER,
ALLOC_BUFFER_WITH_BACKUP,
FREE_BUFFER,
- OBSERVE_NODE,
FILL_BUFFER,
EMPTY_BUFFER,
GET_EXTENSION_INDEX,
@@ -76,7 +75,7 @@ public:
: BpInterface<IOMX>(impl) {
}
- virtual status_t list_nodes(List<String8> *list) {
+ virtual status_t listNodes(List<String8> *list) {
list->clear();
Parcel data, reply;
@@ -93,10 +92,12 @@ public:
return OK;
}
- virtual status_t allocate_node(const char *name, node_id *node) {
+ virtual status_t allocateNode(
+ const char *name, const sp<IOMXObserver> &observer, node_id *node) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeCString(name);
+ data.writeStrongBinder(observer->asBinder());
remote()->transact(ALLOCATE_NODE, data, &reply);
status_t err = reply.readInt32();
@@ -109,7 +110,7 @@ public:
return err;
}
- virtual status_t free_node(node_id node) {
+ virtual status_t freeNode(node_id node) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeIntPtr((intptr_t)node);
@@ -118,7 +119,7 @@ public:
return reply.readInt32();
}
- virtual status_t send_command(
+ virtual status_t sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -130,7 +131,7 @@ public:
return reply.readInt32();
}
- virtual status_t get_parameter(
+ virtual status_t getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
Parcel data, reply;
@@ -151,7 +152,7 @@ public:
return OK;
}
- virtual status_t set_parameter(
+ virtual status_t setParameter(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
Parcel data, reply;
@@ -165,7 +166,7 @@ public:
return reply.readInt32();
}
- virtual status_t get_config(
+ virtual status_t getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
Parcel data, reply;
@@ -186,7 +187,7 @@ public:
return OK;
}
- virtual status_t set_config(
+ virtual status_t setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
Parcel data, reply;
@@ -200,7 +201,7 @@ public:
return reply.readInt32();
}
- virtual status_t use_buffer(
+ virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
buffer_id *buffer) {
Parcel data, reply;
@@ -222,7 +223,7 @@ public:
return err;
}
- virtual status_t allocate_buffer(
+ virtual status_t allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer) {
Parcel data, reply;
@@ -244,7 +245,7 @@ public:
return err;
}
- virtual status_t allocate_buffer_with_backup(
+ virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
buffer_id *buffer) {
Parcel data, reply;
@@ -266,7 +267,7 @@ public:
return err;
}
- virtual status_t free_buffer(
+ virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
@@ -278,26 +279,17 @@ public:
return reply.readInt32();
}
- virtual status_t observe_node(
- node_id node, const sp<IOMXObserver> &observer) {
+ virtual status_t fillBuffer(node_id node, buffer_id buffer) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeIntPtr((intptr_t)node);
- data.writeStrongBinder(observer->asBinder());
- remote()->transact(OBSERVE_NODE, data, &reply);
+ data.writeIntPtr((intptr_t)buffer);
+ remote()->transact(FILL_BUFFER, data, &reply);
return reply.readInt32();
}
- virtual void fill_buffer(node_id node, buffer_id buffer) {
- Parcel data, reply;
- data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
- data.writeIntPtr((intptr_t)node);
- data.writeIntPtr((intptr_t)buffer);
- remote()->transact(FILL_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
- }
-
- virtual void empty_buffer(
+ virtual status_t emptyBuffer(
node_id node,
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
@@ -310,10 +302,12 @@ 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();
}
- virtual status_t get_extension_index(
+ virtual status_t getExtensionIndex(
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index) {
@@ -375,7 +369,7 @@ status_t BnOMX::onTransact(
CHECK_INTERFACE(IOMX, data, reply);
List<String8> list;
- list_nodes(&list);
+ listNodes(&list);
reply->writeInt32(list.size());
for (List<String8>::iterator it = list.begin();
@@ -390,8 +384,14 @@ status_t BnOMX::onTransact(
{
CHECK_INTERFACE(IOMX, data, reply);
+ const char *name = data.readCString();
+
+ sp<IOMXObserver> observer =
+ interface_cast<IOMXObserver>(data.readStrongBinder());
+
node_id node;
- status_t err = allocate_node(data.readCString(), &node);
+
+ status_t err = allocateNode(name, observer, &node);
reply->writeInt32(err);
if (err == OK) {
reply->writeIntPtr((intptr_t)node);
@@ -406,7 +406,7 @@ status_t BnOMX::onTransact(
node_id node = (void*)data.readIntPtr();
- reply->writeInt32(free_node(node));
+ reply->writeInt32(freeNode(node));
return NO_ERROR;
}
@@ -421,7 +421,7 @@ status_t BnOMX::onTransact(
static_cast<OMX_COMMANDTYPE>(data.readInt32());
OMX_S32 param = data.readInt32();
- reply->writeInt32(send_command(node, cmd, param));
+ reply->writeInt32(sendCommand(node, cmd, param));
return NO_ERROR;
}
@@ -439,7 +439,7 @@ status_t BnOMX::onTransact(
void *params = malloc(size);
data.read(params, size);
- status_t err = get_parameter(node, index, params, size);
+ status_t err = getParameter(node, index, params, size);
reply->writeInt32(err);
@@ -463,7 +463,7 @@ status_t BnOMX::onTransact(
size_t size = data.readInt32();
void *params = const_cast<void *>(data.readInplace(size));
- reply->writeInt32(set_parameter(node, index, params, size));
+ reply->writeInt32(setParameter(node, index, params, size));
return NO_ERROR;
}
@@ -481,7 +481,7 @@ status_t BnOMX::onTransact(
void *params = malloc(size);
data.read(params, size);
- status_t err = get_config(node, index, params, size);
+ status_t err = getConfig(node, index, params, size);
reply->writeInt32(err);
@@ -505,7 +505,7 @@ status_t BnOMX::onTransact(
size_t size = data.readInt32();
void *params = const_cast<void *>(data.readInplace(size));
- reply->writeInt32(set_config(node, index, params, size));
+ reply->writeInt32(setConfig(node, index, params, size));
return NO_ERROR;
}
@@ -520,7 +520,7 @@ status_t BnOMX::onTransact(
interface_cast<IMemory>(data.readStrongBinder());
buffer_id buffer;
- status_t err = use_buffer(node, port_index, params, &buffer);
+ status_t err = useBuffer(node, port_index, params, &buffer);
reply->writeInt32(err);
if (err == OK) {
@@ -539,7 +539,7 @@ status_t BnOMX::onTransact(
size_t size = data.readInt32();
buffer_id buffer;
- status_t err = allocate_buffer(node, port_index, size, &buffer);
+ status_t err = allocateBuffer(node, port_index, size, &buffer);
reply->writeInt32(err);
if (err == OK) {
@@ -559,7 +559,7 @@ status_t BnOMX::onTransact(
interface_cast<IMemory>(data.readStrongBinder());
buffer_id buffer;
- status_t err = allocate_buffer_with_backup(
+ status_t err = allocateBufferWithBackup(
node, port_index, params, &buffer);
reply->writeInt32(err);
@@ -578,19 +578,7 @@ status_t BnOMX::onTransact(
node_id node = (void*)data.readIntPtr();
OMX_U32 port_index = data.readInt32();
buffer_id buffer = (void*)data.readIntPtr();
- reply->writeInt32(free_buffer(node, port_index, buffer));
-
- return NO_ERROR;
- }
-
- case OBSERVE_NODE:
- {
- CHECK_INTERFACE(IOMX, data, reply);
-
- node_id node = (void*)data.readIntPtr();
- sp<IOMXObserver> observer =
- interface_cast<IOMXObserver>(data.readStrongBinder());
- reply->writeInt32(observe_node(node, observer));
+ reply->writeInt32(freeBuffer(node, port_index, buffer));
return NO_ERROR;
}
@@ -601,7 +589,7 @@ status_t BnOMX::onTransact(
node_id node = (void*)data.readIntPtr();
buffer_id buffer = (void*)data.readIntPtr();
- fill_buffer(node, buffer);
+ reply->writeInt32(fillBuffer(node, buffer));
return NO_ERROR;
}
@@ -617,9 +605,10 @@ status_t BnOMX::onTransact(
OMX_U32 flags = data.readInt32();
OMX_TICKS timestamp = data.readInt64();
- empty_buffer(
- node, buffer, range_offset, range_length,
- flags, timestamp);
+ reply->writeInt32(
+ emptyBuffer(
+ node, buffer, range_offset, range_length,
+ flags, timestamp));
return NO_ERROR;
}
@@ -632,7 +621,7 @@ status_t BnOMX::onTransact(
const char *parameter_name = data.readCString();
OMX_INDEXTYPE index;
- status_t err = get_extension_index(node, parameter_name, &index);
+ status_t err = getExtensionIndex(node, parameter_name, &index);
reply->writeInt32(err);
@@ -683,7 +672,7 @@ public:
: BpInterface<IOMXObserver>(impl) {
}
- virtual void on_message(const omx_message &msg) {
+ virtual void onMessage(const omx_message &msg) {
Parcel data, reply;
data.writeInterfaceToken(IOMXObserver::getInterfaceDescriptor());
data.write(&msg, sizeof(msg));
@@ -705,7 +694,7 @@ status_t BnOMXObserver::onTransact(
data.read(&msg, sizeof(msg));
// XXX Could use readInplace maybe?
- on_message(msg);
+ onMessage(msg);
return NO_ERROR;
}
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index f21eb73..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
@@ -50,7 +51,7 @@ LOCAL_C_INCLUDES := external/tremor/Tremor \
$(JNI_H_INCLUDE) \
$(call include-path-for, graphics corecg) \
$(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
- $(TOP)/frameworks/base/media/libstagefright/omx
+ $(TOP)/frameworks/base/media/libstagefright/include
LOCAL_MODULE:= libmediaplayerservice
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 84be874..64267de 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -274,8 +274,14 @@ sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClie
return c;
}
-sp<IOMX> MediaPlayerService::createOMX() {
- return new OMX;
+sp<IOMX> MediaPlayerService::getOMX() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mOMX.get() == NULL) {
+ mOMX = new OMX;
+ }
+
+ return mOMX;
}
status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
@@ -350,11 +356,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/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 7d2e611..931667e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -183,7 +183,7 @@ public:
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
virtual sp<IMemory> snoop();
- virtual sp<IOMX> createOMX();
+ virtual sp<IOMX> getOMX();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -281,6 +281,7 @@ private:
mutable Mutex mLock;
SortedVector< wp<Client> > mClients;
int32_t mNextConnId;
+ sp<IOMX> mOMX;
};
// ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 8eabe5d..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;
}
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/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 3c343a3..b774609 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -17,6 +17,7 @@ ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
LOCAL_SRC_FILES += \
AMRExtractor.cpp \
CachingDataSource.cpp \
+ CameraSource.cpp \
DataSource.cpp \
FileSource.cpp \
HTTPDataSource.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 319488e..7b4d178 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -209,15 +209,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..210b2f6 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-#include <media/stagefright/AMRExtractor.h>
+#include "include/AMRExtractor.h"
+#include "include/MP3Extractor.h"
+#include "include/MPEG4Extractor.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 +28,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;
}
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 698223b..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/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..736f1a9d6 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);
+ 8000 * (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..5c3720e 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,7 +995,7 @@ 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;
}
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/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 8535f52..d51802c 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -18,12 +18,16 @@
#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 <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 +45,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);
}
@@ -58,4 +62,25 @@ sp<MediaExtractor> MediaExtractor::Create(
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 2e609e3..76f4182 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -18,15 +18,15 @@
#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/MediaExtractor.h>
#include <media/stagefright/MediaPlayerImpl.h>
@@ -69,18 +69,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;
@@ -250,6 +239,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) {
+ LOGI("format changed.");
+ depopulateISurface();
+ populateISurface();
+ continue;
+ }
+
if (err == ERROR_END_OF_STREAM || err != OK) {
eof = true;
continue;
@@ -261,15 +257,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;
@@ -379,12 +369,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;
}
}
@@ -609,6 +597,9 @@ void MediaPlayerImpl::populateISurface() {
success = success && meta->findInt32(kKeyHeight, &decodedHeight);
CHECK(success);
+ LOGI("mVideoWidth=%d, mVideoHeight=%d, decodedWidth=%d, decodedHeight=%d",
+ mVideoWidth, mVideoHeight, decodedWidth, decodedHeight);
+
if (mSurface.get() != NULL) {
mVideoRenderer =
mClient.interface()->createRenderer(
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/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index dba7a2a..9de873e 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -35,7 +35,7 @@ status_t OMXClient::connect() {
CHECK(service.get() != NULL);
- mOMX = service->createOMX();
+ mOMX = service->getOMX();
CHECK(mOMX.get() != NULL);
return OK;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 1a23fb2..01ec973 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;
@@ -85,12 +88,15 @@ static const CodecInfo kEncoderInfo[] = {
#define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
struct OMXCodecObserver : public BnOMXObserver {
- OMXCodecObserver(const wp<OMXCodec> &target)
- : mTarget(target) {
+ OMXCodecObserver() {
+ }
+
+ void setCodec(const sp<OMXCodec> &target) {
+ mTarget = target;
}
// from IOMXObserver
- virtual void on_message(const omx_message &msg) {
+ virtual void onMessage(const omx_message &msg) {
sp<OMXCodec> codec = mTarget.promote();
if (codec.get() != NULL) {
@@ -166,51 +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;
- 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->allocate_node(componentName, &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;
@@ -218,11 +210,6 @@ 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;
@@ -232,7 +219,6 @@ sp<OMXCodec> OMXCodec::Create(
// XXX Required on P....on only.
quirks |= kRequiresAllocateBufferOnInputPorts;
quirks |= kRequiresAllocateBufferOnOutputPorts;
- quirks |= kOutputDimensionsAre16Aligned;
}
if (!strncmp(componentName, "OMX.TI.", 7)) {
@@ -245,10 +231,98 @@ 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);
+
uint32_t type;
const void *data;
size_t size;
@@ -326,12 +400,14 @@ 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")
&& (profile != kAVCProfileBaseline || level > 39)) {
- // This stream exceeds the decoder's capabilities.
+ // This stream exceeds the decoder's capabilities. The decoder
+ // does not handle this gracefully and would clobber the heap
+ // and wreak havoc instead...
LOGE("Profile and/or level exceed the decoder's capabilities.");
return NULL;
@@ -406,7 +482,7 @@ void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
InitOMXParams(&def);
def.nPortIndex = portIndex;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -415,7 +491,7 @@ void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
}
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
}
@@ -433,7 +509,7 @@ status_t OMXCodec::setVideoPortFormatType(
OMX_U32 index = 0;
for (;;) {
format.nIndex = index;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
@@ -445,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
@@ -478,8 +554,8 @@ status_t OMXCodec::setVideoPortFormatType(
return UNKNOWN_ERROR;
}
- CODEC_LOGI("found a match.");
- status_t err = mOMX->set_parameter(
+ CODEC_LOGV("found a match.");
+ status_t err = mOMX->setParameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
@@ -488,7 +564,7 @@ status_t OMXCodec::setVideoPortFormatType(
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)) {
@@ -522,7 +598,7 @@ void OMXCodec::setVideoInputFormat(
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -534,7 +610,7 @@ void OMXCodec::setVideoInputFormat(
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -543,12 +619,12 @@ void OMXCodec::setVideoInputFormat(
InitOMXParams(&def);
def.nPortIndex = kPortIndexInput;
- err = mOMX->get_parameter(
+ err = mOMX->getParameter(
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);
+ CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
@@ -557,14 +633,14 @@ void OMXCodec::setVideoInputFormat(
video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
video_def->eColorFormat = colorFormat;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, 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)) {
@@ -588,7 +664,7 @@ void OMXCodec::setVideoOutputFormat(
format.nPortIndex = kPortIndexOutput;
format.nIndex = 0;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
CHECK_EQ(err, OK);
@@ -601,7 +677,7 @@ void OMXCodec::setVideoOutputFormat(
|| format.eColorFormat == OMX_COLOR_FormatCbYCrY
|| format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar);
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamVideoPortFormat,
&format, sizeof(format));
CHECK_EQ(err, OK);
@@ -614,7 +690,7 @@ void OMXCodec::setVideoOutputFormat(
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -634,7 +710,7 @@ void OMXCodec::setVideoOutputFormat(
video_def->eColorFormat = OMX_COLOR_FormatUnused;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -643,7 +719,7 @@ void OMXCodec::setVideoOutputFormat(
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
- err = mOMX->get_parameter(
+ err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
@@ -656,7 +732,7 @@ void OMXCodec::setVideoOutputFormat(
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
}
@@ -680,13 +756,11 @@ OMXCodec::OMXCodec(
mInitialBufferSubmit(true),
mSignalledEOS(false),
mNoMoreOutputData(false),
+ mOutputPortSettingsHaveChanged(false),
mSeekTimeUs(-1) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
- mObserver = new OMXCodecObserver(this);
- mOMX->observe_node(mNode, mObserver);
-
setComponentRole();
}
@@ -744,7 +818,7 @@ void OMXCodec::setComponentRole(
roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
- status_t err = omx->set_parameter(
+ status_t err = omx->setParameter(
node, OMX_IndexParamStandardComponentRole,
&roleParams, sizeof(roleParams));
@@ -761,10 +835,7 @@ void OMXCodec::setComponentRole() {
OMXCodec::~OMXCodec() {
CHECK(mState == LOADED || mState == ERROR);
- status_t err = mOMX->observe_node(mNode, NULL);
- CHECK_EQ(err, OK);
-
- err = mOMX->free_node(mNode);
+ status_t err = mOMX->freeNode(mNode);
CHECK_EQ(err, OK);
mNode = NULL;
@@ -786,7 +857,7 @@ status_t OMXCodec::init() {
status_t err;
if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {
- err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
CHECK_EQ(err, OK);
setState(LOADED_TO_IDLE);
}
@@ -795,7 +866,7 @@ status_t OMXCodec::init() {
CHECK_EQ(err, OK);
if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {
- err = mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
CHECK_EQ(err, OK);
setState(LOADED_TO_IDLE);
@@ -832,7 +903,7 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
InitOMXParams(&def);
def.nPortIndex = portIndex;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
if (err != OK) {
@@ -849,14 +920,14 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
IOMX::buffer_id buffer;
if (portIndex == kPortIndexInput
&& (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
- err = mOMX->allocate_buffer_with_backup(
+ err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &buffer);
} else if (portIndex == kPortIndexOutput
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
- err = mOMX->allocate_buffer_with_backup(
+ err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &buffer);
} else {
- err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
+ err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
}
if (err != OK) {
@@ -923,7 +994,7 @@ void OMXCodec::on_message(const omx_message &msg) {
CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
status_t err =
- mOMX->free_buffer(mNode, kPortIndexInput, buffer);
+ mOMX->freeBuffer(mNode, kPortIndexInput, buffer);
CHECK_EQ(err, OK);
buffers->removeAt(i);
@@ -969,7 +1040,7 @@ void OMXCodec::on_message(const omx_message &msg) {
CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
status_t err =
- mOMX->free_buffer(mNode, kPortIndexOutput, buffer);
+ mOMX->freeBuffer(mNode, kPortIndexOutput, buffer);
CHECK_EQ(err, OK);
buffers->removeAt(i);
@@ -989,12 +1060,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);
@@ -1063,6 +1130,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:
@@ -1085,6 +1217,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);
@@ -1139,7 +1280,7 @@ void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) {
mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
status_t err =
- mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
CHECK_EQ(err, OK);
}
} else {
@@ -1179,7 +1320,7 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) {
{
CODEC_LOGV("Now Idle.");
if (mState == LOADED_TO_IDLE) {
- status_t err = mOMX->send_command(
+ status_t err = mOMX->sendCommand(
mNode, OMX_CommandStateSet, OMX_StateExecuting);
CHECK_EQ(err, OK);
@@ -1196,7 +1337,7 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) {
countBuffersWeOwn(mPortBuffers[kPortIndexOutput]),
mPortBuffers[kPortIndexOutput].size());
- status_t err = mOMX->send_command(
+ status_t err = mOMX->sendCommand(
mNode, OMX_CommandStateSet, OMX_StateLoaded);
CHECK_EQ(err, OK);
@@ -1279,7 +1420,7 @@ status_t OMXCodec::freeBuffersOnPort(
CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex);
status_t err =
- mOMX->free_buffer(mNode, portIndex, info->mBuffer);
+ mOMX->freeBuffer(mNode, portIndex, info->mBuffer);
if (err != OK) {
stickyErr = err;
@@ -1339,7 +1480,7 @@ bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
}
status_t err =
- mOMX->send_command(mNode, OMX_CommandFlush, portIndex);
+ mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
CHECK_EQ(err, OK);
return true;
@@ -1352,7 +1493,7 @@ void OMXCodec::disablePortAsync(OMX_U32 portIndex) {
mPortStatus[portIndex] = DISABLING;
status_t err =
- mOMX->send_command(mNode, OMX_CommandPortDisable, portIndex);
+ mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex);
CHECK_EQ(err, OK);
freeBuffersOnPort(portIndex, true);
@@ -1365,7 +1506,7 @@ void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
mPortStatus[portIndex] = ENABLING;
status_t err =
- mOMX->send_command(mNode, OMX_CommandPortEnable, portIndex);
+ mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
CHECK_EQ(err, OK);
}
@@ -1417,10 +1558,11 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
memcpy(info->mMem->pointer(), specific->mData, specific->mSize);
}
- mOMX->empty_buffer(
+ status_t err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, size,
OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG,
0);
+ CHECK_EQ(err, OK);
info->mOwnedByComponent = true;
@@ -1441,7 +1583,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) {
@@ -1461,28 +1603,29 @@ 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);
}
}
- mOMX->empty_buffer(
- mNode, info->mBuffer, 0, srcLength,
- flags, timestamp);
-
- info->mOwnedByComponent = true;
-
if (srcBuffer != NULL) {
srcBuffer->release();
srcBuffer = NULL;
}
+
+ err = mOMX->emptyBuffer(
+ mNode, info->mBuffer, 0, srcLength,
+ flags, timestampUs);
+
+ if (err != OK) {
+ setState(ERROR);
+ return;
+ }
+
+ info->mOwnedByComponent = true;
}
void OMXCodec::fillOutputBuffer(BufferInfo *info) {
@@ -1495,7 +1638,8 @@ void OMXCodec::fillOutputBuffer(BufferInfo *info) {
}
CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
- mOMX->fill_buffer(mNode, info->mBuffer);
+ status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
+ CHECK_EQ(err, OK);
info->mOwnedByComponent = true;
}
@@ -1539,7 +1683,7 @@ void OMXCodec::setRawAudioFormat(
InitOMXParams(&pcmParams);
pcmParams.nPortIndex = portIndex;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
CHECK_EQ(err, OK);
@@ -1560,7 +1704,7 @@ void OMXCodec::setRawAudioFormat(
pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
}
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
CHECK_EQ(err, OK);
@@ -1573,14 +1717,14 @@ void OMXCodec::setAMRFormat() {
def.nPortIndex = kPortIndexInput;
status_t err =
- mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+ mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
CHECK_EQ(err, OK);
def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
def.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
- err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+ err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
CHECK_EQ(err, OK);
}
@@ -1604,14 +1748,14 @@ void OMXCodec::setAMRWBFormat() {
def.nPortIndex = kPortIndexInput;
status_t err =
- mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+ mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
CHECK_EQ(err, OK);
def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
- err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+ err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
CHECK_EQ(err, OK);
}
@@ -1636,7 +1780,7 @@ void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
InitOMXParams(&profile);
profile.nPortIndex = kPortIndexInput;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
CHECK_EQ(err, OK);
@@ -1644,7 +1788,7 @@ void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
profile.nSampleRate = sampleRate;
profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
CHECK_EQ(err, OK);
}
@@ -1668,7 +1812,7 @@ void OMXCodec::setImageOutputFormat(
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -1717,7 +1861,7 @@ void OMXCodec::setImageOutputFormat(
def.nBufferCountActual = def.nBufferCountMin;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
}
@@ -1728,7 +1872,7 @@ void OMXCodec::setJPEGInputFormat(
InitOMXParams(&def);
def.nPortIndex = kPortIndexInput;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -1742,7 +1886,7 @@ void OMXCodec::setJPEGInputFormat(
def.nBufferSize = compressedSize;
def.nBufferCountActual = def.nBufferCountMin;
- err = mOMX->set_parameter(
+ err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
}
@@ -1786,6 +1930,7 @@ status_t OMXCodec::start(MetaData *) {
mInitialBufferSubmit = true;
mSignalledEOS = false;
mNoMoreOutputData = false;
+ mOutputPortSettingsHaveChanged = false;
mSeekTimeUs = -1;
mFilledBuffers.clear();
@@ -1832,7 +1977,7 @@ status_t OMXCodec::stop() {
mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
status_t err =
- mOMX->send_command(mNode, OMX_CommandStateSet, OMX_StateIdle);
+ mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);
CHECK_EQ(err, OK);
}
@@ -1856,6 +2001,8 @@ status_t OMXCodec::stop() {
}
sp<MetaData> OMXCodec::getFormat() {
+ Mutex::Autolock autoLock(mLock);
+
return mOutputFormat;
}
@@ -1869,9 +2016,24 @@ status_t OMXCodec::read(
return UNKNOWN_ERROR;
}
+ bool seeking = false;
+ int64_t seekTimeUs;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ seeking = true;
+ }
+
if (mInitialBufferSubmit) {
mInitialBufferSubmit = false;
+ if (seeking) {
+ CHECK(seekTimeUs >= 0);
+ mSeekTimeUs = seekTimeUs;
+
+ // There's no reason to trigger the code below, there's
+ // nothing to flush yet.
+ seeking = false;
+ }
+
drainInputBuffers();
if (mState == EXECUTING) {
@@ -1881,8 +2043,7 @@ status_t OMXCodec::read(
}
}
- int64_t seekTimeUs;
- if (options && options->getSeekTo(&seekTimeUs)) {
+ if (seeking) {
CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6);
mSignalledEOS = false;
@@ -1919,6 +2080,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());
@@ -2019,8 +2186,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) {
@@ -2164,7 +2329,7 @@ void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
InitOMXParams(&def);
def.nPortIndex = portIndex;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -2230,7 +2395,7 @@ void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
InitOMXParams(&params);
params.nPortIndex = portIndex;
- err = mOMX->get_parameter(
+ err = mOMX->getParameter(
mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
CHECK_EQ(err, OK);
@@ -2249,7 +2414,7 @@ void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
InitOMXParams(&amr);
amr.nPortIndex = portIndex;
- err = mOMX->get_parameter(
+ err = mOMX->getParameter(
mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
CHECK_EQ(err, OK);
@@ -2281,7 +2446,7 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
- status_t err = mOMX->get_parameter(
+ status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
@@ -2307,7 +2472,7 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
InitOMXParams(&params);
params.nPortIndex = kPortIndexOutput;
- err = mOMX->get_parameter(
+ err = mOMX->getParameter(
mNode, OMX_IndexParamAudioPcm, &params, sizeof(params));
CHECK_EQ(err, OK);
@@ -2339,7 +2504,7 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) {
InitOMXParams(&amr);
amr.nPortIndex = kPortIndexOutput;
- err = mOMX->get_parameter(
+ err = mOMX->getParameter(
mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
CHECK_EQ(err, OK);
@@ -2388,7 +2553,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);
@@ -2436,8 +2601,9 @@ status_t QueryCodecs(
return OK;
}
+ sp<OMXCodecObserver> observer = new OMXCodecObserver;
IOMX::node_id node;
- status_t err = omx->allocate_node(componentName, &node);
+ status_t err = omx->allocateNode(componentName, observer, &node);
if (err != OK) {
continue;
@@ -2455,7 +2621,7 @@ status_t QueryCodecs(
param.nPortIndex = queryDecoders ? 0 : 1;
for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
- err = omx->get_parameter(
+ err = omx->getParameter(
node, OMX_IndexParamVideoProfileLevelQuerySupported,
&param, sizeof(param));
@@ -2470,7 +2636,7 @@ status_t QueryCodecs(
caps->mProfileLevels.push(profileLevel);
}
- CHECK_EQ(omx->free_node(node), OK);
+ CHECK_EQ(omx->freeNode(node), OK);
}
}
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 8e8f4fa..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/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/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
new file mode 100644
index 0000000..debf006
--- /dev/null
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -0,0 +1,54 @@
+/*
+ * 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 AMR_EXTRACTOR_H_
+
+#define AMR_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class String8;
+
+class AMRExtractor : public MediaExtractor {
+public:
+ AMRExtractor(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);
+
+ static sp<MetaData> makeAMRFormat(bool isWide);
+
+protected:
+ virtual ~AMRExtractor();
+
+private:
+ sp<DataSource> mDataSource;
+ status_t mInitCheck;
+ bool mIsWide;
+
+ AMRExtractor(const AMRExtractor &);
+ AMRExtractor &operator=(const AMRExtractor &);
+};
+
+bool SniffAMR(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // AMR_EXTRACTOR_H_
diff --git a/media/libstagefright/include/ESDS.h b/media/libstagefright/include/ESDS.h
new file mode 100644
index 0000000..01bcd18
--- /dev/null
+++ b/media/libstagefright/include/ESDS.h
@@ -0,0 +1,64 @@
+/*
+ * 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 ESDS_H_
+
+#define ESDS_H_
+
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+class ESDS {
+public:
+ ESDS(const void *data, size_t size);
+ ~ESDS();
+
+ status_t InitCheck() const;
+
+ status_t getCodecSpecificInfo(const void **data, size_t *size) const;
+
+private:
+ enum {
+ kTag_ESDescriptor = 0x03,
+ kTag_DecoderConfigDescriptor = 0x04,
+ kTag_DecoderSpecificInfo = 0x05
+ };
+
+ uint8_t *mData;
+ size_t mSize;
+
+ status_t mInitCheck;
+
+ size_t mDecoderSpecificOffset;
+ size_t mDecoderSpecificLength;
+
+ status_t skipDescriptorHeader(
+ size_t offset, size_t size,
+ uint8_t *tag, size_t *data_offset, size_t *data_size) const;
+
+ status_t parse();
+ status_t parseESDescriptor(size_t offset, size_t size);
+ status_t parseDecoderConfigDescriptor(size_t offset, size_t size);
+
+ ESDS(const ESDS &);
+ ESDS &operator=(const ESDS &);
+};
+
+} // namespace android
+#endif // ESDS_H_
diff --git a/media/libstagefright/include/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
new file mode 100644
index 0000000..43ef614
--- /dev/null
+++ b/media/libstagefright/include/HTTPStream.h
@@ -0,0 +1,75 @@
+/*
+ * 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 HTTP_STREAM_H_
+
+#define HTTP_STREAM_H_
+
+#include "stagefright_string.h"
+
+#include <sys/types.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+class HTTPStream {
+public:
+ HTTPStream();
+ ~HTTPStream();
+
+ status_t connect(const char *server, int port = 80);
+ status_t disconnect();
+
+ status_t send(const char *data, size_t size);
+
+ // Assumes data is a '\0' terminated string.
+ status_t send(const char *data);
+
+ // Receive up to "size" bytes of data.
+ ssize_t receive(void *data, size_t size);
+
+ status_t receive_header(int *http_status);
+
+ // The header key used to retrieve the status line.
+ static const char *kStatusKey;
+
+ bool find_header_value(
+ const string &key, string *value) const;
+
+private:
+ enum State {
+ READY,
+ CONNECTED
+ };
+
+ State mState;
+ int mSocket;
+
+ KeyedVector<string, string> mHeaders;
+
+ // Receive a line of data terminated by CRLF, line will be '\0' terminated
+ // _excluding_ the termianting CRLF.
+ status_t receive_line(char *line, size_t size);
+
+ HTTPStream(const HTTPStream &);
+ HTTPStream &operator=(const HTTPStream &);
+};
+
+} // namespace android
+
+#endif // HTTP_STREAM_H_
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
new file mode 100644
index 0000000..074973b
--- /dev/null
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -0,0 +1,55 @@
+/*
+ * 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 MP3_EXTRACTOR_H_
+
+#define MP3_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class String8;
+
+class MP3Extractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ MP3Extractor(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 ~MP3Extractor();
+
+private:
+ sp<DataSource> mDataSource;
+ off_t mFirstFramePos;
+ sp<MetaData> mMeta;
+ uint32_t mFixedHeader;
+
+ MP3Extractor(const MP3Extractor &);
+ MP3Extractor &operator=(const MP3Extractor &);
+};
+
+bool SniffMP3(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // MP3_EXTRACTOR_H_
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
new file mode 100644
index 0000000..ce4736d
--- /dev/null
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -0,0 +1,69 @@
+/*
+ * 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 MPEG4_EXTRACTOR_H_
+
+#define MPEG4_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class DataSource;
+class SampleTable;
+class String8;
+
+class MPEG4Extractor : public MediaExtractor {
+public:
+ // Extractor assumes ownership of "source".
+ MPEG4Extractor(const sp<DataSource> &source);
+
+ size_t countTracks();
+ sp<MediaSource> getTrack(size_t index);
+ sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
+
+protected:
+ virtual ~MPEG4Extractor();
+
+private:
+ struct Track {
+ Track *next;
+ sp<MetaData> meta;
+ uint32_t timescale;
+ sp<SampleTable> sampleTable;
+ bool includes_expensive_metadata;
+ };
+
+ sp<DataSource> mDataSource;
+ bool mHaveMetadata;
+
+ Track *mFirstTrack, *mLastTrack;
+
+ uint32_t mHandlerType;
+
+ status_t readMetaData();
+ status_t parseChunk(off_t *offset, int depth);
+
+ MPEG4Extractor(const MPEG4Extractor &);
+ MPEG4Extractor &operator=(const MPEG4Extractor &);
+};
+
+bool SniffMPEG4(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // MPEG4_EXTRACTOR_H_
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/include/OMX.h
index 6325f79..a4b62b2 100644
--- a/media/libstagefright/omx/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -19,66 +19,67 @@
#include <media/IOMX.h>
#include <utils/threads.h>
+#include <utils/KeyedVector.h>
namespace android {
-class NodeMeta;
+class OMXNodeInstance;
-class OMX : public BnOMX {
+class OMX : public BnOMX,
+ public IBinder::DeathRecipient {
public:
OMX();
- virtual status_t list_nodes(List<String8> *list);
+ virtual status_t listNodes(List<String8> *list);
- virtual status_t allocate_node(const char *name, node_id *node);
- virtual status_t free_node(node_id node);
+ virtual status_t allocateNode(
+ const char *name, const sp<IOMXObserver> &observer, node_id *node);
- virtual status_t send_command(
+ virtual status_t freeNode(node_id node);
+
+ virtual status_t sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
- virtual status_t get_parameter(
+ virtual status_t getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size);
- virtual status_t set_parameter(
+ virtual status_t setParameter(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size);
- virtual status_t get_config(
+ virtual status_t getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size);
- virtual status_t set_config(
+ virtual status_t setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size);
- virtual status_t use_buffer(
+ virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
buffer_id *buffer);
- virtual status_t allocate_buffer(
+ virtual status_t allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer);
- virtual status_t allocate_buffer_with_backup(
+ virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
buffer_id *buffer);
- virtual status_t free_buffer(
+ virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer);
- virtual status_t observe_node(
- node_id node, const sp<IOMXObserver> &observer);
-
- virtual void fill_buffer(node_id node, buffer_id buffer);
+ virtual status_t fillBuffer(node_id node, buffer_id buffer);
- virtual void empty_buffer(
+ virtual status_t emptyBuffer(
node_id node,
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp);
- virtual status_t get_extension_index(
+ virtual status_t getExtensionIndex(
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index);
@@ -90,44 +91,38 @@ public:
size_t encodedWidth, size_t encodedHeight,
size_t displayWidth, size_t displayHeight);
-private:
- static OMX_CALLBACKTYPE kCallbacks;
-
- Mutex mLock;
-
- struct CallbackDispatcher;
- sp<CallbackDispatcher> mDispatcher;
-
- static OMX_ERRORTYPE OnEvent(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN OMX_PTR pEventData);
-
- static OMX_ERRORTYPE OnEmptyBufferDone(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
-
- static OMX_ERRORTYPE OnFillBufferDone(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+ virtual void binderDied(const wp<IBinder> &the_late_who);
OMX_ERRORTYPE OnEvent(
- NodeMeta *meta,
+ node_id node,
OMX_IN OMX_EVENTTYPE eEvent,
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData);
OMX_ERRORTYPE OnEmptyBufferDone(
- NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+ node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
OMX_ERRORTYPE OnFillBufferDone(
- NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+ node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ void invalidateNodeID(node_id node);
+
+private:
+ Mutex mLock;
+
+ struct CallbackDispatcher;
+ sp<CallbackDispatcher> mDispatcher;
+
+ int32_t mNodeCounter;
+
+ KeyedVector<wp<IBinder>, OMXNodeInstance *> mLiveNodes;
+ KeyedVector<node_id, OMXNodeInstance *> mNodeIDToInstance;
+
+ node_id makeNodeID(OMXNodeInstance *instance);
+ OMXNodeInstance *findInstance(node_id node);
+
+ void invalidateNodeID_l(node_id node);
OMX(const OMX &);
OMX &operator=(const OMX &);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
new file mode 100644
index 0000000..09a8816
--- /dev/null
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -0,0 +1,125 @@
+/*
+ * 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 OMX_NODE_INSTANCE_H_
+
+#define OMX_NODE_INSTANCE_H_
+
+#include "OMX.h"
+
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class IOMXObserver;
+
+struct OMXNodeInstance {
+ OMXNodeInstance(
+ OMX *owner, const sp<IOMXObserver> &observer);
+
+ void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
+
+ OMX *owner();
+ sp<IOMXObserver> observer();
+ OMX::node_id nodeID();
+
+ status_t freeNode();
+
+ status_t sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param);
+ status_t getParameter(OMX_INDEXTYPE index, void *params, size_t size);
+
+ status_t setParameter(
+ OMX_INDEXTYPE index, const void *params, size_t size);
+
+ status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
+ status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
+
+ status_t useBuffer(
+ OMX_U32 portIndex, const sp<IMemory> &params,
+ OMX::buffer_id *buffer);
+
+ status_t allocateBuffer(
+ OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer);
+
+ status_t allocateBufferWithBackup(
+ OMX_U32 portIndex, const sp<IMemory> &params,
+ OMX::buffer_id *buffer);
+
+ status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
+
+ status_t fillBuffer(OMX::buffer_id buffer);
+
+ status_t emptyBuffer(
+ OMX::buffer_id buffer,
+ OMX_U32 rangeOffset, OMX_U32 rangeLength,
+ OMX_U32 flags, OMX_TICKS timestamp);
+
+ status_t getExtensionIndex(
+ const char *parameterName, OMX_INDEXTYPE *index);
+
+ void onMessage(const omx_message &msg);
+ void onObserverDied();
+ void onGetHandleFailed();
+
+ static OMX_CALLBACKTYPE kCallbacks;
+
+private:
+ Mutex mLock;
+
+ OMX *mOwner;
+ OMX::node_id mNodeID;
+ OMX_HANDLETYPE mHandle;
+ sp<IOMXObserver> mObserver;
+
+ struct ActiveBuffer {
+ OMX_U32 mPortIndex;
+ OMX::buffer_id mID;
+ };
+ Vector<ActiveBuffer> mActiveBuffers;
+
+ ~OMXNodeInstance();
+
+ void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
+ void removeActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
+ void freeActiveBuffers();
+
+ static OMX_ERRORTYPE OnEvent(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData);
+
+ static OMX_ERRORTYPE OnEmptyBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ static OMX_ERRORTYPE OnFillBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE *pBuffer);
+
+ OMXNodeInstance(const OMXNodeInstance &);
+ OMXNodeInstance &operator=(const OMXNodeInstance &);
+};
+
+} // namespace android
+
+#endif // OMX_NODE_INSTANCE_H_
+
diff --git a/media/libstagefright/include/QComHardwareRenderer.h b/media/libstagefright/include/QComHardwareRenderer.h
new file mode 100644
index 0000000..8292dd5
--- /dev/null
+++ b/media/libstagefright/include/QComHardwareRenderer.h
@@ -0,0 +1,57 @@
+/*
+ * 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 QCOM_HARDWARE_RENDERER_H_
+
+#define QCOM_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapPmem;
+
+class QComHardwareRenderer : public VideoRenderer {
+public:
+ QComHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~QComHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<MemoryHeapPmem> mMemoryHeap;
+
+ bool getOffset(void *platformPrivate, size_t *offset);
+ void publishBuffers(uint32_t pmem_fd);
+
+ QComHardwareRenderer(const QComHardwareRenderer &);
+ QComHardwareRenderer &operator=(const QComHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // QCOM_HARDWARE_RENDERER_H_
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
new file mode 100644
index 0000000..ead3431
--- /dev/null
+++ b/media/libstagefright/include/SampleTable.h
@@ -0,0 +1,111 @@
+/*
+ * 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 SAMPLE_TABLE_H_
+
+#define SAMPLE_TABLE_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <media/stagefright/MediaErrors.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class DataSource;
+
+class SampleTable : public RefBase {
+public:
+ SampleTable(const sp<DataSource> &source);
+
+ // type can be 'stco' or 'co64'.
+ status_t setChunkOffsetParams(
+ uint32_t type, off_t data_offset, size_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, size_t data_size);
+
+ status_t setTimeToSampleParams(off_t data_offset, size_t data_size);
+
+ status_t setSyncSampleParams(off_t data_offset, size_t data_size);
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ uint32_t countChunkOffsets() const;
+ status_t getChunkOffset(uint32_t chunk_index, off_t *offset);
+
+ status_t getChunkForSample(
+ uint32_t sample_index, uint32_t *chunk_index,
+ uint32_t *chunk_relative_sample_index, uint32_t *desc_index);
+
+ uint32_t countSamples() const;
+ status_t getSampleSize(uint32_t sample_index, size_t *sample_size);
+
+ status_t getSampleOffsetAndSize(
+ uint32_t sample_index, off_t *offset, size_t *size);
+
+ status_t getMaxSampleSize(size_t *size);
+
+ status_t getDecodingTime(uint32_t sample_index, uint32_t *time);
+
+ enum {
+ kSyncSample_Flag = 1
+ };
+ status_t findClosestSample(
+ uint32_t req_time, uint32_t *sample_index, uint32_t flags);
+
+ status_t findClosestSyncSample(
+ uint32_t start_sample_index, uint32_t *sample_index);
+
+ status_t findThumbnailSample(uint32_t *sample_index);
+
+protected:
+ ~SampleTable();
+
+private:
+ sp<DataSource> mDataSource;
+ Mutex mLock;
+
+ off_t mChunkOffsetOffset;
+ uint32_t mChunkOffsetType;
+ uint32_t mNumChunkOffsets;
+
+ off_t mSampleToChunkOffset;
+ uint32_t mNumSampleToChunkOffsets;
+
+ off_t mSampleSizeOffset;
+ uint32_t mSampleSizeFieldSize;
+ uint32_t mDefaultSampleSize;
+ uint32_t mNumSampleSizes;
+
+ uint32_t mTimeToSampleCount;
+ uint32_t *mTimeToSample;
+
+ off_t mSyncSampleOffset;
+ uint32_t mNumSyncSamples;
+
+ SampleTable(const SampleTable &);
+ SampleTable &operator=(const SampleTable &);
+};
+
+} // namespace android
+
+#endif // SAMPLE_TABLE_H_
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
new file mode 100644
index 0000000..9eed089
--- /dev/null
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFTWARE_RENDERER_H_
+
+#define SOFTWARE_RENDERER_H_
+
+#include <media/stagefright/ColorConverter.h>
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class ISurface;
+class MemoryHeapBase;
+
+class SoftwareRenderer : public VideoRenderer {
+public:
+ SoftwareRenderer(
+ OMX_COLOR_FORMATTYPE colorFormat,
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~SoftwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ OMX_COLOR_FORMATTYPE mColorFormat;
+ ColorConverter mConverter;
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<MemoryHeapBase> mMemoryHeap;
+ int mIndex;
+
+ SoftwareRenderer(const SoftwareRenderer &);
+ SoftwareRenderer &operator=(const SoftwareRenderer &);
+};
+
+} // namespace android
+
+#endif // SOFTWARE_RENDERER_H_
diff --git a/media/libstagefright/include/TIHardwareRenderer.h b/media/libstagefright/include/TIHardwareRenderer.h
new file mode 100644
index 0000000..ef42648
--- /dev/null
+++ b/media/libstagefright/include/TIHardwareRenderer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TI_HARDWARE_RENDERER_H_
+
+#define TI_HARDWARE_RENDERER_H_
+
+#include <media/stagefright/VideoRenderer.h>
+#include <utils/RefBase.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ISurface;
+class Overlay;
+
+class TIHardwareRenderer : public VideoRenderer {
+public:
+ TIHardwareRenderer(
+ const sp<ISurface> &surface,
+ size_t displayWidth, size_t displayHeight,
+ size_t decodedWidth, size_t decodedHeight);
+
+ virtual ~TIHardwareRenderer();
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate);
+
+private:
+ sp<ISurface> mISurface;
+ size_t mDisplayWidth, mDisplayHeight;
+ size_t mDecodedWidth, mDecodedHeight;
+ size_t mFrameSize;
+ sp<Overlay> mOverlay;
+ Vector<void *> mOverlayAddresses;
+ bool mIsFirstFrame;
+ size_t mIndex;
+
+ TIHardwareRenderer(const TIHardwareRenderer &);
+ TIHardwareRenderer &operator=(const TIHardwareRenderer &);
+};
+
+} // namespace android
+
+#endif // TI_HARDWARE_RENDERER_H_
+
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
new file mode 100644
index 0000000..a264421
--- /dev/null
+++ b/media/libstagefright/include/TimedEventQueue.h
@@ -0,0 +1,106 @@
+/*
+ * 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 TIMED_EVENT_QUEUE_H_
+
+#define TIMED_EVENT_QUEUE_H_
+
+#include <pthread.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct TimedEventQueue {
+
+ struct Event : public RefBase {
+ Event() {}
+ virtual ~Event() {}
+
+ protected:
+ virtual void fire(TimedEventQueue *queue, int64_t now_us) = 0;
+
+ private:
+ friend class TimedEventQueue;
+
+ Event(const Event &);
+ Event &operator=(const Event &);
+ };
+
+ TimedEventQueue();
+ ~TimedEventQueue();
+
+ // Start executing the event loop.
+ void start();
+
+ // Stop executing the event loop, if flush is false, any pending
+ // events are discarded, otherwise the queue will stop (and this call
+ // return) once all pending events have been handled.
+ void stop(bool flush = false);
+
+ // Posts an event to the front of the queue (after all events that
+ // have previously been posted to the front but before timed events).
+ void postEvent(const sp<Event> &event);
+
+ void postEventToBack(const sp<Event> &event);
+
+ // It is an error to post an event with a negative delay.
+ void postEventWithDelay(const sp<Event> &event, int64_t delay_us);
+
+ // If the event is to be posted at a time that has already passed,
+ // it will fire as soon as possible.
+ void postTimedEvent(const sp<Event> &event, int64_t realtime_us);
+
+ // Returns true iff event is currently in the queue and has been
+ // successfully cancelled. In this case the event will have been
+ // removed from the queue and won't fire.
+ bool cancelEvent(const sp<Event> &event);
+
+ static int64_t getRealTimeUs();
+
+private:
+ struct QueueItem {
+ sp<Event> event;
+ int64_t realtime_us;
+ };
+
+ struct StopEvent : public TimedEventQueue::Event {
+ virtual void fire(TimedEventQueue *queue, int64_t now_us) {
+ queue->mStopped = true;
+ }
+ };
+
+ pthread_t mThread;
+ List<QueueItem> mQueue;
+ Mutex mLock;
+ Condition mQueueNotEmptyCondition;
+ Condition mQueueHeadChangedCondition;
+
+ bool mRunning;
+ bool mStopped;
+
+ static void *ThreadWrapper(void *me);
+ void threadEntry();
+
+ TimedEventQueue(const TimedEventQueue &);
+ TimedEventQueue &operator=(const TimedEventQueue &);
+};
+
+} // namespace android
+
+#endif // TIMED_EVENT_QUEUE_H_
diff --git a/media/libstagefright/include/stagefright_string.h b/media/libstagefright/include/stagefright_string.h
new file mode 100644
index 0000000..5dc7116
--- /dev/null
+++ b/media/libstagefright/include/stagefright_string.h
@@ -0,0 +1,54 @@
+/*
+ * 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 STRING_H_
+
+#define STRING_H_
+
+#include <utils/String8.h>
+
+namespace android {
+
+class string {
+public:
+ typedef size_t size_type;
+ static size_type npos;
+
+ string();
+ string(const char *s);
+ string(const char *s, size_t length);
+ string(const string &from, size_type start, size_type length = npos);
+
+ const char *c_str() const;
+ size_type size() const;
+
+ void clear();
+ void erase(size_type from, size_type length);
+
+ size_type find(char c) const;
+
+ bool operator<(const string &other) const;
+ bool operator==(const string &other) const;
+
+ string &operator+=(char c);
+
+private:
+ String8 mString;
+};
+
+} // namespace android
+
+#endif // STRING_H_
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 4cadccd..edbc04e 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -10,7 +10,9 @@ LOCAL_C_INCLUDES += $(TOP)/hardware/ti/omap3/liboverlay
LOCAL_C_INCLUDES += $(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
+ ColorConverter.cpp \
OMX.cpp \
+ OMXNodeInstance.cpp \
QComHardwareRenderer.cpp \
SoftwareRenderer.cpp \
TIHardwareRenderer.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 8b83dd6..e361018 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -18,65 +18,28 @@
#define LOG_TAG "OMX"
#include <utils/Log.h>
-#include <sys/socket.h>
-
-#include "OMX.h"
+#include "../include/OMX.h"
#include "OMXRenderer.h"
#include "pv_omxcore.h"
+#include "../include/OMXNodeInstance.h"
+#include "../include/QComHardwareRenderer.h"
+#include "../include/SoftwareRenderer.h"
+#include "../include/TIHardwareRenderer.h"
+
#include <binder/IMemory.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
-#include <media/stagefright/SoftwareRenderer.h>
-#include <media/stagefright/TIHardwareRenderer.h>
#include <media/stagefright/VideoRenderer.h>
#include <OMX_Component.h>
namespace android {
-class NodeMeta {
-public:
- NodeMeta(OMX *owner)
- : mOwner(owner),
- mHandle(NULL) {
- }
-
- OMX *owner() const {
- return mOwner;
- }
-
- void setHandle(OMX_HANDLETYPE handle) {
- CHECK_EQ(mHandle, NULL);
- mHandle = handle;
- }
-
- OMX_HANDLETYPE handle() const {
- return mHandle;
- }
-
- void setObserver(const sp<IOMXObserver> &observer) {
- mObserver = observer;
- }
-
- sp<IOMXObserver> observer() {
- return mObserver;
- }
-
-private:
- OMX *mOwner;
- OMX_HANDLETYPE mHandle;
- sp<IOMXObserver> mObserver;
-
- NodeMeta(const NodeMeta &);
- NodeMeta &operator=(const NodeMeta &);
-};
-
////////////////////////////////////////////////////////////////////////////////
struct OMX::CallbackDispatcher : public RefBase {
- CallbackDispatcher();
+ CallbackDispatcher(OMX *owner);
void post(const omx_message &msg);
@@ -85,6 +48,8 @@ protected:
private:
Mutex mLock;
+
+ OMX *mOwner;
bool mDone;
Condition mQueueChanged;
List<omx_message> mQueue;
@@ -100,8 +65,9 @@ private:
CallbackDispatcher &operator=(const CallbackDispatcher &);
};
-OMX::CallbackDispatcher::CallbackDispatcher()
- : mDone(false) {
+OMX::CallbackDispatcher::CallbackDispatcher(OMX *owner)
+ : mOwner(owner),
+ mDone(false) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
@@ -130,12 +96,12 @@ void OMX::CallbackDispatcher::post(const omx_message &msg) {
}
void OMX::CallbackDispatcher::dispatch(const omx_message &msg) {
- NodeMeta *meta = static_cast<NodeMeta *>(msg.node);
-
- sp<IOMXObserver> observer = meta->observer();
- if (observer.get() != NULL) {
- observer->on_message(msg);
+ OMXNodeInstance *instance = mOwner->findInstance(msg.node);
+ if (instance == NULL) {
+ LOGV("Would have dispatched a message to a node that's already gone.");
+ return;
}
+ instance->onMessage(msg);
}
// static
@@ -213,46 +179,30 @@ private:
BufferMeta &operator=(const BufferMeta &);
};
-// static
-OMX_CALLBACKTYPE OMX::kCallbacks = {
- &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
-};
-
-// static
-OMX_ERRORTYPE OMX::OnEvent(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_EVENTTYPE eEvent,
- OMX_IN OMX_U32 nData1,
- OMX_IN OMX_U32 nData2,
- OMX_IN OMX_PTR pEventData) {
- NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
- return meta->owner()->OnEvent(meta, eEvent, nData1, nData2, pEventData);
+OMX::OMX()
+ : mDispatcher(new CallbackDispatcher(this)),
+ mNodeCounter(0) {
}
-// static
-OMX_ERRORTYPE OMX::OnEmptyBufferDone(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
- NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
- return meta->owner()->OnEmptyBufferDone(meta, pBuffer);
-}
+void OMX::binderDied(const wp<IBinder> &the_late_who) {
+ OMXNodeInstance *instance;
-// static
-OMX_ERRORTYPE OMX::OnFillBufferDone(
- OMX_IN OMX_HANDLETYPE hComponent,
- OMX_IN OMX_PTR pAppData,
- OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
- NodeMeta *meta = static_cast<NodeMeta *>(pAppData);
- return meta->owner()->OnFillBufferDone(meta, pBuffer);
-}
+ {
+ Mutex::Autolock autoLock(mLock);
-OMX::OMX()
- : mDispatcher(new CallbackDispatcher) {
+ ssize_t index = mLiveNodes.indexOfKey(the_late_who);
+ CHECK(index >= 0);
+
+ instance = mLiveNodes.editValueAt(index);
+ mLiveNodes.removeItemsAt(index);
+
+ invalidateNodeID_l(instance->nodeID());
+ }
+
+ instance->onObserverDied();
}
-status_t OMX::list_nodes(List<String8> *list) {
+status_t OMX::listNodes(List<String8> *list) {
OMX_MasterInit(); // XXX Put this somewhere else.
list->clear();
@@ -269,204 +219,132 @@ status_t OMX::list_nodes(List<String8> *list) {
return OK;
}
-status_t OMX::allocate_node(const char *name, node_id *node) {
+status_t OMX::allocateNode(
+ const char *name, const sp<IOMXObserver> &observer, node_id *node) {
Mutex::Autolock autoLock(mLock);
*node = 0;
OMX_MasterInit(); // XXX Put this somewhere else.
- NodeMeta *meta = new NodeMeta(this);
+ OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
OMX_HANDLETYPE handle;
OMX_ERRORTYPE err = OMX_MasterGetHandle(
- &handle, const_cast<char *>(name), meta, &kCallbacks);
+ &handle, const_cast<char *>(name), instance,
+ &OMXNodeInstance::kCallbacks);
if (err != OMX_ErrorNone) {
- LOGE("FAILED to allocate omx component '%s'", name);
+ LOGV("FAILED to allocate omx component '%s'", name);
- delete meta;
- meta = NULL;
+ instance->onGetHandleFailed();
return UNKNOWN_ERROR;
}
- meta->setHandle(handle);
+ *node = makeNodeID(instance);
- *node = meta;
+ instance->setHandle(*node, handle);
+
+ mLiveNodes.add(observer->asBinder(), instance);
+ observer->asBinder()->linkToDeath(this);
return OK;
}
-status_t OMX::free_node(node_id node) {
- Mutex::Autolock autoLock(mLock);
-
- NodeMeta *meta = static_cast<NodeMeta *>(node);
-
- OMX_ERRORTYPE err = OMX_MasterFreeHandle(meta->handle());
+status_t OMX::freeNode(node_id node) {
+ OMXNodeInstance *instance = findInstance(node);
- delete meta;
- meta = NULL;
+ ssize_t index = mLiveNodes.indexOfKey(instance->observer()->asBinder());
+ CHECK(index >= 0);
+ mLiveNodes.removeItemsAt(index);
+ instance->observer()->asBinder()->unlinkToDeath(this);
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+ return instance->freeNode();
}
-status_t OMX::send_command(
+status_t OMX::sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
- Mutex::Autolock autoLock(mLock);
-
- NodeMeta *meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err = OMX_SendCommand(meta->handle(), cmd, param, NULL);
-
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+ return findInstance(node)->sendCommand(cmd, param);
}
-status_t OMX::get_parameter(
+status_t OMX::getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- NodeMeta *meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err = OMX_GetParameter(meta->handle(), index, params);
-
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+ return findInstance(node)->getParameter(
+ index, params, size);
}
-status_t OMX::set_parameter(
+status_t OMX::setParameter(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- NodeMeta *meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err =
- OMX_SetParameter(meta->handle(), index, const_cast<void *>(params));
-
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+ return findInstance(node)->setParameter(
+ index, params, size);
}
-status_t OMX::get_config(
+status_t OMX::getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- NodeMeta *meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err = OMX_GetConfig(meta->handle(), index, params);
-
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+ return findInstance(node)->getConfig(
+ index, params, size);
}
-status_t OMX::set_config(
+status_t OMX::setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
- Mutex::Autolock autoLock(mLock);
-
- NodeMeta *meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err =
- OMX_SetConfig(meta->handle(), index, const_cast<void *>(params));
-
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+ return findInstance(node)->setConfig(
+ index, params, size);
}
-status_t OMX::use_buffer(
+status_t OMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
buffer_id *buffer) {
- Mutex::Autolock autoLock(mLock);
-
- BufferMeta *buffer_meta = new BufferMeta(this, params);
-
- OMX_BUFFERHEADERTYPE *header;
-
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err =
- OMX_UseBuffer(node_meta->handle(), &header, port_index, buffer_meta,
- params->size(), static_cast<OMX_U8 *>(params->pointer()));
-
- if (err != OMX_ErrorNone) {
- LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
-
- delete buffer_meta;
- buffer_meta = NULL;
-
- *buffer = 0;
- return UNKNOWN_ERROR;
- }
-
- *buffer = header;
-
- return OK;
+ return findInstance(node)->useBuffer(
+ port_index, params, buffer);
}
-status_t OMX::allocate_buffer(
+status_t OMX::allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer) {
- Mutex::Autolock autoLock(mLock);
-
- BufferMeta *buffer_meta = new BufferMeta(this, size);
-
- OMX_BUFFERHEADERTYPE *header;
-
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err =
- OMX_AllocateBuffer(node_meta->handle(), &header, port_index,
- buffer_meta, size);
-
- if (err != OMX_ErrorNone) {
- delete buffer_meta;
- buffer_meta = NULL;
-
- *buffer = 0;
- return UNKNOWN_ERROR;
- }
-
- *buffer = header;
-
- return OK;
+ return findInstance(node)->allocateBuffer(
+ port_index, size, buffer);
}
-status_t OMX::allocate_buffer_with_backup(
+status_t OMX::allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
buffer_id *buffer) {
- Mutex::Autolock autoLock(mLock);
-
- BufferMeta *buffer_meta = new BufferMeta(this, params, true);
-
- OMX_BUFFERHEADERTYPE *header;
-
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err =
- OMX_AllocateBuffer(
- node_meta->handle(), &header, port_index, buffer_meta,
- params->size());
-
- if (err != OMX_ErrorNone) {
- delete buffer_meta;
- buffer_meta = NULL;
-
- *buffer = 0;
- return UNKNOWN_ERROR;
- }
-
- *buffer = header;
-
- return OK;
+ return findInstance(node)->allocateBufferWithBackup(
+ port_index, params, buffer);
}
-status_t OMX::free_buffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
- OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
- BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
+ return findInstance(node)->freeBuffer(
+ port_index, buffer);
+}
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
- OMX_ERRORTYPE err =
- OMX_FreeBuffer(node_meta->handle(), port_index, header);
+status_t OMX::fillBuffer(node_id node, buffer_id buffer) {
+ return findInstance(node)->fillBuffer(buffer);
+}
- delete buffer_meta;
- buffer_meta = NULL;
+status_t OMX::emptyBuffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ return findInstance(node)->emptyBuffer(
+ buffer, range_offset, range_length, flags, timestamp);
+}
- return (err != OMX_ErrorNone) ? UNKNOWN_ERROR : OK;
+status_t OMX::getExtensionIndex(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) {
+ return findInstance(node)->getExtensionIndex(
+ parameter_name, index);
}
OMX_ERRORTYPE OMX::OnEvent(
- NodeMeta *meta,
+ node_id node,
OMX_IN OMX_EVENTTYPE eEvent,
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
@@ -475,7 +353,7 @@ OMX_ERRORTYPE OMX::OnEvent(
omx_message msg;
msg.type = omx_message::EVENT;
- msg.node = meta;
+ msg.node = node;
msg.u.event_data.event = eEvent;
msg.u.event_data.data1 = nData1;
msg.u.event_data.data2 = nData2;
@@ -484,14 +362,14 @@ OMX_ERRORTYPE OMX::OnEvent(
return OMX_ErrorNone;
}
-
+
OMX_ERRORTYPE OMX::OnEmptyBufferDone(
- NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+ node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
LOGV("OnEmptyBufferDone buffer=%p", pBuffer);
omx_message msg;
msg.type = omx_message::EMPTY_BUFFER_DONE;
- msg.node = meta;
+ msg.node = node;
msg.u.buffer_data.buffer = pBuffer;
mDispatcher->post(msg);
@@ -500,14 +378,12 @@ OMX_ERRORTYPE OMX::OnEmptyBufferDone(
}
OMX_ERRORTYPE OMX::OnFillBufferDone(
- NodeMeta *meta, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
+ node_id node, OMX_IN OMX_BUFFERHEADERTYPE *pBuffer) {
LOGV("OnFillBufferDone buffer=%p", pBuffer);
- BufferMeta *buffer_meta = static_cast<BufferMeta *>(pBuffer->pAppPrivate);
- buffer_meta->CopyFromOMX(pBuffer);
omx_message msg;
msg.type = omx_message::FILL_BUFFER_DONE;
- msg.node = meta;
+ msg.node = node;
msg.u.extended_buffer_data.buffer = pBuffer;
msg.u.extended_buffer_data.range_offset = pBuffer->nOffset;
msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen;
@@ -520,62 +396,31 @@ OMX_ERRORTYPE OMX::OnFillBufferDone(
return OMX_ErrorNone;
}
-status_t OMX::observe_node(
- node_id node, const sp<IOMXObserver> &observer) {
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
+ // mLock is already held.
- node_meta->setObserver(observer);
+ node_id node = (node_id)++mNodeCounter;
+ mNodeIDToInstance.add(node, instance);
- return OK;
+ return node;
}
-void OMX::fill_buffer(node_id node, buffer_id buffer) {
- OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
- header->nFilledLen = 0;
- header->nOffset = 0;
- header->nFlags = 0;
+OMXNodeInstance *OMX::findInstance(node_id node) {
+ Mutex::Autolock autoLock(mLock);
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
+ ssize_t index = mNodeIDToInstance.indexOfKey(node);
- OMX_ERRORTYPE err =
- OMX_FillThisBuffer(node_meta->handle(), header);
- CHECK_EQ(err, OMX_ErrorNone);
+ return index < 0 ? NULL : mNodeIDToInstance.valueAt(index);
}
-void OMX::empty_buffer(
- node_id node,
- buffer_id buffer,
- OMX_U32 range_offset, OMX_U32 range_length,
- OMX_U32 flags, OMX_TICKS timestamp) {
- OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
- header->nFilledLen = range_length;
- header->nOffset = range_offset;
- header->nFlags = flags;
- header->nTimeStamp = timestamp;
-
- BufferMeta *buffer_meta =
- static_cast<BufferMeta *>(header->pAppPrivate);
- buffer_meta->CopyToOMX(header);
-
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-
- OMX_ERRORTYPE err =
- OMX_EmptyThisBuffer(node_meta->handle(), header);
- CHECK_EQ(err, OMX_ErrorNone);
+void OMX::invalidateNodeID(node_id node) {
+ Mutex::Autolock autoLock(mLock);
+ invalidateNodeID_l(node);
}
-status_t OMX::get_extension_index(
- node_id node,
- const char *parameter_name,
- OMX_INDEXTYPE *index) {
- NodeMeta *node_meta = static_cast<NodeMeta *>(node);
-
- OMX_ERRORTYPE err =
- OMX_GetExtensionIndex(
- node_meta->handle(),
- const_cast<char *>(parameter_name), index);
-
- return err == OMX_ErrorNone ? OK : UNKNOWN_ERROR;
+void OMX::invalidateNodeID_l(node_id node) {
+ // mLock is held.
+ mNodeIDToInstance.removeItem(node);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
new file mode 100644
index 0000000..ab8be53
--- /dev/null
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -0,0 +1,460 @@
+/*
+ * 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 "OMXNodeInstance"
+#include <utils/Log.h>
+
+#include "../include/OMXNodeInstance.h"
+
+#include "pv_omxcore.h"
+
+#include <binder/IMemory.h>
+#include <media/stagefright/MediaDebug.h>
+
+namespace android {
+
+struct BufferMeta {
+ BufferMeta(const sp<IMemory> &mem, bool is_backup = false)
+ : mMem(mem),
+ mIsBackup(is_backup) {
+ }
+
+ BufferMeta(size_t size)
+ : mSize(size),
+ mIsBackup(false) {
+ }
+
+ void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
+ if (!mIsBackup) {
+ return;
+ }
+
+ memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
+ header->pBuffer + header->nOffset,
+ header->nFilledLen);
+ }
+
+ void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
+ if (!mIsBackup) {
+ return;
+ }
+
+ memcpy(header->pBuffer + header->nOffset,
+ (const OMX_U8 *)mMem->pointer() + header->nOffset,
+ header->nFilledLen);
+ }
+
+private:
+ sp<IMemory> mMem;
+ size_t mSize;
+ bool mIsBackup;
+
+ BufferMeta(const BufferMeta &);
+ BufferMeta &operator=(const BufferMeta &);
+};
+
+// static
+OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
+ &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
+};
+
+OMXNodeInstance::OMXNodeInstance(
+ OMX *owner, const sp<IOMXObserver> &observer)
+ : mOwner(owner),
+ mNodeID(NULL),
+ mHandle(NULL),
+ mObserver(observer) {
+}
+
+OMXNodeInstance::~OMXNodeInstance() {
+ CHECK_EQ(mHandle, NULL);
+}
+
+void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
+ CHECK_EQ(mHandle, NULL);
+ mNodeID = node_id;
+ mHandle = handle;
+}
+
+OMX *OMXNodeInstance::owner() {
+ return mOwner;
+}
+
+sp<IOMXObserver> OMXNodeInstance::observer() {
+ return mObserver;
+}
+
+OMX::node_id OMXNodeInstance::nodeID() {
+ return mNodeID;
+}
+
+static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
+ return (err == OMX_ErrorNone) ? OK : UNKNOWN_ERROR;
+}
+
+status_t OMXNodeInstance::freeNode() {
+ // Transition the node from its current state all the way down
+ // to "Loaded".
+ // This ensures that all active buffers are properly freed even
+ // for components that don't do this themselves on a call to
+ // "FreeHandle".
+
+ OMX_STATETYPE state;
+ CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
+ switch (state) {
+ case OMX_StateExecuting:
+ {
+ LOGV("forcing Executing->Idle");
+ sendCommand(OMX_CommandStateSet, OMX_StateIdle);
+ OMX_ERRORTYPE err;
+ while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
+ && state != OMX_StateIdle) {
+ usleep(100000);
+ }
+ CHECK_EQ(err, OMX_ErrorNone);
+
+ // fall through
+ }
+
+ case OMX_StateIdle:
+ {
+ LOGV("forcing Idle->Loaded");
+ sendCommand(OMX_CommandStateSet, OMX_StateLoaded);
+
+ freeActiveBuffers();
+
+ OMX_ERRORTYPE err;
+ while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
+ && state != OMX_StateLoaded) {
+ LOGV("waiting for Loaded state...");
+ usleep(100000);
+ }
+ CHECK_EQ(err, OMX_ErrorNone);
+
+ // fall through
+ }
+
+ case OMX_StateLoaded:
+ break;
+
+ default:
+ CHECK(!"should not be here, unknown state.");
+ break;
+ }
+
+ OMX_ERRORTYPE err = OMX_MasterFreeHandle(mHandle);
+ mHandle = NULL;
+
+ if (err != OMX_ErrorNone) {
+ LOGE("FreeHandle FAILED with error 0x%08x.", err);
+ }
+
+ mOwner->invalidateNodeID(mNodeID);
+ mNodeID = NULL;
+
+ LOGV("OMXNodeInstance going away.");
+ delete this;
+
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::sendCommand(
+ OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::getParameter(
+ OMX_INDEXTYPE index, void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::setParameter(
+ OMX_INDEXTYPE index, const void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_ERRORTYPE err = OMX_SetParameter(
+ mHandle, index, const_cast<void *>(params));
+
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::getConfig(
+ OMX_INDEXTYPE index, void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::setConfig(
+ OMX_INDEXTYPE index, const void *params, size_t size) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_ERRORTYPE err = OMX_SetConfig(
+ mHandle, index, const_cast<void *>(params));
+
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::useBuffer(
+ OMX_U32 portIndex, const sp<IMemory> &params,
+ OMX::buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(params);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ OMX_ERRORTYPE err = OMX_UseBuffer(
+ mHandle, &header, portIndex, buffer_meta,
+ params->size(), static_cast<OMX_U8 *>(params->pointer()));
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ addActiveBuffer(portIndex, *buffer);
+
+ return OK;
+}
+
+status_t OMXNodeInstance::allocateBuffer(
+ OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(size);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ OMX_ERRORTYPE err = OMX_AllocateBuffer(
+ mHandle, &header, portIndex, buffer_meta, size);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ addActiveBuffer(portIndex, *buffer);
+
+ return OK;
+}
+
+status_t OMXNodeInstance::allocateBufferWithBackup(
+ OMX_U32 portIndex, const sp<IMemory> &params,
+ OMX::buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ BufferMeta *buffer_meta = new BufferMeta(params, true);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ OMX_ERRORTYPE err = OMX_AllocateBuffer(
+ mHandle, &header, portIndex, buffer_meta, params->size());
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ *buffer = 0;
+
+ return UNKNOWN_ERROR;
+ }
+
+ *buffer = header;
+
+ addActiveBuffer(portIndex, *buffer);
+
+ return OK;
+}
+
+status_t OMXNodeInstance::freeBuffer(
+ OMX_U32 portIndex, OMX::buffer_id buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ removeActiveBuffer(portIndex, buffer);
+
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
+
+ OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ header->nFilledLen = 0;
+ header->nOffset = 0;
+ header->nFlags = 0;
+
+ OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
+
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::emptyBuffer(
+ OMX::buffer_id buffer,
+ OMX_U32 rangeOffset, OMX_U32 rangeLength,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+ header->nFilledLen = rangeLength;
+ header->nOffset = rangeOffset;
+ header->nFlags = flags;
+ header->nTimeStamp = timestamp;
+
+ BufferMeta *buffer_meta =
+ static_cast<BufferMeta *>(header->pAppPrivate);
+ buffer_meta->CopyToOMX(header);
+
+ OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
+
+ return StatusFromOMXError(err);
+}
+
+status_t OMXNodeInstance::getExtensionIndex(
+ const char *parameterName, OMX_INDEXTYPE *index) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_ERRORTYPE err = OMX_GetExtensionIndex(
+ mHandle, const_cast<char *>(parameterName), index);
+
+ return StatusFromOMXError(err);
+}
+
+void OMXNodeInstance::onMessage(const omx_message &msg) {
+ if (msg.type == omx_message::FILL_BUFFER_DONE) {
+ OMX_BUFFERHEADERTYPE *buffer =
+ static_cast<OMX_BUFFERHEADERTYPE *>(
+ msg.u.extended_buffer_data.buffer);
+
+ BufferMeta *buffer_meta =
+ static_cast<BufferMeta *>(buffer->pAppPrivate);
+
+ buffer_meta->CopyFromOMX(buffer);
+ }
+
+ mObserver->onMessage(msg);
+}
+
+void OMXNodeInstance::onObserverDied() {
+ LOGE("!!! Observer died. Quickly, do something, ... anything...");
+
+ // Try to force shutdown of the node and hope for the best.
+ freeNode();
+}
+
+void OMXNodeInstance::onGetHandleFailed() {
+ delete this;
+}
+
+// static
+OMX_ERRORTYPE OMXNodeInstance::OnEvent(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_EVENTTYPE eEvent,
+ OMX_IN OMX_U32 nData1,
+ OMX_IN OMX_U32 nData2,
+ OMX_IN OMX_PTR pEventData) {
+ OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
+ return instance->owner()->OnEvent(
+ instance->nodeID(), eEvent, nData1, nData2, pEventData);
+}
+
+// static
+OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
+ return instance->owner()->OnEmptyBufferDone(instance->nodeID(), pBuffer);
+}
+
+// static
+OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
+ OMX_IN OMX_HANDLETYPE hComponent,
+ OMX_IN OMX_PTR pAppData,
+ OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
+ return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer);
+}
+
+void OMXNodeInstance::addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id) {
+ ActiveBuffer active;
+ active.mPortIndex = portIndex;
+ active.mID = id;
+ mActiveBuffers.push(active);
+}
+
+void OMXNodeInstance::removeActiveBuffer(
+ OMX_U32 portIndex, OMX::buffer_id id) {
+ bool found = false;
+ for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
+ if (mActiveBuffers[i].mPortIndex == portIndex
+ && mActiveBuffers[i].mID == id) {
+ found = true;
+ mActiveBuffers.removeItemsAt(i);
+ break;
+ }
+ }
+
+ if (!found) {
+ LOGW("Attempt to remove an active buffer we know nothing about...");
+ }
+}
+
+void OMXNodeInstance::freeActiveBuffers() {
+ // Make sure to count down here, as freeBuffer will in turn remove
+ // the active buffer from the vector...
+ for (size_t i = mActiveBuffers.size(); i--;) {
+ freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
+ }
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/omx/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
index 7dc368f..8e78c77 100644
--- a/media/libstagefright/omx/QComHardwareRenderer.cpp
+++ b/media/libstagefright/omx/QComHardwareRenderer.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
+#include "../include/QComHardwareRenderer.h"
+
#include <binder/MemoryHeapBase.h>
#include <binder/MemoryHeapPmem.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/QComHardwareRenderer.h>
#include <ui/ISurface.h>
namespace android {
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index 4ed6869..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 %ld", 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/omx/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
index ebade4a..6dde86a 100644
--- a/media/libstagefright/omx/TIHardwareRenderer.cpp
+++ b/media/libstagefright/omx/TIHardwareRenderer.cpp
@@ -17,7 +17,8 @@
#define LOG_TAG "TIHardwareRenderer"
#include <utils/Log.h>
-#include <media/stagefright/TIHardwareRenderer.h>
+#include "../include/TIHardwareRenderer.h"
+
#include <media/stagefright/MediaDebug.h>
#include <ui/ISurface.h>
#include <ui/Overlay.h>
diff --git a/media/libstagefright/string.cpp b/media/libstagefright/string.cpp
index 5b16784..bd6204b 100644
--- a/media/libstagefright/string.cpp
+++ b/media/libstagefright/string.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/string.h>
+#include "include/stagefright_string.h"
namespace android {