Merge "mv libcpustats from frameworks/base to /native"
diff --git a/api/current.txt b/api/current.txt
index bebbf36..2a64ee1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11924,8 +11924,10 @@
method public java.lang.String[] getDefaultCipherSuites();
method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache);
+ method public byte[] getNpnSelectedProtocol(java.net.Socket);
method public java.lang.String[] getSupportedCipherSuites();
method public void setKeyManagers(javax.net.ssl.KeyManager[]);
+ method public void setNpnProtocols(byte[][]);
method public void setTrustManagers(javax.net.ssl.TrustManager[]);
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 7f94a96..c2c749a 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -332,12 +332,15 @@
ret = 0;
// Make the /data/user directory if necessary
if (access(user_data_dir, R_OK) < 0) {
- if (mkdir(user_data_dir, 0755) < 0) {
+ if (mkdir(user_data_dir, 0711) < 0) {
return -1;
}
if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
return -1;
}
+ if (chmod(user_data_dir, 0711) < 0) {
+ return -1;
+ }
}
// Make the /data/user/0 symlink to /data/data if necessary
if (access(primary_data_dir, R_OK) < 0) {
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 8b55c8fa..52a9293 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -4,18 +4,18 @@
LOCAL_SRC_FILES:= \
stagefright.cpp \
+ jpeg.cpp \
SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia libmedia_native libutils libbinder libstagefright_foundation \
- libskia libgui
+ libjpeg libgui
LOCAL_C_INCLUDES:= \
frameworks/base/media/libstagefright \
frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/native/include/media/openmax \
- external/skia/include/core \
- external/skia/include/images \
+ external/jpeg \
LOCAL_CFLAGS += -Wno-multichar
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index fea62cc..cf2909e 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -28,6 +28,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/NuMediaExtractor.h>
#include <gui/SurfaceComposerClient.h>
@@ -36,7 +37,9 @@
fprintf(stderr, "usage: %s [-a] use audio\n"
"\t\t[-v] use video\n"
"\t\t[-p] playback\n"
- "\t\t[-S] allocate buffers from a surface\n", me);
+ "\t\t[-S] allocate buffers from a surface\n"
+ "\t\t[-D] decrypt input buffers\n",
+ me);
exit(1);
}
@@ -63,7 +66,8 @@
const char *path,
bool useAudio,
bool useVideo,
- const android::sp<android::Surface> &surface) {
+ const android::sp<android::Surface> &surface,
+ bool decryptInputBuffers) {
using namespace android;
static int64_t kTimeout = 500ll;
@@ -109,13 +113,31 @@
state->mNumBuffersDecoded = 0;
state->mIsAudio = isAudio;
- state->mCodec = MediaCodec::CreateByType(
- looper, mime.c_str(), false /* encoder */);
+ if (decryptInputBuffers && !isAudio) {
+ static const MediaCodecList *list = MediaCodecList::getInstance();
+
+ ssize_t index =
+ list->findCodecByType(mime.c_str(), false /* encoder */);
+
+ CHECK_GE(index, 0);
+
+ const char *componentName = list->getCodecName(index);
+
+ AString fullName = componentName;
+ fullName.append(".secure");
+
+ state->mCodec = MediaCodec::CreateByComponentName(
+ looper, fullName.c_str());
+ } else {
+ state->mCodec = MediaCodec::CreateByType(
+ looper, mime.c_str(), false /* encoder */);
+ }
CHECK(state->mCodec != NULL);
err = state->mCodec->configure(
- format, isVideo ? surface : NULL, 0 /* flags */);
+ format, isVideo ? surface : NULL,
+ decryptInputBuffers ? MediaCodec::CONFIGURE_FLAG_SECURE : 0);
CHECK_EQ(err, (status_t)OK);
@@ -202,12 +224,24 @@
err = extractor->getSampleTime(&timeUs);
CHECK_EQ(err, (status_t)OK);
+ uint32_t bufferFlags = 0;
+
+ uint32_t sampleFlags;
+ err = extractor->getSampleFlags(&sampleFlags);
+ CHECK_EQ(err, (status_t)OK);
+
+ if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) {
+ CHECK(decryptInputBuffers);
+
+ bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED;
+ }
+
err = state->mCodec->queueInputBuffer(
index,
0 /* offset */,
buffer->size(),
timeUs,
- 0 /* flags */);
+ bufferFlags);
CHECK_EQ(err, (status_t)OK);
@@ -341,9 +375,10 @@
bool useVideo = false;
bool playback = false;
bool useSurface = false;
+ bool decryptInputBuffers = false;
int res;
- while ((res = getopt(argc, argv, "havpS")) >= 0) {
+ while ((res = getopt(argc, argv, "havpSD")) >= 0) {
switch (res) {
case 'a':
{
@@ -369,6 +404,12 @@
break;
}
+ case 'D':
+ {
+ decryptInputBuffers = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -440,7 +481,8 @@
player->stop();
player->reset();
} else {
- decode(looper, argv[0], useAudio, useVideo, surface);
+ decode(looper, argv[0],
+ useAudio, useVideo, surface, decryptInputBuffers);
}
if (playback || (useSurface && useVideo)) {
diff --git a/cmds/stagefright/jpeg.cpp b/cmds/stagefright/jpeg.cpp
new file mode 100644
index 0000000..7e859c3
--- /dev/null
+++ b/cmds/stagefright/jpeg.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+
+extern "C" {
+#include "jpeglib.h"
+}
+
+static inline uint8_t from565to8(uint16_t p, int start, int bits) {
+ uint8_t c = (p >> start) & ((1 << bits) - 1);
+ return (c << (8 - bits)) | (c >> (bits - (8 - bits)));
+}
+
+struct sf_jpeg_error_mgr {
+ struct jpeg_error_mgr jerr;
+ jmp_buf longjmp_buffer;
+};
+
+void sf_jpeg_error_exit(j_common_ptr cinfo) {
+ struct sf_jpeg_error_mgr *sf_err = (struct sf_jpeg_error_mgr *)cinfo->err;
+ longjmp(sf_err->longjmp_buffer, 0);
+}
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height) {
+ struct sf_jpeg_error_mgr sf_err;
+ struct jpeg_compress_struct cinfo;
+ uint8_t row_data[width * 3];
+ JSAMPROW row_pointer = row_data;
+ FILE *f;
+
+ f = fopen(filename, "w");
+ if (!f) {
+ return -errno;
+ }
+
+ cinfo.err = jpeg_std_error(&sf_err.jerr);
+ sf_err.jerr.error_exit = sf_jpeg_error_exit;
+ if (setjmp(sf_err.longjmp_buffer)) {
+ jpeg_destroy_compress(&cinfo);
+ fclose(f);
+ return -1;
+ }
+
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, f);
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, 80, TRUE);
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+ for (int row = 0; row < height; row++) {
+ uint16_t *src = (uint16_t *)(frame + row * width * 2);
+ uint8_t *dst = row_data;
+ for (int col = 0; col < width; col++) {
+ dst[0] = from565to8(*src, 11, 5);
+ dst[1] = from565to8(*src, 5, 6);
+ dst[2] = from565to8(*src, 0, 5);
+ dst += 3;
+ src++;
+ }
+ jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+ }
+
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ fclose(f);
+ return 0;
+}
diff --git a/cmds/stagefright/jpeg.h b/cmds/stagefright/jpeg.h
new file mode 100644
index 0000000..ce86cf2
--- /dev/null
+++ b/cmds/stagefright/jpeg.h
@@ -0,0 +1,6 @@
+#ifndef _STAGEFRIGHT_JPEG_H_
+#define _STAGEFRIGHT_JPEG_H_
+
+int writeJpegFile(const char *filename, uint8_t *frame, int width, int height);
+
+#endif
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 64df5d1..3bbfbdc 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -287,6 +287,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+
+ int32_t isADTS;
+ if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
+ msg->setInt32("is-adts", true);
+ }
}
uint32_t type;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index dab2e0f..d70c862 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -24,6 +24,7 @@
#include <string.h>
#include <unistd.h>
+#include "jpeg.h"
#include "SineSource.h"
#include <binder/IServiceManager.h>
@@ -49,8 +50,6 @@
#include <media/stagefright/MPEG4Writer.h>
#include <private/media/VideoFrame.h>
-#include <SkBitmap.h>
-#include <SkImageEncoder.h>
#include <fcntl.h>
@@ -787,16 +786,9 @@
VideoFrame *frame = (VideoFrame *)mem->pointer();
- SkBitmap bitmap;
- bitmap.setConfig(
- SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight);
-
- bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame));
-
- CHECK(SkImageEncoder::EncodeFile(
- "/sdcard/out.jpg", bitmap,
- SkImageEncoder::kJPEG_Type,
- SkImageEncoder::kDefaultQuality));
+ CHECK_EQ(writeJpegFile("/sdcard/out.jpg",
+ (uint8_t *)frame + sizeof(VideoFrame),
+ frame->mWidth, frame->mHeight), 0);
}
{
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 5c4b258..6a4f1f2 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -18,13 +18,11 @@
import android.os.SystemProperties;
import android.util.Log;
-
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.cert.X509Certificate;
-
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
@@ -36,7 +34,6 @@
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
-
import org.apache.harmony.xnet.provider.jsse.OpenSSLContextImpl;
import org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl;
import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
@@ -89,6 +86,7 @@
private SSLSocketFactory mSecureFactory = null;
private TrustManager[] mTrustManagers = null;
private KeyManager[] mKeyManagers = null;
+ private byte[] mNpnProtocols = null;
private final int mHandshakeTimeoutMillis;
private final SSLClientSessionCache mSessionCache;
@@ -251,6 +249,60 @@
}
/**
+ * Sets the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
+ * Protocol Negotiation (NPN)</a> protocols that this peer is interested in.
+ *
+ * <p>For servers this is the sequence of protocols to advertise as
+ * supported, in order of preference. This list is sent unencrypted to
+ * all clients that support NPN.
+ *
+ * <p>For clients this is a list of supported protocols to match against the
+ * server's list. If there is no protocol supported by both client and
+ * server then the first protocol in the client's list will be selected.
+ * The order of the client's protocols is otherwise insignificant.
+ *
+ * @param npnProtocols a possibly-empty list of protocol byte arrays. All
+ * arrays must be non-empty and of length less than 256.
+ */
+ public void setNpnProtocols(byte[][] npnProtocols) {
+ this.mNpnProtocols = toNpnProtocolsList(npnProtocols);
+ }
+
+ /**
+ * Returns an array containing the concatenation of length-prefixed byte
+ * strings.
+ */
+ static byte[] toNpnProtocolsList(byte[]... npnProtocols) {
+ int totalLength = 0;
+ for (byte[] s : npnProtocols) {
+ if (s.length == 0 || s.length > 255) {
+ throw new IllegalArgumentException("s.length == 0 || s.length > 255: " + s.length);
+ }
+ totalLength += 1 + s.length;
+ }
+ byte[] result = new byte[totalLength];
+ int pos = 0;
+ for (byte[] s : npnProtocols) {
+ result[pos++] = (byte) s.length;
+ for (byte b : s) {
+ result[pos++] = b;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next
+ * Protocol Negotiation (NPN)</a> protocol selected by client and server, or
+ * null if no protocol was negotiated.
+ *
+ * @param socket a socket created by this factory.
+ */
+ public byte[] getNpnSelectedProtocol(Socket socket) {
+ return ((OpenSSLSocketImpl) socket).getNpnSelectedProtocol();
+ }
+
+ /**
* Sets the {@link KeyManager}s to be used for connections made by this factory.
*/
public void setKeyManagers(KeyManager[] keyManagers) {
@@ -271,6 +323,7 @@
@Override
public Socket createSocket(Socket k, String host, int port, boolean close) throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(k, host, port, close);
+ s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
if (mSecure) {
verifyHostname(s, host);
@@ -289,6 +342,7 @@
@Override
public Socket createSocket() throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket();
+ s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
return s;
}
@@ -305,6 +359,7 @@
throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
addr, port, localAddr, localPort);
+ s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
return s;
}
@@ -319,6 +374,7 @@
@Override
public Socket createSocket(InetAddress addr, int port) throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(addr, port);
+ s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
return s;
}
@@ -334,6 +390,7 @@
throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(
host, port, localAddr, localPort);
+ s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
if (mSecure) {
verifyHostname(s, host);
@@ -350,6 +407,7 @@
@Override
public Socket createSocket(String host, int port) throws IOException {
OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
+ s.setNpnProtocols(mNpnProtocols);
s.setHandshakeTimeout(mHandshakeTimeoutMillis);
if (mSecure) {
verifyHostname(s, host);
diff --git a/core/java/android/webkit/FindListener.java b/core/java/android/webkit/FindListener.java
deleted file mode 100644
index 124f737..0000000
--- a/core/java/android/webkit/FindListener.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-package android.webkit;
-
-/**
- * @hide
- */
-public interface FindListener {
- /**
- * Notify the host application that a find result is available.
- *
- * @param numberOfMatches How many matches have been found
- * @param activeMatchOrdinal The ordinal of the currently selected match
- * @param isDoneCounting Whether we have finished counting matches
- */
- public void onFindResultReceived(int numberOfMatches,
- int activeMatchOrdinal, boolean isDoneCounting);
-}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index dd373de..d225594 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -312,6 +312,24 @@
public static final String SCHEME_GEO = "geo:0,0?q=";
/**
+ * Interface to listen for find results.
+ * @hide
+ */
+ public interface FindListener {
+ /**
+ * Notify the listener about progress made by a find operation.
+ *
+ * @param numberOfMatches How many matches have been found.
+ * @param activeMatchOrdinal The zero-based ordinal of the currently selected match.
+ * @param isDoneCounting Whether the find operation has actually completed. The listener
+ * may be notified multiple times while the operation is underway, and the numberOfMatches
+ * value should not be considered final unless isDoneCounting is true.
+ */
+ public void onFindResultReceived(int numberOfMatches, int activeMatchOrdinal,
+ boolean isDoneCounting);
+ }
+
+ /**
* Interface to listen for new pictures as they change.
* @deprecated This interface is now obsolete.
*/
@@ -1228,10 +1246,10 @@
}
/**
- * Register the interface to be used when a find-on-page result has become
- * available. This will replace the current handler.
+ * Register the listener to be notified as find-on-page operations progress.
+ * This will replace the current listener.
*
- * @param listener An implementation of FindListener
+ * @param listener An implementation of {@link WebView#FindListener}.
* @hide
*/
public void setFindListener(FindListener listener) {
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 03329b8..ab2db22 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1440,7 +1440,7 @@
private PictureListener mPictureListener;
// Used to notify listeners about find-on-page results.
- private FindListener mFindListener;
+ private WebView.FindListener mFindListener;
/**
* Refer to {@link WebView#requestFocusNodeHref(Message)} for more information
@@ -3620,12 +3620,10 @@
}
/**
- * Register the interface to be used when a find-on-page result has become
- * available. This will replace the current handler.
- *
- * @param listener An implementation of FindListener
+ * See {@link WebView#setFindListener(WebView.FindListener)}.
+ * @hide
*/
- public void setFindListener(FindListener listener) {
+ public void setFindListener(WebView.FindListener listener) {
mFindListener = listener;
}
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 7d47e14..f049198 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -192,7 +192,7 @@
public WebBackForwardList copyBackForwardList();
- public void setFindListener(FindListener listener);
+ public void setFindListener(WebView.FindListener listener);
public void findNext(boolean forward);
diff --git a/core/tests/coretests/src/android/net/SSLTest.java b/core/tests/coretests/src/android/net/SSLTest.java
index 810ed0d..c573498 100644
--- a/core/tests/coretests/src/android/net/SSLTest.java
+++ b/core/tests/coretests/src/android/net/SSLTest.java
@@ -16,17 +16,16 @@
package android.net;
-import android.net.SSLCertificateSocketFactory;
import android.test.suitebuilder.annotation.Suppress;
-import junit.framework.TestCase;
-
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
+import java.util.Arrays;
+import junit.framework.TestCase;
-//This test relies on network resources.
-@Suppress
public class SSLTest extends TestCase {
+ //This test relies on network resources.
+ @Suppress
public void testCertificate() throws Exception {
// test www.fortify.net/sslcheck.html
Socket ssl = SSLCertificateSocketFactory.getDefault().createSocket("www.fortify.net",443);
@@ -49,4 +48,35 @@
// System.out.println(new String(b));
}
+
+ public void testStringsToNpnBytes() {
+ byte[] expected = {
+ 6, 's', 'p', 'd', 'y', '/', '2',
+ 8, 'h', 't', 't', 'p', '/', '1', '.', '1',
+ };
+ assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList(
+ new byte[] { 's', 'p', 'd', 'y', '/', '2' },
+ new byte[] { 'h', 't', 't', 'p', '/', '1', '.', '1' })));
+ }
+
+ public void testStringsToNpnBytesEmptyByteArray() {
+ try {
+ SSLCertificateSocketFactory.toNpnProtocolsList(new byte[0]);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testStringsToNpnBytesEmptyArray() {
+ byte[] expected = {};
+ assertTrue(Arrays.equals(expected, SSLCertificateSocketFactory.toNpnProtocolsList()));
+ }
+
+ public void testStringsToNpnBytesOversizedInput() {
+ try {
+ SSLCertificateSocketFactory.toNpnProtocolsList(new byte[256]);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
}
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
new file mode 100644
index 0000000..916abe0
--- /dev/null
+++ b/include/media/ICrypto.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 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 <binder/IInterface.h>
+#include <media/stagefright/foundation/ABase.h>
+
+#ifndef ANDROID_ICRYPTO_H_
+
+#define ANDROID_ICRYPTO_H_
+
+namespace android {
+
+struct ICrypto : public IInterface {
+ DECLARE_META_INTERFACE(Crypto);
+
+ virtual status_t initialize() = 0;
+ virtual status_t terminate() = 0;
+
+ virtual status_t setEntitlementKey(
+ const void *key, size_t keyLength) = 0;
+
+ virtual status_t setEntitlementControlMessage(
+ const void *msg, size_t msgLength) = 0;
+
+ // "dstData" is in media_server's address space (but inaccessible).
+ virtual ssize_t decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset) = 0;
+
+ // "dstData" is in the calling process' address space.
+ virtual ssize_t decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize) = 0;
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(ICrypto);
+};
+
+struct BnCrypto : public BnInterface<ICrypto> {
+ virtual status_t onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_ICRYPTO_H_
+
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index 4f46fcd..76c45a0 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -31,6 +31,7 @@
namespace android {
+struct ICrypto;
class IMediaRecorder;
class IOMX;
struct IStreamSource;
@@ -47,6 +48,7 @@
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat) = 0;
virtual sp<IOMX> getOMX() = 0;
+ virtual sp<ICrypto> makeCrypto() = 0;
// codecs and audio devices usage tracking for the battery app
enum BatteryDataBits {
diff --git a/include/media/JetPlayer.h b/include/media/JetPlayer.h
index 38a3e44..0616bf0 100644
--- a/include/media/JetPlayer.h
+++ b/include/media/JetPlayer.h
@@ -18,7 +18,6 @@
#define JETPLAYER_H_
#include <utils/threads.h>
-#include <nativehelper/jni.h>
#include <libsonivox/jet.h>
#include <libsonivox/eas_types.h>
@@ -40,7 +39,7 @@
static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
static const int JET_PAUSE_UPDATE = 4;
- JetPlayer(jobject javaJetPlayer,
+ JetPlayer(void *javaJetPlayer,
int maxTracks = 32,
int trackBufferSize = 1200);
~JetPlayer();
@@ -75,7 +74,7 @@
jetevent_callback mEventCallback;
- jobject mJavaJetPlayerRef;
+ void* mJavaJetPlayerRef;
Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
pid_t mTid;
Condition mCondition;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index fa1a416..7d7af63 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -89,6 +89,10 @@
kPortIndexOutput = 1
};
+ enum {
+ kFlagIsSecure = 1,
+ };
+
struct BufferInfo {
enum Status {
OWNED_BY_US,
@@ -118,6 +122,7 @@
sp<FlushingState> mFlushingState;
AString mComponentName;
+ uint32_t mFlags;
uint32_t mQuirks;
sp<IOMX> mOMX;
IOMX::node_id mNode;
@@ -176,7 +181,8 @@
status_t setupAACCodec(
bool encoder,
- int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate,
+ bool isADTS);
status_t selectAudioPortFormat(
OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 72ac56a..0fc88e1 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -27,18 +27,21 @@
struct ABuffer;
struct ACodec;
struct AMessage;
+struct ICrypto;
struct SoftwareRenderer;
struct SurfaceTextureClient;
struct MediaCodec : public AHandler {
enum ConfigureFlags {
CONFIGURE_FLAG_ENCODE = 1,
+ CONFIGURE_FLAG_SECURE = 2,
};
enum BufferFlags {
BUFFER_FLAG_SYNCFRAME = 1,
BUFFER_FLAG_CODECCONFIG = 2,
BUFFER_FLAG_EOS = 4,
+ BUFFER_FLAG_ENCRYPTED = 8,
};
static sp<MediaCodec> CreateByType(
@@ -137,11 +140,13 @@
kFlagStickyError = 8,
kFlagDequeueInputPending = 16,
kFlagDequeueOutputPending = 32,
+ kFlagIsSecure = 64,
};
struct BufferInfo {
void *mBufferID;
sp<ABuffer> mData;
+ sp<ABuffer> mEncryptedData;
sp<AMessage> mNotify;
bool mOwnedByClient;
};
@@ -165,6 +170,8 @@
int32_t mDequeueOutputTimeoutGeneration;
uint32_t mDequeueOutputReplyID;
+ sp<ICrypto> mCrypto;
+
MediaCodec(const sp<ALooper> &looper);
static status_t PostAndAwaitResponse(
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index c3ccb56..639446e 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -128,6 +128,12 @@
kKeyTextFormatData = 'text', // raw data
kKeyRequiresSecureBuffers = 'secu', // bool (int32_t)
+
+ kKeyScrambling = 'scrm', // int32_t
+ kKeyEMM = 'emm ', // raw data
+ kKeyECM = 'ecm ', // raw data
+
+ kKeyIsADTS = 'adts', // bool (int32_t)
};
enum {
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index 96efdff..07c7be5 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -31,6 +31,11 @@
struct MediaSource;
struct NuMediaExtractor : public RefBase {
+ enum SampleFlags {
+ SAMPLE_FLAG_SYNC = 1,
+ SAMPLE_FLAG_ENCRYPTED = 2,
+ };
+
NuMediaExtractor();
status_t setDataSource(const char *path);
@@ -46,6 +51,7 @@
status_t readSampleData(const sp<ABuffer> &buffer);
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
+ status_t getSampleFlags(uint32_t *sampleFlags);
protected:
virtual ~NuMediaExtractor();
@@ -61,7 +67,9 @@
status_t mFinalResult;
MediaBuffer *mSample;
int64_t mSampleTimeUs;
- uint32_t mFlags; // bitmask of "TrackFlags"
+ uint32_t mSampleFlags;
+
+ uint32_t mTrackFlags; // bitmask of "TrackFlags"
};
sp<MediaExtractor> mImpl;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7c612ba..7d51dee 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -238,7 +238,11 @@
void setComponentRole();
void setAMRFormat(bool isWAMR, int32_t bitRate);
- status_t setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate);
+
+ status_t setAACFormat(
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate,
+ bool isADTS);
+
void setG711Format(int32_t numChannels);
status_t setVideoPortFormatType(
diff --git a/include/media/stagefright/foundation/AString.h b/include/media/stagefright/foundation/AString.h
index 55ade64..0f8f1e1 100644
--- a/include/media/stagefright/foundation/AString.h
+++ b/include/media/stagefright/foundation/AString.h
@@ -73,6 +73,7 @@
int compare(const AString &other) const;
bool startsWith(const char *prefix) const;
+ bool endsWith(const char *suffix) const;
void tolower();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index bccf1f9..d06e302 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -48,6 +48,7 @@
public static int FLAG_SYNCFRAME = 1;
public static int FLAG_CODECCONFIG = 2;
public static int FLAG_EOS = 4;
+ public static int FLAG_ENCRYPTED = 8;
/** Instantiate a codec component by mime type. For decoder components
this is the mime type of media that this decoder should be able to
@@ -82,6 +83,7 @@
public native final void release();
public static int CONFIGURE_FLAG_ENCODE = 1;
+ public static int CONFIGURE_FLAG_SECURE = 2;
/** Configures a component.
* @param format A map of string/value pairs describing the input format
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 5732c72..9ea3d0e 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -65,6 +65,13 @@
// Returns the current sample's presentation time in microseconds.
public native long getSampleTime();
+ // Keep these in sync with their equivalents in NuMediaExtractor.h
+ public static final int SAMPLE_FLAG_SYNC = 1;
+ public static final int SAMPLE_FLAG_ENCRYPTED = 2;
+
+ // Returns the current sample's flags.
+ public native int getSampleFlags();
+
private static native final void native_init();
private native final void native_setup(String path);
private native final void native_finalize();
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 0c86fc2..8c661b7 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -160,6 +160,10 @@
return mImpl->getSampleTime(sampleTimeUs);
}
+status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
+ return mImpl->getSampleFlags(sampleFlags);
+}
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -343,6 +347,28 @@
return sampleTimeUs;
}
+static jint android_media_MediaExtractor_getSampleFlags(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return -1ll;
+ }
+
+ uint32_t sampleFlags;
+ status_t err = extractor->getSampleFlags(&sampleFlags);
+
+ if (err == ERROR_END_OF_STREAM) {
+ return -1ll;
+ } else if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return false;
+ }
+
+ return sampleFlags;
+}
+
static void android_media_MediaExtractor_native_init(JNIEnv *env) {
jclass clazz = env->FindClass("android/media/MediaExtractor");
CHECK(clazz != NULL);
@@ -412,6 +438,9 @@
{ "getSampleTime", "()J",
(void *)android_media_MediaExtractor_getSampleTime },
+ { "getSampleFlags", "()I",
+ (void *)android_media_MediaExtractor_getSampleFlags },
+
{ "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
{ "native_setup", "(Ljava/lang/String;)V",
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 70e58c6..49a64d6 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -43,6 +43,7 @@
status_t readSampleData(jobject byteBuf, size_t offset, size_t *sampleSize);
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
+ status_t getSampleFlags(uint32_t *sampleFlags);
protected:
virtual ~JMediaExtractor();
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 8b2321c..1190448 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -324,7 +324,7 @@
env->DeleteLocalRef(byteArray); byteArray = NULL;
}
- msg->setObject(key.c_str(), buffer);
+ msg->setBuffer(key.c_str(), buffer);
}
}
diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk
index 98d6449..70dbfb3 100644
--- a/media/jni/soundpool/Android.mk
+++ b/media/jni/soundpool/Android.mk
@@ -2,14 +2,14 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- android_media_SoundPool.cpp \
- SoundPool.cpp \
- SoundPoolThread.cpp
+ android_media_SoundPool.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libmedia
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
- libbinder \
libandroid_runtime \
libnativehelper \
libmedia \
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index da3af9d..c6dee06 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -23,7 +23,7 @@
#include <nativehelper/jni.h>
#include <nativehelper/JNIHelp.h>
#include <android_runtime/AndroidRuntime.h>
-#include "SoundPool.h"
+#include <SoundPool.h>
using namespace android;
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 51c8b68..bdb1a1c 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <new>
+#include <time.h>
#include <audio_effects/effect_visualizer.h>
@@ -47,9 +48,9 @@
VISUALIZER_STATE_ACTIVE,
};
-// maximum number of reads from same buffer before resetting capture buffer. This means
+// maximum time since last capture buffer update before resetting capture buffer. This means
// that the framework has stopped playing audio and we must start returning silence
-#define MAX_STALL_COUNT 10
+#define MAX_STALL_TIME_MS 1000
struct VisualizerContext {
const struct effect_interface_s *mItfe;
@@ -59,7 +60,7 @@
uint8_t mState;
uint8_t mCurrentBuf;
uint8_t mLastBuf;
- uint8_t mStallCount;
+ struct timespec mBufferUpdateTime;
uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
};
@@ -72,7 +73,7 @@
pContext->mCaptureIdx = 0;
pContext->mCurrentBuf = 0;
pContext->mLastBuf = 1;
- pContext->mStallCount = 0;
+ pContext->mBufferUpdateTime.tv_sec = 0;
memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
}
@@ -321,6 +322,11 @@
if (pContext->mCaptureIdx == pContext->mCaptureSize) {
pContext->mCurrentBuf ^= 1;
pContext->mCaptureIdx = 0;
+
+ // update last buffer update time stamp
+ if (clock_gettime(CLOCK_MONOTONIC, &pContext->mBufferUpdateTime) < 0) {
+ pContext->mBufferUpdateTime.tv_sec = 0;
+ }
}
if (inBuffer->raw != outBuffer->raw) {
@@ -453,16 +459,25 @@
pContext->mCaptureSize);
// if audio framework has stopped playing audio although the effect is still
// active we must clear the capture buffer to return silence
- if (pContext->mLastBuf == pContext->mCurrentBuf) {
- if (pContext->mStallCount < MAX_STALL_COUNT) {
- if (++pContext->mStallCount == MAX_STALL_COUNT) {
+ if ((pContext->mLastBuf == pContext->mCurrentBuf) &&
+ (pContext->mBufferUpdateTime.tv_sec != 0)) {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ time_t secs = ts.tv_sec - pContext->mBufferUpdateTime.tv_sec;
+ long nsec = ts.tv_nsec - pContext->mBufferUpdateTime.tv_nsec;
+ if (nsec < 0) {
+ --secs;
+ nsec += 1000000000;
+ }
+ uint32_t deltaMs = secs * 1000 + nsec / 1000000;
+ if (deltaMs > MAX_STALL_TIME_MS) {
+ ALOGV("capture going to idle");
+ pContext->mBufferUpdateTime.tv_sec = 0;
memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
0x80,
pContext->mCaptureSize);
}
}
- } else {
- pContext->mStallCount = 0;
}
pContext->mLastBuf = pContext->mCurrentBuf;
} else {
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index c34e23b..c8e1dc7 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -17,6 +17,7 @@
IAudioFlingerClient.cpp \
IAudioTrack.cpp \
IAudioRecord.cpp \
+ ICrypto.cpp \
AudioRecord.cpp \
AudioSystem.cpp \
mediaplayer.cpp \
@@ -43,7 +44,9 @@
IEffectClient.cpp \
AudioEffect.cpp \
Visualizer.cpp \
- MemoryLeakTrackUtil.cpp
+ MemoryLeakTrackUtil.cpp \
+ SoundPool.cpp \
+ SoundPoolThread.cpp
LOCAL_SHARED_LIBRARIES := \
libui libcutils libutils libbinder libsonivox libicuuc libexpat \
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
new file mode 100644
index 0000000..827d7af
--- /dev/null
+++ b/media/libmedia/ICrypto.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 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 "ICrypto"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/ICrypto.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+enum {
+ INITIALIZE = IBinder::FIRST_CALL_TRANSACTION,
+ TERMINATE,
+ SET_ENTITLEMENT_KEY,
+ SET_ECM,
+ DECRYPT_VIDEO,
+ DECRYPT_AUDIO,
+};
+
+struct BpCrypto : public BpInterface<ICrypto> {
+ BpCrypto(const sp<IBinder> &impl)
+ : BpInterface<ICrypto>(impl) {
+ }
+
+ virtual status_t initialize() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ remote()->transact(INITIALIZE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t terminate() {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ remote()->transact(TERMINATE, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t setEntitlementKey(
+ const void *key, size_t keyLength) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ data.writeInt32(keyLength);
+ data.write(key, keyLength);
+ remote()->transact(SET_ENTITLEMENT_KEY, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t setEntitlementControlMessage(
+ const void *msg, size_t msgLength) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ data.writeInt32(msgLength);
+ data.write(msg, msgLength);
+ remote()->transact(SET_ECM, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual ssize_t decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ if (iv == NULL) {
+ if (ivLength > 0) {
+ return -EINVAL;
+ }
+
+ data.writeInt32(-1);
+ } else {
+ data.writeInt32(ivLength);
+ data.write(iv, ivLength);
+ }
+
+ data.writeInt32(srcDataSize);
+ data.write(srcData, srcDataSize);
+
+ data.writeIntPtr((intptr_t)dstData);
+ data.writeInt32(dstDataOffset);
+
+ remote()->transact(DECRYPT_VIDEO, data, &reply);
+
+ return reply.readInt32();
+ }
+
+ virtual ssize_t decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
+ if (iv == NULL) {
+ if (ivLength > 0) {
+ return -EINVAL;
+ }
+
+ data.writeInt32(-1);
+ } else {
+ data.writeInt32(ivLength);
+ data.write(iv, ivLength);
+ }
+
+ data.writeInt32(srcDataSize);
+ data.write(srcData, srcDataSize);
+ data.writeInt32(dstDataSize);
+
+ remote()->transact(DECRYPT_AUDIO, data, &reply);
+
+ ssize_t res = reply.readInt32();
+
+ if (res <= 0) {
+ return res;
+ }
+
+ reply.read(dstData, res);
+
+ return res;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(BpCrypto);
+};
+
+IMPLEMENT_META_INTERFACE(Crypto, "android.hardware.ICrypto");
+
+////////////////////////////////////////////////////////////////////////////////
+
+status_t BnCrypto::onTransact(
+ uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+ switch (code) {
+ case INITIALIZE:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+ reply->writeInt32(initialize());
+
+ return OK;
+ }
+
+ case TERMINATE:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+ reply->writeInt32(terminate());
+
+ return OK;
+ }
+
+ case SET_ENTITLEMENT_KEY:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ size_t keyLength = data.readInt32();
+ void *key = malloc(keyLength);
+ data.read(key, keyLength);
+
+ reply->writeInt32(setEntitlementKey(key, keyLength));
+
+ free(key);
+ key = NULL;
+
+ return OK;
+ }
+
+ case SET_ECM:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ size_t msgLength = data.readInt32();
+ void *msg = malloc(msgLength);
+ data.read(msg, msgLength);
+
+ reply->writeInt32(setEntitlementControlMessage(msg, msgLength));
+
+ free(msg);
+ msg = NULL;
+
+ return OK;
+ }
+
+ case DECRYPT_VIDEO:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ void *iv = NULL;
+
+ int32_t ivLength = data.readInt32();
+ if (ivLength >= 0) {
+ iv = malloc(ivLength);
+ data.read(iv, ivLength);
+ }
+
+ size_t srcDataSize = data.readInt32();
+ void *srcData = malloc(srcDataSize);
+ data.read(srcData, srcDataSize);
+
+ void *dstData = (void *)data.readIntPtr();
+ size_t dstDataOffset = data.readInt32();
+
+ reply->writeInt32(
+ decryptVideo(
+ iv,
+ ivLength < 0 ? 0 : ivLength,
+ srcData,
+ srcDataSize,
+ dstData,
+ dstDataOffset));
+
+ free(srcData);
+ srcData = NULL;
+
+ if (iv != NULL) {
+ free(iv);
+ iv = NULL;
+ }
+
+ return OK;
+ }
+
+ case DECRYPT_AUDIO:
+ {
+ CHECK_INTERFACE(ICrypto, data, reply);
+
+ void *iv = NULL;
+
+ int32_t ivLength = data.readInt32();
+ if (ivLength >= 0) {
+ iv = malloc(ivLength);
+ data.read(iv, ivLength);
+ }
+
+ size_t srcDataSize = data.readInt32();
+ void *srcData = malloc(srcDataSize);
+ data.read(srcData, srcDataSize);
+
+ size_t dstDataSize = data.readInt32();
+ void *dstData = malloc(dstDataSize);
+
+ ssize_t res =
+ decryptAudio(
+ iv,
+ ivLength < 0 ? 0 : ivLength,
+ srcData,
+ srcDataSize,
+ dstData,
+ dstDataSize);
+
+ reply->writeInt32(res);
+
+ if (res > 0) {
+ reply->write(dstData, res);
+ }
+
+ free(dstData);
+ dstData = NULL;
+
+ free(srcData);
+ srcData = NULL;
+
+ if (iv != NULL) {
+ free(iv);
+ iv = NULL;
+ }
+
+ return OK;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index 9b8d7c3..7e6d54b 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -18,7 +18,6 @@
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
-#include <SkBitmap.h>
#include <media/IMediaMetadataRetriever.h>
#include <utils/String8.h>
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index f5fccef..9120617 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -20,6 +20,7 @@
#include <binder/Parcel.h>
#include <binder/IMemory.h>
+#include <media/ICrypto.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaRecorder.h>
#include <media/IOMX.h>
@@ -36,6 +37,7 @@
CREATE_MEDIA_RECORDER,
CREATE_METADATA_RETRIEVER,
GET_OMX,
+ MAKE_CRYPTO,
ADD_BATTERY_DATA,
PULL_BATTERY_DATA
};
@@ -111,6 +113,13 @@
return interface_cast<IOMX>(reply.readStrongBinder());
}
+ virtual sp<ICrypto> makeCrypto() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ remote()->transact(MAKE_CRYPTO, data, &reply);
+ return interface_cast<ICrypto>(reply.readStrongBinder());
+ }
+
virtual void addBatteryData(uint32_t params) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
@@ -191,6 +200,12 @@
reply->writeStrongBinder(omx->asBinder());
return NO_ERROR;
} break;
+ case MAKE_CRYPTO: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ sp<ICrypto> crypto = makeCrypto();
+ reply->writeStrongBinder(crypto->asBinder());
+ return NO_ERROR;
+ } break;
case ADD_BATTERY_DATA: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
uint32_t params = data.readInt32();
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
index 7fa6bb7..52aee49 100644
--- a/media/libmedia/JetPlayer.cpp
+++ b/media/libmedia/JetPlayer.cpp
@@ -30,7 +30,7 @@
static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
//-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(jobject javaJetPlayer, int maxTracks, int trackBufferSize) :
+JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
mEventCallback(NULL),
mJavaJetPlayerRef(javaJetPlayer),
mTid(-1),
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/libmedia/SoundPool.cpp
similarity index 99%
rename from media/jni/soundpool/SoundPool.cpp
rename to media/libmedia/SoundPool.cpp
index 5aed8a1..306c57d 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/libmedia/SoundPool.cpp
@@ -685,7 +685,7 @@
void SoundChannel::callback(int event, void* user, void *info)
{
SoundChannel* channel = static_cast<SoundChannel*>((void *)((unsigned long)user & ~1));
-
+
channel->process(event, info, (unsigned long)user & 1);
}
diff --git a/media/jni/soundpool/SoundPool.h b/media/libmedia/SoundPool.h
similarity index 100%
rename from media/jni/soundpool/SoundPool.h
rename to media/libmedia/SoundPool.h
diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/libmedia/SoundPoolThread.cpp
similarity index 100%
rename from media/jni/soundpool/SoundPoolThread.cpp
rename to media/libmedia/SoundPoolThread.cpp
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/libmedia/SoundPoolThread.h
similarity index 100%
rename from media/jni/soundpool/SoundPoolThread.h
rename to media/libmedia/SoundPoolThread.h
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 4c6e0bd..675c563 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -7,6 +7,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ Crypto.cpp \
MediaRecorderClient.cpp \
MediaPlayerService.cpp \
MetadataRetrieverClient.cpp \
@@ -42,7 +43,7 @@
$(TOP)/frameworks/base/media/libstagefright/include \
$(TOP)/frameworks/base/media/libstagefright/rtsp \
$(TOP)/frameworks/native/include/media/openmax \
- $(TOP)/external/tremolo/Tremolo
+ $(TOP)/external/tremolo/Tremolo \
LOCAL_MODULE:= libmediaplayerservice
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
new file mode 100644
index 0000000..e02035f
--- /dev/null
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 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 "Crypto"
+#include <utils/Log.h>
+
+#include "Crypto.h"
+
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+Crypto::Crypto() {
+}
+
+Crypto::~Crypto() {
+}
+
+status_t Crypto::initialize() {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::terminate() {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::setEntitlementKey(
+ const void *key, size_t keyLength) {
+ return ERROR_UNSUPPORTED;
+}
+
+status_t Crypto::setEntitlementControlMessage(
+ const void *msg, size_t msgLength) {
+ return ERROR_UNSUPPORTED;
+}
+
+ssize_t Crypto::decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset) {
+ return ERROR_UNSUPPORTED;
+}
+
+ssize_t Crypto::decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize) {
+ return ERROR_UNSUPPORTED;
+}
+
+} // namespace android
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
new file mode 100644
index 0000000..9855496
--- /dev/null
+++ b/media/libmediaplayerservice/Crypto.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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 CRYPTO_H_
+
+#define CRYPTO_H_
+
+#include <media/ICrypto.h>
+#include <utils/threads.h>
+
+namespace android {
+
+struct Crypto : public BnCrypto {
+ Crypto();
+
+ virtual status_t initialize();
+ virtual status_t terminate();
+
+ virtual status_t setEntitlementKey(
+ const void *key, size_t keyLength);
+
+ virtual status_t setEntitlementControlMessage(
+ const void *msg, size_t msgLength);
+
+ virtual ssize_t decryptVideo(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataOffset);
+
+ virtual ssize_t decryptAudio(
+ const void *iv, size_t ivLength,
+ const void *srcData, size_t srcDataSize,
+ void *dstData, size_t dstDataSize);
+
+protected:
+ virtual ~Crypto();
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(Crypto);
+};
+
+} // namespace android
+
+#endif // CRYPTO_H_
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 840e475..123d07ff 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -70,6 +70,8 @@
#include <OMX.h>
+#include "Crypto.h"
+
namespace android {
sp<MediaPlayerBase> createAAH_TXPlayer();
sp<MediaPlayerBase> createAAH_RXPlayer();
@@ -292,6 +294,16 @@
return mOMX;
}
+sp<ICrypto> MediaPlayerService::makeCrypto() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mCrypto == NULL) {
+ mCrypto = new Crypto;
+ }
+
+ return mCrypto;
+}
+
status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index d4e0eb1..b08dd6c 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -240,6 +240,7 @@
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, audio_format_t* pFormat);
virtual sp<IOMX> getOMX();
+ virtual sp<ICrypto> makeCrypto();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -419,6 +420,7 @@
SortedVector< wp<MediaRecorderClient> > mMediaRecorderClients;
int32_t mNextConnId;
sp<IOMX> mOMX;
+ sp<ICrypto> mCrypto;
};
// ----------------------------------------------------------------------------
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 1600141..5733229 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -125,6 +125,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+
+ int32_t isADTS;
+ if (meta->findInt32(kKeyIsADTS, &isADTS) && isADTS != 0) {
+ msg->setInt32("is-adts", true);
+ }
}
int32_t maxInputSize;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e5ad4b7..db2beda 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -427,24 +427,34 @@
sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
CHECK(mem.get() != NULL);
- IOMX::buffer_id buffer;
+ BufferInfo info;
+ info.mStatus = BufferInfo::OWNED_BY_US;
uint32_t requiresAllocateBufferBit =
(portIndex == kPortIndexInput)
? OMXCodec::kRequiresAllocateBufferOnInputPorts
: OMXCodec::kRequiresAllocateBufferOnOutputPorts;
- if (mQuirks & requiresAllocateBufferBit) {
+ if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) {
+ mem.clear();
+
+ void *ptr;
+ err = mOMX->allocateBuffer(
+ mNode, portIndex, def.nBufferSize, &info.mBufferID,
+ &ptr);
+
+ info.mData = new ABuffer(ptr, def.nBufferSize);
+ } else if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer);
+ mNode, portIndex, mem, &info.mBufferID);
} else {
- err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
+ err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID);
}
- BufferInfo info;
- info.mBufferID = buffer;
- info.mStatus = BufferInfo::OWNED_BY_US;
- info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
+ if (mem != NULL) {
+ info.mData = new ABuffer(mem->pointer(), def.nBufferSize);
+ }
+
mBuffers[portIndex].push(info);
}
}
@@ -840,7 +850,13 @@
|| !msg->findInt32("sample-rate", &sampleRate)) {
err = INVALID_OPERATION;
} else {
- err = setupAACCodec(encoder, numChannels, sampleRate, bitRate);
+ int32_t isADTS;
+ if (!msg->findInt32("is-adts", &isADTS)) {
+ isADTS = 0;
+ }
+
+ err = setupAACCodec(
+ encoder, numChannels, sampleRate, bitRate, isADTS != 0);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
err = setupAMRCodec(encoder, false /* isWAMR */, bitRate);
@@ -934,7 +950,11 @@
status_t ACodec::setupAACCodec(
bool encoder,
- int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+ if (encoder && isADTS) {
+ return -EINVAL;
+ }
+
status_t err = setupRawAudioFormat(
encoder ? kPortIndexInput : kPortIndexOutput,
sampleRate,
@@ -1021,7 +1041,11 @@
profile.nChannels = numChannels;
profile.nSampleRate = sampleRate;
- profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ profile.eAACStreamFormat =
+ isADTS
+ ? OMX_AUDIO_AACStreamFormatMP4ADTS
+ : OMX_AUDIO_AACStreamFormatMP4FF;
return mOMX->setParameter(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
@@ -2653,6 +2677,12 @@
observer->setNotificationMessage(notify);
mCodec->mComponentName = componentName;
+ mCodec->mFlags = 0;
+
+ if (componentName.endsWith(".secure")) {
+ mCodec->mFlags |= kFlagIsSecure;
+ }
+
mCodec->mQuirks = quirks;
mCodec->mOMX = omx;
mCodec->mNode = node;
@@ -2701,6 +2731,7 @@
mCodec->mNode = NULL;
mCodec->mOMX.clear();
mCodec->mQuirks = 0;
+ mCodec->mFlags = 0;
mCodec->mComponentName.clear();
mCodec->changeState(mCodec->mUninitializedState);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index a9e7f360..42b5c7e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -22,10 +22,14 @@
#include "include/SoftwareRenderer.h"
+#include <binder/IServiceManager.h>
#include <gui/SurfaceTextureClient.h>
+#include <media/ICrypto.h>
+#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/ACodec.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -528,6 +532,12 @@
info.mOwnedByClient = false;
CHECK(msg->findBuffer(name.c_str(), &info.mData));
+ if (portIndex == kPortIndexInput
+ && (mFlags & kFlagIsSecure)) {
+ info.mEncryptedData =
+ new ABuffer(info.mData->capacity());
+ }
+
buffers->push_back(info);
}
@@ -742,6 +752,59 @@
format->setInt32("encoder", true);
}
+ if (flags & CONFIGURE_FLAG_SECURE) {
+ mFlags |= kFlagIsSecure;
+
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+
+ CHECK(service != NULL);
+
+ mCrypto = service->makeCrypto();
+
+ status_t err = mCrypto->initialize();
+
+ if (err == OK) {
+ sp<ABuffer> emm;
+ if (format->findBuffer("emm", &emm)) {
+ err = mCrypto->setEntitlementKey(
+ emm->data(), emm->size());
+ }
+ }
+
+ if (err == OK) {
+ sp<ABuffer> ecm;
+ if (format->findBuffer("ecm", &ecm)) {
+ CHECK_EQ(ecm->size(), 80u);
+
+ // bytes 16..47 of the original ecm stream data.
+ err = mCrypto->setEntitlementControlMessage(
+ ecm->data() + 16, 32);
+ }
+ }
+
+ if (err != OK) {
+ ALOGE("failed to instantiate crypto service.");
+
+ mCrypto.clear();
+
+ setState(INITIALIZED);
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", UNKNOWN_ERROR);
+
+ response->postReply(mReplyID);
+ break;
+ }
+ } else {
+ mFlags &= ~kFlagIsSecure;
+ }
+
mCodec->initiateConfigureComponent(format);
break;
}
@@ -983,7 +1046,10 @@
for (size_t i = 0; i < srcBuffers.size(); ++i) {
const BufferInfo &info = srcBuffers.itemAt(i);
- dstBuffers->push_back(info.mData);
+ dstBuffers->push_back(
+ (portIndex == kPortIndexInput
+ && (mFlags & kFlagIsSecure))
+ ? info.mEncryptedData : info.mData);
}
(new AMessage)->postReply(replyID);
@@ -1037,10 +1103,15 @@
}
void MediaCodec::setState(State newState) {
- if (newState == UNINITIALIZED) {
+ if (newState == INITIALIZED) {
delete mSoftRenderer;
mSoftRenderer = NULL;
+ if (mCrypto != NULL) {
+ mCrypto->terminate();
+ mCrypto.clear();
+ }
+
mNativeWindow.clear();
mOutputFormat.clear();
@@ -1150,6 +1221,43 @@
info->mData->meta()->setInt32("csd", true);
}
+ if (mFlags & kFlagIsSecure) {
+ uint8_t iv[16];
+ memset(iv, 0, sizeof(iv));
+
+ ssize_t outLength;
+
+ if (mFlags & kFlagIsSoftwareCodec) {
+ outLength = mCrypto->decryptAudio(
+ (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
+ (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
+ info->mEncryptedData->base() + offset,
+ size,
+ info->mData->base(),
+ info->mData->capacity());
+ } else {
+ outLength = mCrypto->decryptVideo(
+ (flags & BUFFER_FLAG_ENCRYPTED) ? iv : NULL,
+ (flags & BUFFER_FLAG_ENCRYPTED) ? sizeof(iv) : 0,
+ info->mEncryptedData->base() + offset,
+ size,
+ info->mData->base(),
+ 0 /* offset */);
+ }
+
+ if (outLength < 0) {
+ return outLength;
+ }
+
+ if ((size_t)outLength > info->mEncryptedData->capacity()) {
+ return -ERANGE;
+ }
+
+ info->mData->setRange(0, outLength);
+ } else if (flags & BUFFER_FLAG_ENCRYPTED) {
+ return -EINVAL;
+ }
+
reply->setBuffer("buffer", info->mData);
reply->post();
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index afd4763..224ec33 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -107,6 +107,11 @@
msg->setInt32("channel-count", numChannels);
msg->setInt32("sample-rate", sampleRate);
+
+ int32_t isADTS;
+ if (meta->findInt32(kKeyIsADTS, &isADTS)) {
+ msg->setInt32("is-adts", true);
+ }
}
int32_t maxInputSize;
@@ -232,6 +237,20 @@
msg->setBuffer("csd-1", buffer);
}
+ if (meta->findData(kKeyEMM, &type, &data, &size)) {
+ sp<ABuffer> emm = new ABuffer(size);
+ memcpy(emm->data(), data, size);
+
+ msg->setBuffer("emm", emm);
+ }
+
+ if (meta->findData(kKeyECM, &type, &data, &size)) {
+ sp<ABuffer> ecm = new ABuffer(size);
+ memcpy(ecm->data(), data, size);
+
+ msg->setBuffer("ecm", ecm);
+ }
+
*format = msg;
return OK;
@@ -267,13 +286,14 @@
info->mFinalResult = OK;
info->mSample = NULL;
info->mSampleTimeUs = -1ll;
- info->mFlags = 0;
+ info->mSampleFlags = 0;
+ info->mTrackFlags = 0;
const char *mime;
CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
- info->mFlags |= kIsVorbis;
+ info->mTrackFlags |= kIsVorbis;
}
return OK;
@@ -288,6 +308,7 @@
info->mSample = NULL;
info->mSampleTimeUs = -1ll;
+ info->mSampleFlags = 0;
}
}
}
@@ -306,6 +327,7 @@
info->mSample->release();
info->mSample = NULL;
info->mSampleTimeUs = -1ll;
+ info->mSampleFlags = 0;
}
} else if (info->mFinalResult != OK) {
continue;
@@ -323,11 +345,25 @@
info->mFinalResult = err;
info->mSampleTimeUs = -1ll;
+ info->mSampleFlags = 0;
continue;
} else {
CHECK(info->mSample != NULL);
CHECK(info->mSample->meta_data()->findInt64(
kKeyTime, &info->mSampleTimeUs));
+
+ info->mSampleFlags = 0;
+
+ int32_t val;
+ if (info->mSample->meta_data()->findInt32(
+ kKeyIsSyncFrame, &val) && val != 0) {
+ info->mSampleFlags |= SAMPLE_FLAG_SYNC;
+ }
+
+ if (info->mSample->meta_data()->findInt32(
+ kKeyScrambling, &val) && val != 0) {
+ info->mSampleFlags |= SAMPLE_FLAG_ENCRYPTED;
+ }
}
}
@@ -371,7 +407,7 @@
size_t sampleSize = info->mSample->range_length();
- if (info->mFlags & kIsVorbis) {
+ if (info->mTrackFlags & kIsVorbis) {
// Each sample's data is suffixed by the number of page samples
// or -1 if not available.
sampleSize += sizeof(int32_t);
@@ -387,7 +423,7 @@
memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
- if (info->mFlags & kIsVorbis) {
+ if (info->mTrackFlags & kIsVorbis) {
int32_t numPageSamples;
if (!info->mSample->meta_data()->findInt32(
kKeyValidSamples, &numPageSamples)) {
@@ -430,4 +466,17 @@
return OK;
}
+status_t NuMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
+ ssize_t minIndex = fetchTrackSamples();
+
+ if (minIndex < 0) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
+ *sampleFlags = info->mSampleFlags;
+
+ return OK;
+}
+
} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 8b6e9d5..9769f21 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -515,7 +515,12 @@
CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
- status_t err = setAACFormat(numChannels, sampleRate, bitRate);
+ int32_t isADTS;
+ if (!meta->findInt32(kKeyIsADTS, &isADTS)) {
+ isADTS = false;
+ }
+
+ status_t err = setAACFormat(numChannels, sampleRate, bitRate, isADTS);
if (err != OK) {
CODEC_LOGE("setAACFormat() failed (err = %d)", err);
return err;
@@ -3386,11 +3391,17 @@
}
}
-status_t OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate, int32_t bitRate) {
- if (numChannels > 2)
+status_t OMXCodec::setAACFormat(
+ int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) {
+ if (numChannels > 2) {
ALOGW("Number of channels: (%d) \n", numChannels);
+ }
if (mIsEncoder) {
+ if (isADTS) {
+ return -EINVAL;
+ }
+
//////////////// input port ////////////////////
setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
@@ -3445,7 +3456,9 @@
&profile, sizeof(profile));
if (err != OK) {
- CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err);
+ CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
+ "(err = %d)",
+ err);
return err;
}
} else {
@@ -3459,13 +3472,19 @@
profile.nChannels = numChannels;
profile.nSampleRate = sampleRate;
- profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+
+ profile.eAACStreamFormat =
+ isADTS
+ ? OMX_AUDIO_AACStreamFormatMP4ADTS
+ : OMX_AUDIO_AACStreamFormatMP4FF;
err = mOMX->setParameter(
mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile));
if (err != OK) {
- CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed (err = %d)", err);
+ CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed "
+ "(err = %d)",
+ err);
return err;
}
}
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 6d345bb..9df15eb 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,10 +31,6 @@
#include <media/stagefright/foundation/ADebug.h>
-#ifdef ANDROID_SIMULATOR
-#include <jni.h>
-#endif
-
namespace android {
TimedEventQueue::TimedEventQueue()
@@ -193,27 +189,10 @@
// static
void *TimedEventQueue::ThreadWrapper(void *me) {
-#ifdef ANDROID_SIMULATOR
- // The simulator runs everything as one process, so any
- // Binder calls happen on this thread instead of a thread
- // in another process. We therefore need to make sure that
- // this thread can do calls into interpreted code.
- // On the device this is not an issue because the remote
- // thread will already be set up correctly for this.
- JavaVM *vm;
- int numvms;
- JNI_GetCreatedJavaVMs(&vm, 1, &numvms);
- JNIEnv *env;
- vm->AttachCurrentThread(&env, NULL);
-#endif
-
androidSetThreadPriority(0, ANDROID_PRIORITY_FOREGROUND);
static_cast<TimedEventQueue *>(me)->threadEntry();
-#ifdef ANDROID_SIMULATOR
- vm->DetachCurrentThread();
-#endif
return NULL;
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index ea6c360..90f96c6 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -23,6 +23,7 @@
#include "pvmp4audiodecoder_api.h"
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
namespace android {
@@ -42,6 +43,7 @@
OMX_COMPONENTTYPE **component)
: SimpleSoftOMXComponent(name, callbacks, appData, component),
mConfig(new tPVMP4AudioDecoderExternal),
+ mIsADTS(false),
mDecoderBuf(NULL),
mInputBufferCount(0),
mUpsamplingFactor(2),
@@ -140,7 +142,12 @@
aacParams->nAACtools = 0;
aacParams->nAACERtools = 0;
aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
- aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+
+ aacParams->eAACStreamFormat =
+ mIsADTS
+ ? OMX_AUDIO_AACStreamFormatMP4ADTS
+ : OMX_AUDIO_AACStreamFormatMP4FF;
+
aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
if (!isConfigured()) {
@@ -215,6 +222,15 @@
return OMX_ErrorUndefined;
}
+ if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) {
+ mIsADTS = false;
+ } else if (aacParams->eAACStreamFormat
+ == OMX_AUDIO_AACStreamFormatMP4ADTS) {
+ mIsADTS = true;
+ } else {
+ return OMX_ErrorUndefined;
+ }
+
return OMX_ErrorNone;
}
@@ -299,8 +315,35 @@
mNumSamplesOutput = 0;
}
- mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
- mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ if (mIsADTS) {
+ // skip 30 bits, aac_frame_length follows.
+ // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
+
+ const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
+
+ CHECK_GE(inHeader->nFilledLen, 7);
+
+ bool protectionAbsent = (adtsHeader[1] & 1);
+
+ unsigned aac_frame_length =
+ ((adtsHeader[3] & 3) << 11)
+ | (adtsHeader[4] << 3)
+ | (adtsHeader[5] >> 5);
+
+ CHECK_GE(inHeader->nFilledLen, aac_frame_length);
+
+ size_t headerSize = (protectionAbsent ? 7 : 9);
+
+ mConfig->pInputBuffer = (UChar *)adtsHeader + headerSize;
+ mConfig->inputBufferCurrentLength = aac_frame_length - headerSize;
+
+ inHeader->nOffset += headerSize;
+ inHeader->nFilledLen -= headerSize;
+ } else {
+ mConfig->pInputBuffer = inHeader->pBuffer + inHeader->nOffset;
+ mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
+ }
+
mConfig->inputBufferMaxLength = 0;
mConfig->inputBufferUsedLength = 0;
mConfig->remainderBits = 0;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.h b/media/libstagefright/codecs/aacdec/SoftAAC.h
index 963fd27..da0b8ed 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.h
@@ -49,6 +49,7 @@
};
tPVMP4AudioDecoderExternal *mConfig;
+ bool mIsADTS;
void *mDecoderBuf;
size_t mInputBufferCount;
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index 61b76cf..dee786d 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -310,6 +310,16 @@
return !strncmp(mData, prefix, strlen(prefix));
}
+bool AString::endsWith(const char *suffix) const {
+ size_t suffixLen = strlen(suffix);
+
+ if (mSize < suffixLen) {
+ return false;
+ }
+
+ return !strcmp(mData + mSize - suffixLen, suffix);
+}
+
AString StringPrintf(const char *format, ...) {
va_list ap;
va_start(ap, format);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index d708ba6..e1ac53c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -117,6 +117,12 @@
mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs);
+ int32_t scrambling;
+ if (buffer->meta()->findInt32("scrambling", &scrambling)
+ && scrambling != 0) {
+ mediaBuffer->meta_data()->setInt32(kKeyScrambling, scrambling);
+ }
+
*out = mediaBuffer;
return OK;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 60749b3..37a594e 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3038,7 +3038,7 @@
}
final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
- if (IS_USER_BUILD) {
+ if (true || IS_USER_BUILD) {
return;
}
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3ecbf77..e430529 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -89,6 +89,7 @@
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.EventLog;
+import android.util.FloatMath;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -5261,8 +5262,8 @@
synchronized(mWindowMap) {
long ident = Binder.clearCallingIdentity();
- dw = mAppDisplayWidth;
- dh = mAppDisplayHeight;
+ dw = mCurDisplayWidth;
+ dh = mCurDisplayHeight;
int aboveAppLayer = mPolicy.windowTypeToLayerLw(
WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
@@ -5382,7 +5383,7 @@
Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
Matrix matrix = new Matrix();
ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
- matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
+ matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
Canvas canvas = new Canvas(bm);
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);