Merge "FINAL ATTEMPT: HTTP services are now provided from JAVA and made available to media code"
This commit is contained in:
committed by
Android (Google) Code Review
commit
cb1b23b5e6
@@ -260,6 +260,8 @@ LOCAL_SRC_FILES += \
|
||||
media/java/android/media/IAudioService.aidl \
|
||||
media/java/android/media/IAudioFocusDispatcher.aidl \
|
||||
media/java/android/media/IAudioRoutesObserver.aidl \
|
||||
media/java/android/media/IMediaHTTPConnection.aidl \
|
||||
media/java/android/media/IMediaHTTPService.aidl \
|
||||
media/java/android/media/IMediaRouterClient.aidl \
|
||||
media/java/android/media/IMediaRouterService.aidl \
|
||||
media/java/android/media/IMediaScannerListener.aidl \
|
||||
|
||||
33
media/java/android/media/IMediaHTTPConnection.aidl
Normal file
33
media/java/android/media/IMediaHTTPConnection.aidl
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.media;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
/** MUST STAY IN SYNC WITH NATIVE CODE at libmedia/IMediaHTTPConnection.{cpp,h} */
|
||||
|
||||
/** @hide */
|
||||
interface IMediaHTTPConnection
|
||||
{
|
||||
IBinder connect(in String uri, in String headers);
|
||||
void disconnect();
|
||||
|
||||
int readAt(long offset, int size);
|
||||
long getSize();
|
||||
String getMIMEType();
|
||||
}
|
||||
|
||||
27
media/java/android/media/IMediaHTTPService.aidl
Normal file
27
media/java/android/media/IMediaHTTPService.aidl
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.media;
|
||||
|
||||
import android.media.IMediaHTTPConnection;
|
||||
|
||||
/** MUST STAY IN SYNC WITH NATIVE CODE at libmedia/IMediaHTTPService.{cpp,h} */
|
||||
|
||||
/** @hide */
|
||||
interface IMediaHTTPService
|
||||
{
|
||||
IMediaHTTPConnection makeHTTPConnection();
|
||||
}
|
||||
@@ -21,7 +21,9 @@ import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaHTTPService;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
@@ -137,11 +139,19 @@ final public class MediaExtractor {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
setDataSource(path, keys, values);
|
||||
|
||||
nativeSetDataSource(
|
||||
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
|
||||
path,
|
||||
keys,
|
||||
values);
|
||||
}
|
||||
|
||||
private native final void setDataSource(
|
||||
String path, String[] keys, String[] values) throws IOException;
|
||||
private native final void nativeSetDataSource(
|
||||
IBinder httpServiceBinder,
|
||||
String path,
|
||||
String[] keys,
|
||||
String[] values) throws IOException;
|
||||
|
||||
/**
|
||||
* Sets the data source (file-path or http URL) to use.
|
||||
@@ -156,7 +166,11 @@ final public class MediaExtractor {
|
||||
* and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
|
||||
*/
|
||||
public final void setDataSource(String path) throws IOException {
|
||||
setDataSource(path, null, null);
|
||||
nativeSetDataSource(
|
||||
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
|
||||
path,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
263
media/java/android/media/MediaHTTPConnection.java
Normal file
263
media/java/android/media/MediaHTTPConnection.java
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.media;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import android.os.StrictMode;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.URL;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** @hide */
|
||||
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
||||
private static final String TAG = "MediaHTTPConnection";
|
||||
private static final boolean VERBOSE = false;
|
||||
|
||||
private long mCurrentOffset = -1;
|
||||
private URL mURL = null;
|
||||
private Map<String, String> mHeaders = null;
|
||||
private HttpURLConnection mConnection = null;
|
||||
private long mTotalSize = -1;
|
||||
private InputStream mInputStream = null;
|
||||
|
||||
public MediaHTTPConnection() {
|
||||
if (CookieHandler.getDefault() == null) {
|
||||
CookieHandler.setDefault(new CookieManager());
|
||||
}
|
||||
|
||||
native_setup();
|
||||
}
|
||||
|
||||
public IBinder connect(String uri, String headers) {
|
||||
if (VERBOSE) {
|
||||
Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
|
||||
}
|
||||
|
||||
try {
|
||||
disconnect();
|
||||
mURL = new URL(uri);
|
||||
mHeaders = convertHeaderStringToMap(headers);
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return native_getIMemory();
|
||||
}
|
||||
|
||||
private Map<String, String> convertHeaderStringToMap(String headers) {
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
|
||||
String[] pairs = headers.split("\r\n");
|
||||
for (String pair : pairs) {
|
||||
int colonPos = pair.indexOf(":");
|
||||
if (colonPos >= 0) {
|
||||
String key = pair.substring(0, colonPos);
|
||||
String val = pair.substring(colonPos + 1);
|
||||
|
||||
map.put(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
teardownConnection();
|
||||
mHeaders = null;
|
||||
mURL = null;
|
||||
}
|
||||
|
||||
private void teardownConnection() {
|
||||
if (mConnection != null) {
|
||||
mInputStream = null;
|
||||
|
||||
mConnection.disconnect();
|
||||
mConnection = null;
|
||||
|
||||
mCurrentOffset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void seekTo(long offset) throws IOException {
|
||||
teardownConnection();
|
||||
|
||||
try {
|
||||
mConnection = (HttpURLConnection)mURL.openConnection();
|
||||
|
||||
if (mHeaders != null) {
|
||||
for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
|
||||
mConnection.setRequestProperty(
|
||||
entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (offset > 0) {
|
||||
mConnection.setRequestProperty(
|
||||
"Range", "bytes=" + offset + "-");
|
||||
}
|
||||
|
||||
if (mConnection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
|
||||
// Partial content, we cannot just use getContentLength
|
||||
// because what we want is not just the length of the range
|
||||
// returned but the size of the full content if available.
|
||||
|
||||
String contentRange =
|
||||
mConnection.getHeaderField("Content-Range");
|
||||
|
||||
mTotalSize = -1;
|
||||
if (contentRange != null) {
|
||||
// format is "bytes xxx-yyy/zzz
|
||||
// where "zzz" is the total number of bytes of the
|
||||
// content or '*' if unknown.
|
||||
|
||||
int lastSlashPos = contentRange.lastIndexOf('/');
|
||||
if (lastSlashPos >= 0) {
|
||||
String total =
|
||||
contentRange.substring(lastSlashPos + 1);
|
||||
|
||||
try {
|
||||
mTotalSize = Long.parseLong(total);
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mConnection.getResponseCode()
|
||||
!= HttpURLConnection.HTTP_OK) {
|
||||
throw new IOException();
|
||||
} else {
|
||||
mTotalSize = mConnection.getContentLength();
|
||||
}
|
||||
|
||||
if (offset > 0
|
||||
&& mConnection.getResponseCode()
|
||||
!= HttpURLConnection.HTTP_PARTIAL) {
|
||||
// Some servers simply ignore "Range" requests and serve
|
||||
// data from the start of the content.
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
mInputStream =
|
||||
new BufferedInputStream(mConnection.getInputStream());
|
||||
|
||||
mCurrentOffset = offset;
|
||||
} catch (IOException e) {
|
||||
mTotalSize = -1;
|
||||
mInputStream = null;
|
||||
mConnection = null;
|
||||
mCurrentOffset = -1;
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public int readAt(long offset, int size) {
|
||||
return native_readAt(offset, size);
|
||||
}
|
||||
|
||||
private int readAt(long offset, byte[] data, int size) {
|
||||
StrictMode.ThreadPolicy policy =
|
||||
new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
||||
|
||||
StrictMode.setThreadPolicy(policy);
|
||||
|
||||
try {
|
||||
if (offset != mCurrentOffset) {
|
||||
seekTo(offset);
|
||||
}
|
||||
|
||||
int n = mInputStream.read(data, 0, size);
|
||||
|
||||
if (n == -1) {
|
||||
// InputStream signals EOS using a -1 result, our semantics
|
||||
// are to return a 0-length read.
|
||||
n = 0;
|
||||
}
|
||||
|
||||
mCurrentOffset += n;
|
||||
|
||||
if (VERBOSE) {
|
||||
Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
|
||||
}
|
||||
|
||||
return n;
|
||||
} catch (IOException e) {
|
||||
if (VERBOSE) {
|
||||
Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
|
||||
}
|
||||
return -1;
|
||||
} catch (Exception e) {
|
||||
if (VERBOSE) {
|
||||
Log.d(TAG, "unknown exception " + e);
|
||||
Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
if (mConnection == null) {
|
||||
try {
|
||||
seekTo(0);
|
||||
} catch (IOException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return mTotalSize;
|
||||
}
|
||||
|
||||
public String getMIMEType() {
|
||||
if (mConnection == null) {
|
||||
try {
|
||||
seekTo(0);
|
||||
} catch (IOException e) {
|
||||
return "application/octet-stream";
|
||||
}
|
||||
}
|
||||
|
||||
return mConnection.getContentType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
native_finalize();
|
||||
}
|
||||
|
||||
private static native final void native_init();
|
||||
private native final void native_setup();
|
||||
private native final void native_finalize();
|
||||
|
||||
private native final IBinder native_getIMemory();
|
||||
private native final int native_readAt(long offset, int size);
|
||||
|
||||
static {
|
||||
System.loadLibrary("media_jni");
|
||||
native_init();
|
||||
}
|
||||
|
||||
private int mNativeContext;
|
||||
}
|
||||
44
media/java/android/media/MediaHTTPService.java
Normal file
44
media/java/android/media/MediaHTTPService.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.media;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
/** @hide */
|
||||
public class MediaHTTPService extends IMediaHTTPService.Stub {
|
||||
private static final String TAG = "MediaHTTPService";
|
||||
|
||||
public MediaHTTPService() {
|
||||
}
|
||||
|
||||
public IMediaHTTPConnection makeHTTPConnection() {
|
||||
return new MediaHTTPConnection();
|
||||
}
|
||||
|
||||
/* package private */static IBinder createHttpServiceBinderIfNecessary(
|
||||
String path) {
|
||||
if (path.startsWith("http://")
|
||||
|| path.startsWith("https://")
|
||||
|| path.startsWith("widevine://")) {
|
||||
return (new MediaHTTPService()).asBinder();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
@@ -100,11 +101,16 @@ public class MediaMetadataRetriever
|
||||
values[i] = entry.getValue();
|
||||
++i;
|
||||
}
|
||||
_setDataSource(uri, keys, values);
|
||||
|
||||
_setDataSource(
|
||||
MediaHTTPService.createHttpServiceBinderIfNecessary(uri),
|
||||
uri,
|
||||
keys,
|
||||
values);
|
||||
}
|
||||
|
||||
private native void _setDataSource(
|
||||
String uri, String[] keys, String[] values)
|
||||
IBinder httpServiceBinder, String uri, String[] keys, String[] values)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.net.ProxyProperties;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
@@ -989,8 +990,18 @@ public class MediaPlayer implements SubtitleController.Listener
|
||||
}
|
||||
}
|
||||
|
||||
private native void _setDataSource(
|
||||
private void _setDataSource(
|
||||
String path, String[] keys, String[] values)
|
||||
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
|
||||
nativeSetDataSource(
|
||||
MediaHTTPService.createHttpServiceBinderIfNecessary(path),
|
||||
path,
|
||||
keys,
|
||||
values);
|
||||
}
|
||||
|
||||
private native void nativeSetDataSource(
|
||||
IBinder httpServiceBinder, String path, String[] keys, String[] values)
|
||||
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \
|
||||
android_media_MediaCodecList.cpp \
|
||||
android_media_MediaDrm.cpp \
|
||||
android_media_MediaExtractor.cpp \
|
||||
android_media_MediaHTTPConnection.cpp \
|
||||
android_media_MediaMuxer.cpp \
|
||||
android_media_MediaPlayer.cpp \
|
||||
android_media_MediaRecorder.cpp \
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "jni.h"
|
||||
#include "JNIHelp.h"
|
||||
|
||||
#include <media/IMediaHTTPService.h>
|
||||
#include <media/hardware/CryptoAPI.h>
|
||||
#include <media/stagefright/foundation/ABuffer.h>
|
||||
#include <media/stagefright/foundation/ADebug.h>
|
||||
@@ -35,6 +36,8 @@
|
||||
#include <media/stagefright/MetaData.h>
|
||||
#include <media/stagefright/NuMediaExtractor.h>
|
||||
|
||||
#include "android_util_Binder.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
struct fields_t {
|
||||
@@ -135,8 +138,10 @@ JMediaExtractor::~JMediaExtractor() {
|
||||
}
|
||||
|
||||
status_t JMediaExtractor::setDataSource(
|
||||
const char *path, const KeyedVector<String8, String8> *headers) {
|
||||
return mImpl->setDataSource(path, headers);
|
||||
const sp<IMediaHTTPService> &httpService,
|
||||
const char *path,
|
||||
const KeyedVector<String8, String8> *headers) {
|
||||
return mImpl->setDataSource(httpService, path, headers);
|
||||
}
|
||||
|
||||
status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
|
||||
@@ -661,7 +666,10 @@ static void android_media_MediaExtractor_native_setup(
|
||||
|
||||
static void android_media_MediaExtractor_setDataSource(
|
||||
JNIEnv *env, jobject thiz,
|
||||
jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) {
|
||||
jobject httpServiceBinderObj,
|
||||
jstring pathObj,
|
||||
jobjectArray keysArray,
|
||||
jobjectArray valuesArray) {
|
||||
sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
|
||||
|
||||
if (extractor == NULL) {
|
||||
@@ -686,7 +694,13 @@ static void android_media_MediaExtractor_setDataSource(
|
||||
return;
|
||||
}
|
||||
|
||||
status_t err = extractor->setDataSource(path, &headers);
|
||||
sp<IMediaHTTPService> httpService;
|
||||
if (httpServiceBinderObj != NULL) {
|
||||
sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
|
||||
httpService = interface_cast<IMediaHTTPService>(binder);
|
||||
}
|
||||
|
||||
status_t err = extractor->setDataSource(httpService, path, &headers);
|
||||
|
||||
env->ReleaseStringUTFChars(pathObj, path);
|
||||
path = NULL;
|
||||
@@ -839,8 +853,9 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "native_finalize", "()V",
|
||||
(void *)android_media_MediaExtractor_native_finalize },
|
||||
|
||||
{ "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;"
|
||||
"[Ljava/lang/String;)V",
|
||||
{ "nativeSetDataSource",
|
||||
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
|
||||
"[Ljava/lang/String;)V",
|
||||
(void *)android_media_MediaExtractor_setDataSource },
|
||||
|
||||
{ "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
struct IMediaHTTPService;
|
||||
struct MetaData;
|
||||
struct NuMediaExtractor;
|
||||
|
||||
@@ -36,6 +37,7 @@ struct JMediaExtractor : public RefBase {
|
||||
JMediaExtractor(JNIEnv *env, jobject thiz);
|
||||
|
||||
status_t setDataSource(
|
||||
const sp<IMediaHTTPService> &httpService,
|
||||
const char *path,
|
||||
const KeyedVector<String8, String8> *headers);
|
||||
|
||||
|
||||
179
media/jni/android_media_MediaHTTPConnection.cpp
Normal file
179
media/jni/android_media_MediaHTTPConnection.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2013, 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 "MediaHTTPConnection-JNI"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <binder/MemoryDealer.h>
|
||||
#include <media/stagefright/foundation/ADebug.h>
|
||||
#include <nativehelper/ScopedLocalRef.h>
|
||||
|
||||
#include "android_media_MediaHTTPConnection.h"
|
||||
#include "android_util_Binder.h"
|
||||
|
||||
#include "android_runtime/AndroidRuntime.h"
|
||||
#include "jni.h"
|
||||
#include "JNIHelp.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
JMediaHTTPConnection::JMediaHTTPConnection(JNIEnv *env, jobject thiz)
|
||||
: mClass(NULL),
|
||||
mObject(NULL),
|
||||
mByteArrayObj(NULL) {
|
||||
jclass clazz = env->GetObjectClass(thiz);
|
||||
CHECK(clazz != NULL);
|
||||
|
||||
mClass = (jclass)env->NewGlobalRef(clazz);
|
||||
mObject = env->NewWeakGlobalRef(thiz);
|
||||
|
||||
mDealer = new MemoryDealer(kBufferSize, "MediaHTTPConnection");
|
||||
mMemory = mDealer->allocate(kBufferSize);
|
||||
|
||||
ScopedLocalRef<jbyteArray> tmp(
|
||||
env, env->NewByteArray(JMediaHTTPConnection::kBufferSize));
|
||||
|
||||
mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
|
||||
}
|
||||
|
||||
JMediaHTTPConnection::~JMediaHTTPConnection() {
|
||||
JNIEnv *env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
env->DeleteGlobalRef(mByteArrayObj);
|
||||
mByteArrayObj = NULL;
|
||||
env->DeleteWeakGlobalRef(mObject);
|
||||
mObject = NULL;
|
||||
env->DeleteGlobalRef(mClass);
|
||||
mClass = NULL;
|
||||
}
|
||||
|
||||
sp<IMemory> JMediaHTTPConnection::getIMemory() {
|
||||
return mMemory;
|
||||
}
|
||||
|
||||
jbyteArray JMediaHTTPConnection::getByteArrayObj() {
|
||||
return mByteArrayObj;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
|
||||
using namespace android;
|
||||
|
||||
struct fields_t {
|
||||
jfieldID context;
|
||||
|
||||
jmethodID readAtMethodID;
|
||||
};
|
||||
|
||||
static fields_t gFields;
|
||||
|
||||
static sp<JMediaHTTPConnection> setObject(
|
||||
JNIEnv *env, jobject thiz, const sp<JMediaHTTPConnection> &conn) {
|
||||
sp<JMediaHTTPConnection> old =
|
||||
(JMediaHTTPConnection *)env->GetIntField(thiz, gFields.context);
|
||||
|
||||
if (conn != NULL) {
|
||||
conn->incStrong(thiz);
|
||||
}
|
||||
if (old != NULL) {
|
||||
old->decStrong(thiz);
|
||||
}
|
||||
env->SetIntField(thiz, gFields.context, (int)conn.get());
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
static sp<JMediaHTTPConnection> getObject(JNIEnv *env, jobject thiz) {
|
||||
return (JMediaHTTPConnection *)env->GetIntField(thiz, gFields.context);
|
||||
}
|
||||
|
||||
static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) {
|
||||
ScopedLocalRef<jclass> clazz(
|
||||
env, env->FindClass("android/media/MediaHTTPConnection"));
|
||||
CHECK(clazz.get() != NULL);
|
||||
|
||||
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "I");
|
||||
CHECK(gFields.context != NULL);
|
||||
|
||||
gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
|
||||
}
|
||||
|
||||
static void android_media_MediaHTTPConnection_native_setup(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
sp<JMediaHTTPConnection> conn = new JMediaHTTPConnection(env, thiz);
|
||||
|
||||
setObject(env, thiz, conn);
|
||||
}
|
||||
|
||||
static void android_media_MediaHTTPConnection_native_finalize(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
setObject(env, thiz, NULL);
|
||||
}
|
||||
|
||||
static jobject android_media_MediaHTTPConnection_native_getIMemory(
|
||||
JNIEnv *env, jobject thiz) {
|
||||
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
|
||||
|
||||
return javaObjectForIBinder(env, conn->getIMemory()->asBinder());
|
||||
}
|
||||
|
||||
static jint android_media_MediaHTTPConnection_native_readAt(
|
||||
JNIEnv *env, jobject thiz, jlong offset, jint size) {
|
||||
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
|
||||
|
||||
if (size > JMediaHTTPConnection::kBufferSize) {
|
||||
size = JMediaHTTPConnection::kBufferSize;
|
||||
}
|
||||
|
||||
jbyteArray byteArrayObj = conn->getByteArrayObj();
|
||||
|
||||
jint n = env->CallIntMethod(
|
||||
thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
|
||||
|
||||
if (n > 0) {
|
||||
env->GetByteArrayRegion(
|
||||
byteArrayObj,
|
||||
0,
|
||||
n,
|
||||
(jbyte *)conn->getIMemory()->pointer());
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
{ "native_getIMemory", "()Landroid/os/IBinder;",
|
||||
(void *)android_media_MediaHTTPConnection_native_getIMemory },
|
||||
|
||||
{ "native_readAt", "(JI)I",
|
||||
(void *)android_media_MediaHTTPConnection_native_readAt },
|
||||
|
||||
{ "native_init", "()V",
|
||||
(void *)android_media_MediaHTTPConnection_native_init },
|
||||
|
||||
{ "native_setup", "()V",
|
||||
(void *)android_media_MediaHTTPConnection_native_setup },
|
||||
|
||||
{ "native_finalize", "()V",
|
||||
(void *)android_media_MediaHTTPConnection_native_finalize },
|
||||
};
|
||||
|
||||
int register_android_media_MediaHTTPConnection(JNIEnv *env) {
|
||||
return AndroidRuntime::registerNativeMethods(env,
|
||||
"android/media/MediaHTTPConnection", gMethods, NELEM(gMethods));
|
||||
}
|
||||
|
||||
57
media/jni/android_media_MediaHTTPConnection.h
Normal file
57
media/jni/android_media_MediaHTTPConnection.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013, 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 _ANDROID_MEDIA_MEDIAHTTPCONNECTION_H_
|
||||
#define _ANDROID_MEDIA_MEDIAHTTPCONNECTION_H_
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
#include <media/stagefright/foundation/ABase.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
struct IMemory;
|
||||
struct MemoryDealer;
|
||||
|
||||
struct JMediaHTTPConnection : public RefBase {
|
||||
enum {
|
||||
kBufferSize = 32768,
|
||||
};
|
||||
|
||||
JMediaHTTPConnection(JNIEnv *env, jobject thiz);
|
||||
|
||||
sp<IMemory> getIMemory();
|
||||
|
||||
jbyteArray getByteArrayObj();
|
||||
|
||||
protected:
|
||||
virtual ~JMediaHTTPConnection();
|
||||
|
||||
private:
|
||||
jclass mClass;
|
||||
jweak mObject;
|
||||
jbyteArray mByteArrayObj;
|
||||
|
||||
sp<MemoryDealer> mDealer;
|
||||
sp<IMemory> mMemory;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(JMediaHTTPConnection);
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
#endif // _ANDROID_MEDIA_MEDIAHTTPCONNECTION_H_
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/threads.h>
|
||||
#include <core/SkBitmap.h>
|
||||
#include <media/IMediaHTTPService.h>
|
||||
#include <media/mediametadataretriever.h>
|
||||
#include <private/media/VideoFrame.h>
|
||||
|
||||
@@ -29,6 +30,7 @@
|
||||
#include "JNIHelp.h"
|
||||
#include "android_runtime/AndroidRuntime.h"
|
||||
#include "android_media_Utils.h"
|
||||
#include "android_util_Binder.h"
|
||||
|
||||
|
||||
using namespace android;
|
||||
@@ -80,7 +82,7 @@ static void setRetriever(JNIEnv* env, jobject thiz, MediaMetadataRetriever* retr
|
||||
|
||||
static void
|
||||
android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
|
||||
JNIEnv *env, jobject thiz, jstring path,
|
||||
JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
|
||||
jobjectArray keys, jobjectArray values) {
|
||||
|
||||
ALOGV("setDataSource");
|
||||
@@ -122,10 +124,19 @@ android_media_MediaMetadataRetriever_setDataSourceAndHeaders(
|
||||
env, keys, values, &headersVector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sp<IMediaHTTPService> httpService;
|
||||
if (httpServiceBinderObj != NULL) {
|
||||
sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
|
||||
httpService = interface_cast<IMediaHTTPService>(binder);
|
||||
}
|
||||
|
||||
process_media_retriever_call(
|
||||
env,
|
||||
retriever->setDataSource(
|
||||
pathStr.string(), headersVector.size() > 0 ? &headersVector : NULL),
|
||||
httpService,
|
||||
pathStr.string(),
|
||||
headersVector.size() > 0 ? &headersVector : NULL),
|
||||
|
||||
"java/lang/RuntimeException",
|
||||
"setDataSource failed");
|
||||
@@ -442,7 +453,7 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
|
||||
static JNINativeMethod nativeMethods[] = {
|
||||
{
|
||||
"_setDataSource",
|
||||
"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
|
||||
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
|
||||
(void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
|
||||
},
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "utils/Log.h"
|
||||
|
||||
#include <media/mediaplayer.h>
|
||||
#include <media/IMediaHTTPService.h>
|
||||
#include <media/MediaPlayerInterface.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
@@ -45,6 +46,7 @@
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
|
||||
#include "android_util_Binder.h"
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace android;
|
||||
@@ -183,7 +185,7 @@ static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStat
|
||||
|
||||
static void
|
||||
android_media_MediaPlayer_setDataSourceAndHeaders(
|
||||
JNIEnv *env, jobject thiz, jstring path,
|
||||
JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
|
||||
jobjectArray keys, jobjectArray values) {
|
||||
|
||||
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
|
||||
@@ -214,8 +216,15 @@ android_media_MediaPlayer_setDataSourceAndHeaders(
|
||||
return;
|
||||
}
|
||||
|
||||
sp<IMediaHTTPService> httpService;
|
||||
if (httpServiceBinderObj != NULL) {
|
||||
sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
|
||||
httpService = interface_cast<IMediaHTTPService>(binder);
|
||||
}
|
||||
|
||||
status_t opStatus =
|
||||
mp->setDataSource(
|
||||
httpService,
|
||||
pathStr,
|
||||
headersVector.size() > 0? &headersVector : NULL);
|
||||
|
||||
@@ -726,7 +735,8 @@ static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz
|
||||
}
|
||||
|
||||
static jint
|
||||
android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject java_reply)
|
||||
android_media_MediaPlayer_pullBatteryData(
|
||||
JNIEnv *env, jobject /* thiz */, jobject java_reply)
|
||||
{
|
||||
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
|
||||
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
|
||||
@@ -856,8 +866,9 @@ android_media_MediaPlayer_updateProxyConfig(
|
||||
|
||||
static JNINativeMethod gMethods[] = {
|
||||
{
|
||||
"_setDataSource",
|
||||
"(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
|
||||
"nativeSetDataSource",
|
||||
"(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
|
||||
"[Ljava/lang/String;)V",
|
||||
(void *)android_media_MediaPlayer_setDataSourceAndHeaders
|
||||
},
|
||||
|
||||
@@ -911,6 +922,7 @@ extern int register_android_media_Drm(JNIEnv *env);
|
||||
extern int register_android_media_MediaCodec(JNIEnv *env);
|
||||
extern int register_android_media_MediaExtractor(JNIEnv *env);
|
||||
extern int register_android_media_MediaCodecList(JNIEnv *env);
|
||||
extern int register_android_media_MediaHTTPConnection(JNIEnv *env);
|
||||
extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
|
||||
extern int register_android_media_MediaMuxer(JNIEnv *env);
|
||||
extern int register_android_media_MediaRecorder(JNIEnv *env);
|
||||
@@ -922,7 +934,7 @@ extern int register_android_mtp_MtpDatabase(JNIEnv *env);
|
||||
extern int register_android_mtp_MtpDevice(JNIEnv *env);
|
||||
extern int register_android_mtp_MtpServer(JNIEnv *env);
|
||||
|
||||
jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
|
||||
{
|
||||
JNIEnv* env = NULL;
|
||||
jint result = -1;
|
||||
@@ -1018,6 +1030,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (register_android_media_MediaHTTPConnection(env) < 0) {
|
||||
ALOGE("ERROR: MediaHTTPConnection native registration failed");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* success -- return valid version number */
|
||||
result = JNI_VERSION_1_4;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
using android::INVALID_OPERATION;
|
||||
using android::Surface;
|
||||
using android::IGraphicBufferProducer;
|
||||
using android::IMediaHTTPService;
|
||||
using android::MediaPlayerBase;
|
||||
using android::OK;
|
||||
using android::Parcel;
|
||||
@@ -57,6 +58,7 @@ class Player: public MediaPlayerBase
|
||||
virtual bool hardwareOutput() {return true;}
|
||||
|
||||
virtual status_t setDataSource(
|
||||
const sp<IMediaHTTPService> &httpService,
|
||||
const char *url,
|
||||
const KeyedVector<String8, String8> *) {
|
||||
ALOGV("setDataSource %s", url);
|
||||
|
||||
Reference in New Issue
Block a user