manual merge

Change-Id: I9cdacbf1e445e7f6cf06ad03df541a744c242774
This commit is contained in:
Jean-Baptiste Queru
2010-04-12 15:32:13 -07:00
16 changed files with 401 additions and 162 deletions

View File

@@ -27062,19 +27062,6 @@
deprecated="not deprecated" deprecated="not deprecated"
visibility="public" visibility="public"
> >
<method name="setKeyPrefix"
return="void"
abstract="false"
native="false"
synchronized="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
<parameter name="keyPrefix" type="java.lang.String">
</parameter>
</method>
<method name="writeEntityData" <method name="writeEntityData"
return="int" return="int"
abstract="false" abstract="false"
@@ -27109,28 +27096,6 @@
<exception name="IOException" type="java.io.IOException"> <exception name="IOException" type="java.io.IOException">
</exception> </exception>
</method> </method>
<field name="OP_DELETE"
type="int"
transient="false"
volatile="false"
value="2"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="OP_UPDATE"
type="int"
transient="false"
volatile="false"
value="1"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
</class> </class>
<interface name="BackupHelper" <interface name="BackupHelper"
abstract="true" abstract="true"

View File

@@ -147,7 +147,7 @@ int main(int argc, char **argv) {
OMXClient client; OMXClient client;
CHECK_EQ(client.connect(), OK); CHECK_EQ(client.connect(), OK);
#if 1 #if 0
sp<MediaSource> source = createSource(argv[1]); sp<MediaSource> source = createSource(argv[1]);
if (source == NULL) { if (source == NULL) {
@@ -165,14 +165,15 @@ int main(int argc, char **argv) {
success = success && meta->findInt32(kKeyHeight, &height); success = success && meta->findInt32(kKeyHeight, &height);
CHECK(success); CHECK(success);
#else #else
int width = 800; int width = 720;
int height = 480; int height = 480;
sp<MediaSource> decoder = new DummySource(width, height); sp<MediaSource> decoder = new DummySource(width, height);
#endif #endif
sp<MetaData> enc_meta = new MetaData; sp<MetaData> enc_meta = new MetaData;
// enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
enc_meta->setInt32(kKeyWidth, width); enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height); enc_meta->setInt32(kKeyHeight, height);
@@ -213,6 +214,8 @@ int main(int argc, char **argv) {
#if 0 #if 0
CameraSource *source = CameraSource::Create(); CameraSource *source = CameraSource::Create();
source->start();
printf("source = %p\n", source); printf("source = %p\n", source);
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
@@ -227,6 +230,8 @@ int main(int argc, char **argv) {
buffer = NULL; buffer = NULL;
} }
source->stop();
delete source; delete source;
source = NULL; source = NULL;
#endif #endif

View File

@@ -25,9 +25,6 @@ import java.io.IOException;
public class BackupDataOutput { public class BackupDataOutput {
int mBackupWriter; int mBackupWriter;
public static final int OP_UPDATE = 1;
public static final int OP_DELETE = 2;
/** @hide */ /** @hide */
public BackupDataOutput(FileDescriptor fd) { public BackupDataOutput(FileDescriptor fd) {
if (fd == null) throw new NullPointerException(); if (fd == null) throw new NullPointerException();
@@ -71,6 +68,7 @@ public class BackupDataOutput {
} }
} }
/** @hide */
public void setKeyPrefix(String keyPrefix) { public void setKeyPrefix(String keyPrefix) {
setKeyPrefix_native(mBackupWriter, keyPrefix); setKeyPrefix_native(mBackupWriter, keyPrefix);
} }

View File

@@ -574,7 +574,9 @@ public class Browser {
} }
/** /**
* Request all icons from the database. * Request all icons from the database. This call must either be called
* in the main thread or have had Looper.prepare() invoked in the calling
* thread.
* Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS}
* @param cr The ContentResolver used to access the database. * @param cr The ContentResolver used to access the database.
* @param where Clause to be used to limit the query from the database. * @param where Clause to be used to limit the query from the database.
@@ -584,25 +586,8 @@ public class Browser {
*/ */
public static final void requestAllIcons(ContentResolver cr, String where, public static final void requestAllIcons(ContentResolver cr, String where,
WebIconDatabase.IconListener listener) { WebIconDatabase.IconListener listener) {
Cursor c = null; WebIconDatabase.getInstance()
try { .bulkRequestIconForPageUrl(cr, where, listener);
c = cr.query(
BOOKMARKS_URI,
new String[] { BookmarkColumns.URL },
where, null, null);
if (c.moveToFirst()) {
final WebIconDatabase db = WebIconDatabase.getInstance();
do {
db.requestIconForPageUrl(c.getString(0), listener);
} while (c.moveToNext());
}
} catch (IllegalStateException e) {
Log.e(LOGTAG, "requestAllIcons", e);
} finally {
if (c != null) {
c.close();
}
}
} }
public static class BookmarkColumns implements BaseColumns { public static class BookmarkColumns implements BaseColumns {

View File

@@ -16,10 +16,15 @@
package android.webkit; package android.webkit;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.graphics.Bitmap; import android.provider.Browser;
import android.util.Log;
import java.util.HashMap;
import java.util.Vector; import java.util.Vector;
/** /**
@@ -30,6 +35,7 @@ import java.util.Vector;
* single object. * single object.
*/ */
public final class WebIconDatabase { public final class WebIconDatabase {
private static final String LOGTAG = "WebIconDatabase";
// Global instance of a WebIconDatabase // Global instance of a WebIconDatabase
private static WebIconDatabase sIconDatabase; private static WebIconDatabase sIconDatabase;
// EventHandler for handling messages before and after the WebCore thread is // EventHandler for handling messages before and after the WebCore thread is
@@ -45,6 +51,7 @@ public final class WebIconDatabase {
static final int REQUEST_ICON = 3; static final int REQUEST_ICON = 3;
static final int RETAIN_ICON = 4; static final int RETAIN_ICON = 4;
static final int RELEASE_ICON = 5; static final int RELEASE_ICON = 5;
static final int BULK_REQUEST_ICON = 6;
// Message for dispatching icon request results // Message for dispatching icon request results
private static final int ICON_RESULT = 10; private static final int ICON_RESULT = 10;
// Actual handler that runs in WebCore thread // Actual handler that runs in WebCore thread
@@ -100,12 +107,11 @@ public final class WebIconDatabase {
case REQUEST_ICON: case REQUEST_ICON:
IconListener l = (IconListener) msg.obj; IconListener l = (IconListener) msg.obj;
String url = msg.getData().getString("url"); String url = msg.getData().getString("url");
Bitmap icon = nativeIconForPageUrl(url); requestIconAndSendResult(url, l);
if (icon != null) { break;
EventHandler.this.sendMessage(
Message.obtain(null, ICON_RESULT, case BULK_REQUEST_ICON:
new IconResult(url, icon, l))); bulkRequestIcons(msg);
}
break; break;
case RETAIN_ICON: case RETAIN_ICON:
@@ -126,6 +132,10 @@ public final class WebIconDatabase {
} }
} }
private synchronized boolean hasHandler() {
return mHandler != null;
}
private synchronized void postMessage(Message msg) { private synchronized void postMessage(Message msg) {
if (mMessages != null) { if (mMessages != null) {
mMessages.add(msg); mMessages.add(msg);
@@ -133,6 +143,39 @@ public final class WebIconDatabase {
mHandler.sendMessage(msg); mHandler.sendMessage(msg);
} }
} }
private void bulkRequestIcons(Message msg) {
HashMap map = (HashMap) msg.obj;
IconListener listener = (IconListener) map.get("listener");
ContentResolver cr = (ContentResolver) map.get("contentResolver");
String where = (String) map.get("where");
Cursor c = null;
try {
c = cr.query(
Browser.BOOKMARKS_URI,
new String[] { Browser.BookmarkColumns.URL },
where, null, null);
if (c.moveToFirst()) {
do {
String url = c.getString(0);
requestIconAndSendResult(url, listener);
} while (c.moveToNext());
}
} catch (IllegalStateException e) {
Log.e(LOGTAG, "BulkRequestIcons", e);
} finally {
if (c != null) c.close();
}
}
private void requestIconAndSendResult(String url, IconListener listener) {
Bitmap icon = nativeIconForPageUrl(url);
if (icon != null) {
sendMessage(obtainMessage(ICON_RESULT,
new IconResult(url, icon, listener)));
}
}
} }
/** /**
@@ -192,6 +235,30 @@ public final class WebIconDatabase {
mEventHandler.postMessage(msg); mEventHandler.postMessage(msg);
} }
/** {@hide}
*/
public void bulkRequestIconForPageUrl(ContentResolver cr, String where,
IconListener listener) {
if (listener == null) {
return;
}
// Special case situation: we don't want to add this message to the
// queue if there is no handler because we may never have a real
// handler to service the messages and the cursor will never get
// closed.
if (mEventHandler.hasHandler()) {
// Don't use Bundle as it is parcelable.
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("contentResolver", cr);
map.put("where", where);
map.put("listener", listener);
Message msg =
Message.obtain(null, EventHandler.BULK_REQUEST_ICON, map);
mEventHandler.postMessage(msg);
}
}
/** /**
* Retain the icon for the given page url. * Retain the icon for the given page url.
* @param url The page's url. * @param url The page's url.

View File

@@ -116,7 +116,7 @@ screen. </p>
generalized densities: high, medium, and low. Applications can provide custom generalized densities: high, medium, and low. Applications can provide custom
resources for each of these three densities &mdash; the platform handles the resources for each of these three densities &mdash; the platform handles the
scaling of the resources up or down to meet the actual screen density. </p></dd> scaling of the resources up or down to meet the actual screen density. </p></dd>
<dt><em>Density independent pixel (dip)</em></dt> <dt><em>Density-independent pixel (dip)</em></dt>
<dd>A virtual pixel unit that applications can use in defining their UI, to <dd>A virtual pixel unit that applications can use in defining their UI, to
express layout dimensions or position in a density-independent way. express layout dimensions or position in a density-independent way.
<p>The density-independent pixel is equivalent to one physical pixel on a 160 <p>The density-independent pixel is equivalent to one physical pixel on a 160
@@ -432,7 +432,7 @@ does this in three ways: </p>
<ul> <ul>
<li>Through pre-scaling of drawable resources (scaled at resource loading <li>Through pre-scaling of drawable resources (scaled at resource loading
time)</li> time)</li>
<li>Through auto-scaling of device-independent pixel (dip) values used in <li>Through auto-scaling of density-independent pixel (dip) values used in
layouts</li> layouts</li>
<li>Through auto-scaling of absolute pixel values used in the application (only <li>Through auto-scaling of absolute pixel values used in the application (only
needed if the application has set <code>android:anyDensity="false"</code> in its needed if the application has set <code>android:anyDensity="false"</code> in its
@@ -573,7 +573,7 @@ installing the application on small-screen devices. </li>
are signaling to the platform that your application wants to manage its UI by are signaling to the platform that your application wants to manage its UI by
itself, for all screen densities, using the actual screen dimensions and pixels. itself, for all screen densities, using the actual screen dimensions and pixels.
In this case, the application must ensure that it declares its UI dimensions In this case, the application must ensure that it declares its UI dimensions
using device-independent pixels and scales any actual pixel values or math by using density-independent pixels and scales any actual pixel values or math by
the scaling factor available from the scaling factor available from
{@link android.util.DisplayMetrics#density android.util.DisplayMetrics.density}.</p> {@link android.util.DisplayMetrics#density android.util.DisplayMetrics.density}.</p>

View File

@@ -42,14 +42,12 @@ protected:
virtual ~AMRWriter(); virtual ~AMRWriter();
private: private:
Mutex mLock;
FILE *mFile; FILE *mFile;
status_t mInitCheck; status_t mInitCheck;
sp<MediaSource> mSource; sp<MediaSource> mSource;
bool mStarted; bool mStarted;
volatile bool mDone; volatile bool mDone;
bool mReachedEOS; volatile bool mReachedEOS;
pthread_t mThread; pthread_t mThread;
static void *ThreadWrapper(void *); static void *ThreadWrapper(void *);

View File

@@ -2090,14 +2090,18 @@ public class AudioService extends IAudioService.Stub {
Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId);
// this will take care of notifying the new focus owner if needed // this will take care of notifying the new focus owner if needed
removeFocusStackEntry(clientId, true); synchronized(mFocusStack) {
removeFocusStackEntry(clientId, true);
}
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
} }
public void unregisterAudioFocusClient(String clientId) { public void unregisterAudioFocusClient(String clientId) {
removeFocusStackEntry(clientId, false); synchronized(mFocusStack) {
removeFocusStackEntry(clientId, false);
}
} }

View File

@@ -228,14 +228,10 @@ MediaPlayerService::~MediaPlayerService()
sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid) sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
{ {
#ifndef NO_OPENCORE
sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid); sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
wp<MediaRecorderClient> w = recorder; wp<MediaRecorderClient> w = recorder;
Mutex::Autolock lock(mLock); Mutex::Autolock lock(mLock);
mMediaRecorderClients.add(w); mMediaRecorderClients.add(w);
#else
sp<MediaRecorderClient> recorder = NULL;
#endif
LOGV("Create new media recorder client from pid %d", pid); LOGV("Create new media recorder client from pid %d", pid);
return recorder; return recorder;
} }

View File

@@ -53,8 +53,6 @@ status_t AMRWriter::initCheck() const {
} }
status_t AMRWriter::addSource(const sp<MediaSource> &source) { status_t AMRWriter::addSource(const sp<MediaSource> &source) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) { if (mInitCheck != OK) {
return mInitCheck; return mInitCheck;
} }
@@ -95,8 +93,6 @@ status_t AMRWriter::addSource(const sp<MediaSource> &source) {
} }
status_t AMRWriter::start() { status_t AMRWriter::start() {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) { if (mInitCheck != OK) {
return mInitCheck; return mInitCheck;
} }
@@ -127,16 +123,12 @@ status_t AMRWriter::start() {
} }
void AMRWriter::stop() { void AMRWriter::stop() {
{ if (!mStarted) {
Mutex::Autolock autoLock(mLock); return;
if (!mStarted) {
return;
}
mDone = true;
} }
mDone = true;
void *dummy; void *dummy;
pthread_join(mThread, &dummy); pthread_join(mThread, &dummy);
@@ -153,13 +145,7 @@ void *AMRWriter::ThreadWrapper(void *me) {
} }
void AMRWriter::threadFunc() { void AMRWriter::threadFunc() {
for (;;) { while (!mDone) {
Mutex::Autolock autoLock(mLock);
if (mDone) {
break;
}
MediaBuffer *buffer; MediaBuffer *buffer;
status_t err = mSource->read(&buffer); status_t err = mSource->read(&buffer);
@@ -184,12 +170,10 @@ void AMRWriter::threadFunc() {
buffer = NULL; buffer = NULL;
} }
Mutex::Autolock autoLock(mLock);
mReachedEOS = true; mReachedEOS = true;
} }
bool AMRWriter::reachedEOS() { bool AMRWriter::reachedEOS() {
Mutex::Autolock autoLock(mLock);
return mReachedEOS; return mReachedEOS;
} }

View File

@@ -142,13 +142,6 @@ CameraSource::CameraSource(const sp<Camera> &camera)
mFirstFrameTimeUs(0), mFirstFrameTimeUs(0),
mNumFrames(0), mNumFrames(0),
mStarted(false) { mStarted(false) {
char value[PROPERTY_VALUE_MAX];
if (property_get("ro.hardware", value, NULL) && !strcmp(value, "sholes")) {
// The hardware encoder(s) do not support yuv420, but only YCbYCr,
// fortunately the camera also supports this, so we needn't transcode.
mCamera->setParameters(String8("preview-format=yuv422i-yuyv"));
}
String8 s = mCamera->getParameters(); String8 s = mCamera->getParameters();
printf("params: \"%s\"\n", s.string()); printf("params: \"%s\"\n", s.string());

View File

@@ -24,6 +24,7 @@
#include <media/stagefright/MetaData.h> #include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDebug.h> #include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h> #include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h> #include <media/stagefright/Utils.h>
@@ -59,16 +60,22 @@ private:
void *mCodecSpecificData; void *mCodecSpecificData;
size_t mCodecSpecificDataSize; size_t mCodecSpecificDataSize;
bool mGotAllCodecSpecificData;
bool mReachedEOS; bool mReachedEOS;
static void *ThreadWrapper(void *me); static void *ThreadWrapper(void *me);
void threadEntry(); void threadEntry();
status_t makeAVCCodecSpecificData(
const uint8_t *data, size_t size);
Track(const Track &); Track(const Track &);
Track &operator=(const Track &); Track &operator=(const Track &);
}; };
#define USE_NALLEN_FOUR 1
MPEG4Writer::MPEG4Writer(const char *filename) MPEG4Writer::MPEG4Writer(const char *filename)
: mFile(fopen(filename, "wb")), : mFile(fopen(filename, "wb")),
mOffset(0), mOffset(0),
@@ -213,23 +220,55 @@ off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
return old_offset; return old_offset;
} }
static void StripStartcode(MediaBuffer *buffer) {
if (buffer->range_length() < 4) {
return;
}
const uint8_t *ptr =
(const uint8_t *)buffer->data() + buffer->range_offset();
if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
buffer->set_range(
buffer->range_offset() + 4, buffer->range_length() - 4);
}
}
off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) { off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) {
Mutex::Autolock autoLock(mLock); Mutex::Autolock autoLock(mLock);
StripStartcode(buffer);
off_t old_offset = mOffset; off_t old_offset = mOffset;
size_t length = buffer->range_length(); size_t length = buffer->range_length();
#if USE_NALLEN_FOUR
uint8_t x = length >> 24;
fwrite(&x, 1, 1, mFile);
x = (length >> 16) & 0xff;
fwrite(&x, 1, 1, mFile);
x = (length >> 8) & 0xff;
fwrite(&x, 1, 1, mFile);
x = length & 0xff;
fwrite(&x, 1, 1, mFile);
#else
CHECK(length < 65536); CHECK(length < 65536);
uint8_t x = length >> 8; uint8_t x = length >> 8;
fwrite(&x, 1, 1, mFile); fwrite(&x, 1, 1, mFile);
x = length & 0xff; x = length & 0xff;
fwrite(&x, 1, 1, mFile); fwrite(&x, 1, 1, mFile);
#endif
fwrite((const uint8_t *)buffer->data() + buffer->range_offset(), fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
1, length, mFile); 1, length, mFile);
#if USE_NALLEN_FOUR
mOffset += length + 4;
#else
mOffset += length + 2; mOffset += length + 2;
#endif
return old_offset; return old_offset;
} }
@@ -320,6 +359,7 @@ MPEG4Writer::Track::Track(
mMaxTimeStampUs(0), mMaxTimeStampUs(0),
mCodecSpecificData(NULL), mCodecSpecificData(NULL),
mCodecSpecificDataSize(0), mCodecSpecificDataSize(0),
mGotAllCodecSpecificData(false),
mReachedEOS(false) { mReachedEOS(false) {
} }
@@ -380,6 +420,104 @@ void *MPEG4Writer::Track::ThreadWrapper(void *me) {
return NULL; return NULL;
} }
#include <ctype.h>
static void hexdump(const void *_data, size_t size) {
const uint8_t *data = (const uint8_t *)_data;
size_t offset = 0;
while (offset < size) {
printf("0x%04x ", offset);
size_t n = size - offset;
if (n > 16) {
n = 16;
}
for (size_t i = 0; i < 16; ++i) {
if (i == 8) {
printf(" ");
}
if (offset + i < size) {
printf("%02x ", data[offset + i]);
} else {
printf(" ");
}
}
printf(" ");
for (size_t i = 0; i < n; ++i) {
if (isprint(data[offset + i])) {
printf("%c", data[offset + i]);
} else {
printf(".");
}
}
printf("\n");
offset += 16;
}
}
status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
const uint8_t *data, size_t size) {
// hexdump(data, size);
if (mCodecSpecificData != NULL) {
LOGE("Already have codec specific data");
return ERROR_MALFORMED;
}
if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
LOGE("Must start with a start code");
return ERROR_MALFORMED;
}
size_t picParamOffset = 4;
while (picParamOffset + 3 < size
&& memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
++picParamOffset;
}
if (picParamOffset + 3 >= size) {
LOGE("Could not find start-code for pictureParameterSet");
return ERROR_MALFORMED;
}
size_t seqParamSetLength = picParamOffset - 4;
size_t picParamSetLength = size - picParamOffset - 4;
mCodecSpecificDataSize =
6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
mCodecSpecificData = malloc(mCodecSpecificDataSize);
uint8_t *header = (uint8_t *)mCodecSpecificData;
header[0] = 1;
header[1] = 0x42; // profile
header[2] = 0x80;
header[3] = 0x1e; // level
#if USE_NALLEN_FOUR
header[4] = 0xfc | 3; // length size == 4 bytes
#else
header[4] = 0xfc | 1; // length size == 2 bytes
#endif
header[5] = 0xe0 | 1;
header[6] = seqParamSetLength >> 8;
header[7] = seqParamSetLength & 0xff;
memcpy(&header[8], &data[4], seqParamSetLength);
header += 8 + seqParamSetLength;
header[0] = 1;
header[1] = picParamSetLength >> 8;
header[2] = picParamSetLength & 0xff;
memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
return OK;
}
void MPEG4Writer::Track::threadEntry() { void MPEG4Writer::Track::threadEntry() {
sp<MetaData> meta = mSource->getFormat(); sp<MetaData> meta = mSource->getFormat();
const char *mime; const char *mime;
@@ -399,54 +537,40 @@ void MPEG4Writer::Track::threadEntry() {
++count; ++count;
if (is_avc && count < 3) { int32_t isCodecConfig;
size_t size = buffer->range_length(); if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
&& isCodecConfig) {
CHECK(!mGotAllCodecSpecificData);
switch (count) { if (is_avc) {
case 1: status_t err = makeAVCCodecSpecificData(
{ (const uint8_t *)buffer->data()
CHECK_EQ(mCodecSpecificData, NULL); + buffer->range_offset(),
mCodecSpecificData = malloc(size + 8); buffer->range_length());
uint8_t *header = (uint8_t *)mCodecSpecificData;
header[0] = 1;
header[1] = 0x42; // profile
header[2] = 0x80;
header[3] = 0x1e; // level
header[4] = 0xfc | 3;
header[5] = 0xe0 | 1;
header[6] = size >> 8;
header[7] = size & 0xff;
memcpy(&header[8],
(const uint8_t *)buffer->data() + buffer->range_offset(),
size);
mCodecSpecificDataSize = size + 8; if (err != OK) {
break; LOGE("failed to parse avc codec specific data.");
}
case 2:
{
size_t offset = mCodecSpecificDataSize;
mCodecSpecificDataSize += size + 3;
mCodecSpecificData = realloc(mCodecSpecificData, mCodecSpecificDataSize);
uint8_t *header = (uint8_t *)mCodecSpecificData;
header[offset] = 1;
header[offset + 1] = size >> 8;
header[offset + 2] = size & 0xff;
memcpy(&header[offset + 3],
(const uint8_t *)buffer->data() + buffer->range_offset(),
size);
break; break;
} }
} else if (is_mpeg4) {
mCodecSpecificDataSize = buffer->range_length();
mCodecSpecificData = malloc(mCodecSpecificDataSize);
memcpy(mCodecSpecificData,
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
buffer->range_length());
} }
buffer->release(); buffer->release();
buffer = NULL; buffer = NULL;
mGotAllCodecSpecificData = true;
continue; continue;
} } else if (!mGotAllCodecSpecificData &&
count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
// The TI mpeg4 encoder does not properly set the
// codec-specific-data flag.
if (mCodecSpecificData == NULL && is_mpeg4) {
const uint8_t *data = const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset(); (const uint8_t *)buffer->data() + buffer->range_offset();
@@ -474,13 +598,74 @@ void MPEG4Writer::Track::threadEntry() {
memcpy(mCodecSpecificData, data, offset); memcpy(mCodecSpecificData, data, offset);
buffer->set_range(buffer->range_offset() + offset, size - offset); buffer->set_range(buffer->range_offset() + offset, size - offset);
if (size == offset) {
buffer->release();
buffer = NULL;
continue;
}
mGotAllCodecSpecificData = true;
} else if (!mGotAllCodecSpecificData && is_avc && count < 3) {
// The TI video encoder does not flag codec specific data
// as such and also splits up SPS and PPS across two buffers.
const uint8_t *data =
(const uint8_t *)buffer->data() + buffer->range_offset();
size_t size = buffer->range_length();
CHECK(count == 2 || mCodecSpecificData == NULL);
size_t offset = mCodecSpecificDataSize;
mCodecSpecificDataSize += size + 4;
mCodecSpecificData =
realloc(mCodecSpecificData, mCodecSpecificDataSize);
memcpy((uint8_t *)mCodecSpecificData + offset,
"\x00\x00\x00\x01", 4);
memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
buffer->release();
buffer = NULL;
if (count == 2) {
void *tmp = mCodecSpecificData;
size = mCodecSpecificDataSize;
mCodecSpecificData = NULL;
mCodecSpecificDataSize = 0;
status_t err = makeAVCCodecSpecificData(
(const uint8_t *)tmp, size);
free(tmp);
tmp = NULL;
if (err != OK) {
LOGE("failed to parse avc codec specific data.");
break;
}
mGotAllCodecSpecificData = true;
}
continue;
} }
off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer) off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer)
: mOwner->addSample(buffer); : mOwner->addSample(buffer);
SampleInfo info; SampleInfo info;
info.size = is_avc ? buffer->range_length() + 2 : buffer->range_length(); info.size = is_avc
#if USE_NALLEN_FOUR
? buffer->range_length() + 4
#else
? buffer->range_length() + 2
#endif
: buffer->range_length();
info.offset = offset; info.offset = offset;
int64_t timestampUs; int64_t timestampUs;
@@ -733,19 +918,29 @@ void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
mOwner->beginBox("stts"); mOwner->beginBox("stts");
mOwner->writeInt32(0); // version=0, flags=0 mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt32(mSampleInfos.size() - 1); mOwner->writeInt32(mSampleInfos.size());
List<SampleInfo>::iterator it = mSampleInfos.begin(); List<SampleInfo>::iterator it = mSampleInfos.begin();
int64_t last = (*it).timestamp; int64_t last = (*it).timestamp;
int64_t lastDuration = 1;
++it; ++it;
while (it != mSampleInfos.end()) { while (it != mSampleInfos.end()) {
mOwner->writeInt32(1); mOwner->writeInt32(1);
mOwner->writeInt32((*it).timestamp - last); lastDuration = (*it).timestamp - last;
mOwner->writeInt32(lastDuration);
last = (*it).timestamp; last = (*it).timestamp;
++it; ++it;
} }
// We don't really know how long the last frame lasts, since
// there is no frame time after it, just repeat the previous
// frame's duration.
mOwner->writeInt32(1);
mOwner->writeInt32(lastDuration);
mOwner->endBox(); // stts mOwner->endBox(); // stts
mOwner->beginBox("stsz"); mOwner->beginBox("stsz");

View File

@@ -137,6 +137,7 @@ static const CodecInfo kEncoderInfo[] = {
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
{ MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
}; };
@@ -679,6 +680,7 @@ static size_t getFrameSize(
case OMX_COLOR_FormatCbYCrY: case OMX_COLOR_FormatCbYCrY:
return width * height * 2; return width * height * 2;
case OMX_COLOR_FormatYUV420Planar:
case OMX_COLOR_FormatYUV420SemiPlanar: case OMX_COLOR_FormatYUV420SemiPlanar:
return (width * height * 3) / 2; return (width * height * 3) / 2;
@@ -706,7 +708,7 @@ void OMXCodec::setVideoInputFormat(
OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar; OMX_COLOR_FORMATTYPE colorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) { if (!strcasecmp("OMX.TI.Video.encoder", mComponentName)) {
colorFormat = OMX_COLOR_FormatYCbYCr; colorFormat = OMX_COLOR_FormatYUV420Planar;
} }
CHECK_EQ(setVideoPortFormatType( CHECK_EQ(setVideoPortFormatType(
@@ -764,6 +766,14 @@ void OMXCodec::setVideoInputFormat(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
switch (compressionFormat) { switch (compressionFormat) {
case OMX_VIDEO_CodingMPEG4: case OMX_VIDEO_CodingMPEG4:
{ {
@@ -911,7 +921,7 @@ status_t OMXCodec::setupAVCEncoderParameters() {
CHECK_EQ(err, OK); CHECK_EQ(err, OK);
bitrateType.eControlRate = OMX_Video_ControlRateVariable; bitrateType.eControlRate = OMX_Video_ControlRateVariable;
bitrateType.nTargetBitrate = 1000000; bitrateType.nTargetBitrate = 3000000;
err = mOMX->setParameter( err = mOMX->setParameter(
mNode, OMX_IndexParamVideoBitrate, mNode, OMX_IndexParamVideoBitrate,
@@ -2068,7 +2078,13 @@ void OMXCodec::fillOutputBuffer(BufferInfo *info) {
CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer); CODEC_LOGV("Calling fill_buffer on buffer %p", info->mBuffer);
status_t err = mOMX->fillBuffer(mNode, info->mBuffer); status_t err = mOMX->fillBuffer(mNode, info->mBuffer);
CHECK_EQ(err, OK);
if (err != OK) {
CODEC_LOGE("fillBuffer failed w/ error 0x%08x", err);
setState(ERROR);
return;
}
info->mOwnedByComponent = true; info->mOwnedByComponent = true;
} }

View File

@@ -19,6 +19,7 @@
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
#include <stdint.h> #include <stdint.h>
//#define LOG_NDEBUG 0
#define LOG_TAG "TimedEventQueue" #define LOG_TAG "TimedEventQueue"
#include <utils/Log.h> #include <utils/Log.h>
@@ -169,6 +170,8 @@ void TimedEventQueue::cancelEvents(
mQueueHeadChangedCondition.signal(); mQueueHeadChangedCondition.signal();
} }
LOGV("cancelling event %d", (*it).event->eventID());
(*it).event->setEventID(0); (*it).event->setEventID(0);
it = mQueue.erase(it); it = mQueue.erase(it);
@@ -229,14 +232,16 @@ void TimedEventQueue::threadEntry() {
mQueueNotEmptyCondition.wait(mLock); mQueueNotEmptyCondition.wait(mLock);
} }
List<QueueItem>::iterator it; event_id eventID = 0;
for (;;) { for (;;) {
if (mQueue.empty()) { if (mQueue.empty()) {
// The only event in the queue could have been cancelled // The only event in the queue could have been cancelled
// while we were waiting for its scheduled time. // while we were waiting for its scheduled time.
break; break;
} }
it = mQueue.begin();
List<QueueItem>::iterator it = mQueue.begin();
eventID = (*it).event->eventID();
now_us = getRealTimeUs(); now_us = getRealTimeUs();
int64_t when_us = (*it).realtime_us; int64_t when_us = (*it).realtime_us;
@@ -276,19 +281,39 @@ void TimedEventQueue::threadEntry() {
} }
} }
if (mQueue.empty()) { // The event w/ this id may have been cancelled while we're
continue; // waiting for its trigger-time, in that case
} // removeEventFromQueue_l will return NULL.
// Otherwise, the QueueItem will be removed
event = (*it).event; // from the queue and the referenced event returned.
event->setEventID(0); event = removeEventFromQueue_l(eventID);
mQueue.erase(it);
} }
// Fire event with the lock NOT held. if (event != NULL) {
event->fire(this, now_us); // Fire event with the lock NOT held.
event->fire(this, now_us);
}
} }
} }
sp<TimedEventQueue::Event> TimedEventQueue::removeEventFromQueue_l(
event_id id) {
for (List<QueueItem>::iterator it = mQueue.begin();
it != mQueue.end(); ++it) {
if ((*it).event->eventID() == id) {
sp<Event> event = (*it).event;
event->setEventID(0);
mQueue.erase(it);
return event;
}
}
LOGW("Event %d was not found in the queue, already cancelled?", id);
return NULL;
}
} // namespace android } // namespace android

View File

@@ -121,6 +121,8 @@ private:
static void *ThreadWrapper(void *me); static void *ThreadWrapper(void *me);
void threadEntry(); void threadEntry();
sp<Event> removeEventFromQueue_l(event_id id);
TimedEventQueue(const TimedEventQueue &); TimedEventQueue(const TimedEventQueue &);
TimedEventQueue &operator=(const TimedEventQueue &); TimedEventQueue &operator=(const TimedEventQueue &);
}; };

View File

@@ -264,6 +264,8 @@ status_t OMXNodeInstance::useBuffer(
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
CHECK_EQ(header->pAppPrivate, buffer_meta);
*buffer = header; *buffer = header;
addActiveBuffer(portIndex, *buffer); addActiveBuffer(portIndex, *buffer);
@@ -294,6 +296,8 @@ status_t OMXNodeInstance::allocateBuffer(
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
CHECK_EQ(header->pAppPrivate, buffer_meta);
*buffer = header; *buffer = header;
*buffer_data = header->pBuffer; *buffer_data = header->pBuffer;
@@ -325,6 +329,8 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
CHECK_EQ(header->pAppPrivate, buffer_meta);
*buffer = header; *buffer = header;
addActiveBuffer(portIndex, *buffer); addActiveBuffer(portIndex, *buffer);