summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioDeviceInfo.java39
-rw-r--r--media/java/android/media/Image.java39
-rw-r--r--media/java/android/media/ImageReader.java123
-rw-r--r--media/java/android/media/ImageUtils.java16
-rw-r--r--media/java/android/media/ImageWriter.java93
-rw-r--r--media/java/android/media/MediaDataSource.java21
-rw-r--r--media/java/android/media/MediaPlayer.java34
-rw-r--r--media/java/android/media/MediaSync.java118
-rw-r--r--media/java/android/media/MediaTimestamp.java24
-rw-r--r--media/java/android/media/tv/DvbDeviceInfo.aidl20
-rw-r--r--media/java/android/media/tv/DvbDeviceInfo.java97
-rw-r--r--media/java/android/media/tv/ITvInputManager.aidl6
-rw-r--r--media/java/android/media/tv/TvInputManager.java59
-rw-r--r--media/jni/android_media_ImageReader.cpp18
-rw-r--r--media/jni/android_media_MediaDataSource.cpp15
-rw-r--r--media/jni/android_media_MediaExtractor.cpp5
-rw-r--r--media/jni/soundpool/SoundPool.cpp8
17 files changed, 418 insertions, 317 deletions
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index 566f8dc..0384d40 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -16,6 +16,7 @@
package android.media;
+import android.annotation.NonNull;
import android.util.SparseIntArray;
/**
@@ -121,8 +122,9 @@ public final class AudioDeviceInfo {
/**
* @return The human-readable name of the audio device.
*/
- public CharSequence getName() {
- return mPort.name();
+ public CharSequence getProductName() {
+ String portName = mPort.name();
+ return portName.length() != 0 ? portName : android.os.Build.MODEL;
}
/**
@@ -151,27 +153,38 @@ public final class AudioDeviceInfo {
/**
* @return An array of sample rates supported by the audio device.
*/
- public int[] getSampleRates() {
+ public @NonNull int[] getSampleRates() {
return mPort.samplingRates();
}
/**
- * @return An array of channel masks ({@link AudioFormat#CHANNEL_IN_STEREO},
- * {@link AudioFormat#CHANNEL_OUT_7POINT1) for which this audio device can be configured.
+ * @return An array of channel position masks (e.g. {@link AudioFormat#CHANNEL_IN_STEREO},
+ * {@link AudioFormat#CHANNEL_OUT_7POINT1}) for which this audio device can be configured.
*
* @see AudioFormat
*/
- public int[] getChannelMasks() {
+ public @NonNull int[] getChannelMasks() {
return mPort.channelMasks();
}
/**
- * @return An array of channel counts (1, 2, 4....) for which this audio device
+ * @return An array of channel index masks for which this audio device can be configured.
+ *
+ * @see AudioFormat
+ */
+ public @NonNull int[] getChannelIndexMasks() {
+ // TODO: implement
+ return new int[0];
+ }
+
+ /**
+ * @return An array of channel counts (1, 2, 4, ...) for which this audio device
* can be configured.
*/
- public int[] getChannelCounts() {
+ public @NonNull int[] getChannelCounts() {
int[] masks = getChannelMasks();
int[] counts = new int[masks.length];
+ // TODO: consider channel index masks
for (int mask_index = 0; mask_index < masks.length; mask_index++) {
counts[mask_index] = isSink()
? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
@@ -181,12 +194,16 @@ public final class AudioDeviceInfo {
}
/**
- * @return An array of audio format IDs (@link AudioFormat#ENCODING_PCM_16BIT,
- * {@link AudioFormat#ENCODING_PCM_FLOAT}...) supported by the audio device.
+ * @return An array of audio encodings (e.g. {@link AudioFormat#ENCODING_PCM_16BIT},
+ * {@link AudioFormat#ENCODING_PCM_FLOAT}) supported by the audio device.
+ * <code>ENCODING_PCM_FLOAT</code> indicates the device supports more
+ * than 16 bits of integer precision. Specifying <code>ENCODING_PCM_FLOAT</code>
+ * with {@link AudioTrack} or {@link AudioRecord} can preserve at least 24 bits of
+ * integer precision to that device.
*
* @see AudioFormat
*/
- public int[] getFormats() {
+ public @NonNull int[] getFormats() {
return mPort.formats();
}
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 195c987..e18e9a3 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -163,10 +163,12 @@ public abstract class Image implements AutoCloseable {
* Get the timestamp associated with this frame.
* <p>
* The timestamp is measured in nanoseconds, and is normally monotonically
- * increasing. However, the behavior of the timestamp depends on the source
- * of this image. See {@link android.hardware.Camera Camera},
- * {@link android.hardware.camera2.CameraDevice CameraDevice}, {@link MediaPlayer} and
- * {@link MediaCodec} for more details.
+ * increasing. The timestamps for the images from different sources may have
+ * different timebases therefore may not be comparable. The specific meaning and
+ * timebase of the timestamp depend on the source providing images. See
+ * {@link android.hardware.Camera Camera},
+ * {@link android.hardware.camera2.CameraDevice CameraDevice},
+ * {@link MediaPlayer} and {@link MediaCodec} for more details.
* </p>
*/
public abstract long getTimestamp();
@@ -175,9 +177,11 @@ public abstract class Image implements AutoCloseable {
* Set the timestamp associated with this frame.
* <p>
* The timestamp is measured in nanoseconds, and is normally monotonically
- * increasing. However, the behavior of the timestamp depends on
- * the destination of this image. See {@link android.hardware.Camera Camera}
- * , {@link android.hardware.camera2.CameraDevice CameraDevice},
+ * increasing. The timestamps for the images from different sources may have
+ * different timebases therefore may not be comparable. The specific meaning and
+ * timebase of the timestamp depend on the source providing images. See
+ * {@link android.hardware.Camera Camera},
+ * {@link android.hardware.camera2.CameraDevice CameraDevice},
* {@link MediaPlayer} and {@link MediaCodec} for more details.
* </p>
* <p>
@@ -195,18 +199,6 @@ public abstract class Image implements AutoCloseable {
return;
}
- /**
- * <p>Check if the image is opaque.</p>
- *
- * <p>The pixel data of opaque images are not accessible to the application,
- * and therefore {@link #getPlanes} will return an empty array for an opaque image.
- * </p>
- */
- public boolean isOpaque() {
- throwISEIfImageIsInvalid();
- return false;
- }
-
private Rect mCropRect;
/**
@@ -243,10 +235,11 @@ public abstract class Image implements AutoCloseable {
/**
* Get the array of pixel planes for this Image. The number of planes is
- * determined by the format of the Image. The application will get an
- * empty array if the image is opaque because the opaque image pixel data
- * is not directly accessible. The application can check if an image is
- * opaque by calling {@link Image#isOpaque}.
+ * determined by the format of the Image. The application will get an empty
+ * array if the image format is {@link android.graphics.ImageFormat#PRIVATE
+ * PRIVATE}, because the image pixel data is not directly accessible. The
+ * application can check the image format by calling
+ * {@link Image#getFormat()}.
*/
public abstract Plane[] getPlanes();
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 6d30208..9bd721a 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -68,76 +68,45 @@ public class ImageReader implements AutoCloseable {
private static final int ACQUIRE_MAX_IMAGES = 2;
/**
- * <p>Create a new reader for images of the desired size and format.</p>
- *
- * <p>The {@code maxImages} parameter determines the maximum number of {@link Image}
- * objects that can be be acquired from the {@code ImageReader}
- * simultaneously. Requesting more buffers will use up more memory, so it is
- * important to use only the minimum number necessary for the use case.</p>
- *
- * <p>The valid sizes and formats depend on the source of the image
- * data.</p>
- *
- * @param width
- * The default width in pixels of the Images that this reader will produce.
- * @param height
- * The default height in pixels of the Images that this reader will produce.
- * @param format
- * The format of the Image that this reader will produce. This
- * must be one of the {@link android.graphics.ImageFormat} or
- * {@link android.graphics.PixelFormat} constants. Note that
- * not all formats is supported, like ImageFormat.NV21.
- * @param maxImages
- * The maximum number of images the user will want to
- * access simultaneously. This should be as small as possible to limit
- * memory use. Once maxImages Images are obtained by the user, one of them
- * has to be released before a new Image will become available for access
- * through {@link #acquireLatestImage()} or {@link #acquireNextImage()}.
- * Must be greater than 0.
- *
- * @see Image
- */
- public static ImageReader newInstance(int width, int height, int format, int maxImages) {
- if (format == ImageFormat.PRIVATE) {
- throw new IllegalArgumentException("To obtain an opaque ImageReader, please use"
- + " newOpaqueInstance rather than newInstance");
- }
- return new ImageReader(width, height, format, maxImages);
- }
-
- /**
- * <p>
- * Create a new opaque reader for images of the desired size.
- * </p>
* <p>
- * An opaque {@link ImageReader} produces images that are not directly
- * accessible by the application. The application can still acquire images
- * from an opaque image reader, and send them to the
- * {@link android.hardware.camera2.CameraDevice camera} for reprocessing via
- * {@link ImageWriter} interface. However, the {@link Image#getPlanes()
- * getPlanes()} will return an empty array for opaque images. The
- * application can check if an existing reader is an opaque reader by
- * calling {@link #isOpaque()}.
+ * Create a new reader for images of the desired size and format.
* </p>
* <p>
* The {@code maxImages} parameter determines the maximum number of
* {@link Image} objects that can be be acquired from the
* {@code ImageReader} simultaneously. Requesting more buffers will use up
- * more memory, so it is important to use only the minimum number necessary.
+ * more memory, so it is important to use only the minimum number necessary
+ * for the use case.
* </p>
* <p>
* The valid sizes and formats depend on the source of the image data.
* </p>
* <p>
- * Opaque ImageReaders are more efficient to use when application access to
- * image data is not necessary, compared to ImageReaders using a non-opaque
- * format such as {@link ImageFormat#YUV_420_888 YUV_420_888}.
+ * If the {@code format} is {@link ImageFormat#PRIVATE PRIVATE}, the created
+ * {@link ImageReader} will produce images that are not directly accessible
+ * by the application. The application can still acquire images from this
+ * {@link ImageReader}, and send them to the
+ * {@link android.hardware.camera2.CameraDevice camera} for reprocessing via
+ * {@link ImageWriter} interface. However, the {@link Image#getPlanes()
+ * getPlanes()} will return an empty array for {@link ImageFormat#PRIVATE
+ * PRIVATE} format images. The application can check if an existing reader's
+ * format by calling {@link #getImageFormat()}.
+ * </p>
+ * <p>
+ * {@link ImageFormat#PRIVATE PRIVATE} format {@link ImageReader
+ * ImageReaders} are more efficient to use when application access to image
+ * data is not necessary, compared to ImageReaders using other format such
+ * as {@link ImageFormat#YUV_420_888 YUV_420_888}.
* </p>
*
* @param width The default width in pixels of the Images that this reader
* will produce.
* @param height The default height in pixels of the Images that this reader
* will produce.
+ * @param format The format of the Image that this reader will produce. This
+ * must be one of the {@link android.graphics.ImageFormat} or
+ * {@link android.graphics.PixelFormat} constants. Note that not
+ * all formats are supported, like ImageFormat.NV21.
* @param maxImages The maximum number of images the user will want to
* access simultaneously. This should be as small as possible to
* limit memory use. Once maxImages Images are obtained by the
@@ -147,8 +116,8 @@ public class ImageReader implements AutoCloseable {
* Must be greater than 0.
* @see Image
*/
- public static ImageReader newOpaqueInstance(int width, int height, int maxImages) {
- return new ImageReader(width, height, ImageFormat.PRIVATE, maxImages);
+ public static ImageReader newInstance(int width, int height, int format, int maxImages) {
+ return new ImageReader(width, height, format, maxImages);
}
/**
@@ -248,23 +217,6 @@ public class ImageReader implements AutoCloseable {
}
/**
- * <p>
- * Check if the {@link ImageReader} is an opaque reader.
- * </p>
- * <p>
- * An opaque image reader produces opaque images, see {@link Image#isOpaque}
- * for more details.
- * </p>
- *
- * @return true if the ImageReader is opaque.
- * @see Image#isOpaque
- * @see ImageReader#newOpaqueInstance
- */
- public boolean isOpaque() {
- return mFormat == ImageFormat.PRIVATE;
- }
-
- /**
* <p>Get a {@link Surface} that can be used to produce {@link Image Images} for this
* {@code ImageReader}.</p>
*
@@ -540,11 +492,11 @@ public class ImageReader implements AutoCloseable {
* </p>
* <p>
* This method can be used to achieve zero buffer copy for use cases like
- * {@link android.hardware.camera2.CameraDevice Camera2 API} OPAQUE and YUV
+ * {@link android.hardware.camera2.CameraDevice Camera2 API} PRIVATE and YUV
* reprocessing, where the application can select an output image from
* {@link ImageReader} and transfer this image directly to
* {@link ImageWriter}, where this image can be consumed by camera directly.
- * For OPAQUE reprocessing, this is the only way to send input buffers to
+ * For PRIVATE reprocessing, this is the only way to send input buffers to
* the {@link android.hardware.camera2.CameraDevice camera} for
* reprocessing.
* </p>
@@ -703,26 +655,26 @@ public class ImageReader implements AutoCloseable {
@Override
public int getFormat() {
throwISEIfImageIsInvalid();
+ int readerFormat = ImageReader.this.getImageFormat();
+ // Assume opaque reader always produce opaque images.
+ mFormat = (readerFormat == ImageFormat.PRIVATE) ? readerFormat :
+ nativeGetFormat(readerFormat);
return mFormat;
}
@Override
public int getWidth() {
throwISEIfImageIsInvalid();
- if (mWidth == -1) {
- mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() :
- nativeGetWidth(mFormat);
- }
+ mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() :
+ nativeGetWidth(mFormat);
return mWidth;
}
@Override
public int getHeight() {
throwISEIfImageIsInvalid();
- if (mHeight == -1) {
- mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() :
- nativeGetHeight(mFormat);
- }
+ mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() :
+ nativeGetHeight(mFormat);
return mHeight;
}
@@ -746,12 +698,6 @@ public class ImageReader implements AutoCloseable {
}
@Override
- public boolean isOpaque() {
- throwISEIfImageIsInvalid();
- return mFormat == ImageFormat.PRIVATE;
- }
-
- @Override
protected final void finalize() throws Throwable {
try {
close();
@@ -876,6 +822,7 @@ public class ImageReader implements AutoCloseable {
private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
private synchronized native int nativeGetWidth(int format);
private synchronized native int nativeGetHeight(int format);
+ private synchronized native int nativeGetFormat(int readerFormat);
}
private synchronized native void nativeInit(Object weakSelf, int w, int h,
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index 89313bf..c312525 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -57,7 +57,7 @@ class ImageUtils {
case ImageFormat.RAW_SENSOR:
case ImageFormat.RAW10:
return 1;
- case PixelFormat.OPAQUE:
+ case ImageFormat.PRIVATE:
return 0;
default:
throw new UnsupportedOperationException(
@@ -70,10 +70,11 @@ class ImageUtils {
* Copy source image data to destination Image.
* </p>
* <p>
- * Only support the copy between two non-opaque images with same properties
- * (format, size, etc.). The data from the source image will be copied to
- * the byteBuffers from the destination Image starting from position zero,
- * and the destination image will be rewound to zero after copy is done.
+ * Only support the copy between two non-{@link ImageFormat#PRIVATE PRIVATE} format
+ * images with same properties (format, size, etc.). The data from the
+ * source image will be copied to the byteBuffers from the destination Image
+ * starting from position zero, and the destination image will be rewound to
+ * zero after copy is done.
* </p>
*
* @param src The source image to be copied from.
@@ -88,8 +89,9 @@ class ImageUtils {
if (src.getFormat() != dst.getFormat()) {
throw new IllegalArgumentException("Src and dst images should have the same format");
}
- if (src.isOpaque() || dst.isOpaque()) {
- throw new IllegalArgumentException("Opaque image is not copyable");
+ if (src.getFormat() == ImageFormat.PRIVATE ||
+ dst.getFormat() == ImageFormat.PRIVATE) {
+ throw new IllegalArgumentException("PRIVATE format images are not copyable");
}
if (!(dst.getOwner() instanceof ImageWriter)) {
throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index f805339..2ef2519 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -33,8 +33,8 @@ import java.util.List;
/**
* <p>
* The ImageWriter class allows an application to produce Image data into a
- * {@link android.view.Surface}, and have it be consumed by another component like
- * {@link android.hardware.camera2.CameraDevice CameraDevice}.
+ * {@link android.view.Surface}, and have it be consumed by another component
+ * like {@link android.hardware.camera2.CameraDevice CameraDevice}.
* </p>
* <p>
* Several Android API classes can provide input {@link android.view.Surface
@@ -54,21 +54,21 @@ import java.util.List;
* <p>
* If the application already has an Image from {@link ImageReader}, the
* application can directly queue this Image into ImageWriter (via
- * {@link #queueInputImage}), potentially with zero buffer copies. For the opaque
- * Images produced by an opaque ImageReader (created by
- * {@link ImageReader#newOpaqueInstance}), this is the only way to send Image
- * data to ImageWriter, as the Image data aren't accessible by the application.
+ * {@link #queueInputImage}), potentially with zero buffer copies. For the
+ * {@link ImageFormat#PRIVATE PRIVATE} format Images produced by
+ * {@link ImageReader}, this is the only way to send Image data to ImageWriter,
+ * as the Image data aren't accessible by the application.
* </p>
- * Once new input Images are queued into an ImageWriter, it's up to the downstream
- * components (e.g. {@link ImageReader} or
+ * Once new input Images are queued into an ImageWriter, it's up to the
+ * downstream components (e.g. {@link ImageReader} or
* {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
* downstream components cannot consume the Images at least as fast as the
- * ImageWriter production rate, the {@link #dequeueInputImage} call will eventually
- * block and the application will have to drop input frames. </p>
+ * ImageWriter production rate, the {@link #dequeueInputImage} call will
+ * eventually block and the application will have to drop input frames. </p>
*/
public class ImageWriter implements AutoCloseable {
private final Object mListenerLock = new Object();
- private ImageListener mListener;
+ private OnImageReleasedListener mListener;
private ListenerHandler mListenerHandler;
private long mNativeContext;
@@ -168,32 +168,34 @@ public class ImageWriter implements AutoCloseable {
* This call will block if all available input images have been queued by
* the application and the downstream consumer has not yet consumed any.
* When an Image is consumed by the downstream consumer and released, an
- * {@link ImageListener#onInputImageReleased} callback will be fired, which
- * indicates that there is one input Image available. For non-opaque formats
- * (({@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE})), it is
+ * {@link OnImageReleasedListener#onImageReleased} callback will be fired,
+ * which indicates that there is one input Image available. For non-
+ * {@link ImageFormat#PRIVATE PRIVATE} formats (
+ * {@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE}), it is
* recommended to dequeue the next Image only after this callback is fired,
* in the steady state.
* </p>
* <p>
- * If the ImageWriter is opaque ({@link ImageWriter#getFormat()} ==
- * {@link ImageFormat#PRIVATE}), the image buffer is inaccessible to
- * the application, and calling this method will result in an
- * {@link IllegalStateException}. Instead, the application should acquire
- * opaque images from some other component (e.g. an opaque
+ * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
+ * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
+ * image buffer is inaccessible to the application, and calling this method
+ * will result in an {@link IllegalStateException}. Instead, the application
+ * should acquire images from some other component (e.g. an
* {@link ImageReader}), and queue them directly to this ImageWriter via the
* {@link ImageWriter#queueInputImage queueInputImage()} method.
* </p>
*
* @return The next available input Image from this ImageWriter.
* @throws IllegalStateException if {@code maxImages} Images are currently
- * dequeued, or the ImageWriter is opaque.
+ * dequeued, or the ImageWriter format is
+ * {@link ImageFormat#PRIVATE PRIVATE}.
* @see #queueInputImage
* @see Image#close
*/
public Image dequeueInputImage() {
if (mWriterFormat == ImageFormat.PRIVATE) {
throw new IllegalStateException(
- "Opaque ImageWriter doesn't support this operation since opaque images are"
+ "PRIVATE format ImageWriter doesn't support this operation since the images are"
+ " inaccessible to the application!");
}
@@ -229,10 +231,10 @@ public class ImageWriter implements AutoCloseable {
* </p>
* <p>
* After this method is called and the downstream consumer consumes and
- * releases the Image, an {@link ImageListener#onInputImageReleased
- * onInputImageReleased()} callback will fire. The application can use this
- * callback to avoid sending Images faster than the downstream consumer
- * processing rate in steady state.
+ * releases the Image, an {@link OnImageReleasedListener#onImageReleased}
+ * callback will fire. The application can use this callback to avoid
+ * sending Images faster than the downstream consumer processing rate in
+ * steady state.
* </p>
* <p>
* Passing in an Image from some other component (e.g. an
@@ -271,12 +273,12 @@ public class ImageWriter implements AutoCloseable {
}
ImageReader prevOwner = (ImageReader) image.getOwner();
- // Only do the image attach for opaque images for now. Do the image
+ // Only do the image attach for PRIVATE format images for now. Do the image
// copy for other formats. TODO: use attach for other formats to
// improve the performance, and fall back to copy when attach/detach
// fails. Right now, detach is guaranteed to fail as the buffer is
// locked when ImageReader#acquireNextImage is called. See bug 19962027.
- if (image.isOpaque()) {
+ if (image.getFormat() == ImageFormat.PRIVATE) {
prevOwner.detachImage(image);
attachAndQueueInputImage(image);
// This clears the native reference held by the original owner.
@@ -319,8 +321,9 @@ public class ImageWriter implements AutoCloseable {
* Get the ImageWriter format.
* <p>
* This format may be different than the Image format returned by
- * {@link Image#getFormat()}. However, if the ImageWriter is opaque (format
- * == {@link ImageFormat#PRIVATE}) , the images from it will also be opaque.
+ * {@link Image#getFormat()}. However, if the ImageWriter format is
+ * {@link ImageFormat#PRIVATE PRIVATE}, calling {@link #dequeueInputImage()}
+ * will result in an {@link IllegalStateException}.
* </p>
*
* @return The ImageWriter format.
@@ -333,7 +336,7 @@ public class ImageWriter implements AutoCloseable {
* ImageWriter callback interface, used to to asynchronously notify the
* application of various ImageWriter events.
*/
- public interface ImageListener {
+ public interface OnImageReleasedListener {
/**
* <p>
* Callback that is called when an input Image is released back to
@@ -361,7 +364,7 @@ public class ImageWriter implements AutoCloseable {
* @see ImageWriter
* @see Image
*/
- void onInputImageReleased(ImageWriter writer);
+ void onImageReleased(ImageWriter writer);
}
/**
@@ -375,7 +378,7 @@ public class ImageWriter implements AutoCloseable {
* @throws IllegalArgumentException If no handler specified and the calling
* thread has no looper.
*/
- public void setImageListener(ImageListener listener, Handler handler) {
+ public void setOnImageReleasedListener(OnImageReleasedListener listener, Handler handler) {
synchronized (mListenerLock) {
if (listener != null) {
Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
@@ -408,7 +411,7 @@ public class ImageWriter implements AutoCloseable {
*/
@Override
public void close() {
- setImageListener(null, null);
+ setOnImageReleasedListener(null, null);
for (Image image : mDequeuedImages) {
image.close();
}
@@ -431,19 +434,18 @@ public class ImageWriter implements AutoCloseable {
* Attach and queue input Image to this ImageWriter.
* </p>
* <p>
- * When an Image is from an opaque source (e.g. an opaque ImageReader
- * created by {@link ImageReader#newOpaqueInstance}), or the source Image is
- * so large that copying its data is too expensive, this method can be used
- * to migrate the source Image into ImageWriter without a data copy, and
- * then queue it to this ImageWriter. The source Image must be detached from
- * its previous owner already, or this call will throw an
+ * When the format of an Image is {@link ImageFormat#PRIVATE PRIVATE}, or
+ * the source Image is so large that copying its data is too expensive, this
+ * method can be used to migrate the source Image into ImageWriter without a
+ * data copy, and then queue it to this ImageWriter. The source Image must
+ * be detached from its previous owner already, or this call will throw an
* {@link IllegalStateException}.
* </p>
* <p>
* After this call, the ImageWriter takes ownership of this Image. This
* ownership will automatically be removed from this writer after the
* consumer releases this Image, that is, after
- * {@link ImageListener#onInputImageReleased}. The caller is responsible for
+ * {@link OnImageReleasedListener#onImageReleased}. The caller is responsible for
* closing this Image through {@link Image#close()} to free up the resources
* held by this Image.
* </p>
@@ -492,12 +494,12 @@ public class ImageWriter implements AutoCloseable {
@Override
public void handleMessage(Message msg) {
- ImageListener listener;
+ OnImageReleasedListener listener;
synchronized (mListenerLock) {
listener = mListener;
}
if (listener != null) {
- listener.onInputImageReleased(ImageWriter.this);
+ listener.onImageReleased(ImageWriter.this);
}
}
}
@@ -647,13 +649,6 @@ public class ImageWriter implements AutoCloseable {
}
@Override
- public boolean isOpaque() {
- throwISEIfImageIsInvalid();
-
- return getFormat() == ImageFormat.PRIVATE;
- }
-
- @Override
public Plane[] getPlanes() {
throwISEIfImageIsInvalid();
diff --git a/media/java/android/media/MediaDataSource.java b/media/java/android/media/MediaDataSource.java
index 246c0ef..948da0b 100644
--- a/media/java/android/media/MediaDataSource.java
+++ b/media/java/android/media/MediaDataSource.java
@@ -18,6 +18,7 @@
package android.media;
import java.io.Closeable;
+import java.io.IOException;
/**
* For supplying media data to the framework. Implement this if your app has
@@ -29,34 +30,32 @@ import java.io.Closeable;
* you don't need to do your own synchronization unless you're modifying the
* MediaDataSource from another thread while it's being used by the framework.</p>
*/
-public interface MediaDataSource extends Closeable {
+public abstract class MediaDataSource implements Closeable {
/**
* Called to request data from the given position.
*
* Implementations should should write up to {@code size} bytes into
* {@code buffer}, and return the number of bytes written.
*
- * Return {@code 0} to indicate that {@code position} is at, or beyond, the
- * end of the source.
+ * Return {@code 0} if size is zero (thus no bytes are read).
*
- * Return {@code -1} to indicate that a fatal error occurred. The failed
- * read will not be retried, so transient errors should be handled
- * internally.
- *
- * Throwing an exception from this method will have the same effect as
- * returning {@code -1}.
+ * Return {@code -1} to indicate that end of stream is reached.
*
* @param position the position in the data source to read from.
* @param buffer the buffer to read the data into.
+ * @param offset the offset within buffer to read the data into.
* @param size the number of bytes to read.
+ * @throws IOException on fatal errors.
* @return the number of bytes read, or -1 if there was an error.
*/
- public int readAt(long position, byte[] buffer, int size);
+ public abstract int readAt(long position, byte[] buffer, int offset, int size)
+ throws IOException;
/**
* Called to get the size of the data source.
*
+ * @throws IOException on fatal errors
* @return the size of data source in bytes, or -1 if the size is unknown.
*/
- public long getSize();
+ public abstract long getSize() throws IOException;
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 256ab29..e3a6a83 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1360,6 +1360,8 @@ public class MediaPlayer implements SubtitleController.Listener
* frequency.
* When rate is larger than 1.0, pitch becomes higher.
* When rate is smaller than 1.0, pitch becomes lower.
+ *
+ * @hide
*/
public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2;
@@ -1372,6 +1374,8 @@ public class MediaPlayer implements SubtitleController.Listener
* <p>
* This mode is only supported for a limited range of playback speed factors,
* e.g. between 1/2x and 2x.
+ *
+ * @hide
*/
public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1;
@@ -1383,6 +1387,8 @@ public class MediaPlayer implements SubtitleController.Listener
* Try to keep audio pitch when changing the playback rate, but allow the
* system to determine how to change audio playback if the rate is out
* of range.
+ *
+ * @hide
*/
public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0;
@@ -1406,8 +1412,11 @@ public class MediaPlayer implements SubtitleController.Listener
* @throws IllegalStateException if the internal player engine has not been
* initialized.
* @throws IllegalArgumentException if audioMode is not supported.
+ *
+ * @hide
*/
- public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) {
+ @NonNull
+ public PlaybackParams easyPlaybackParams(float rate, @PlaybackRateAudioMode int audioMode) {
PlaybackParams params = new PlaybackParams();
params.allowDefaults();
switch (audioMode) {
@@ -1425,7 +1434,7 @@ public class MediaPlayer implements SubtitleController.Listener
final String msg = "Audio playback mode " + audioMode + " is not supported";
throw new IllegalArgumentException(msg);
}
- setPlaybackParams(params);
+ return params;
}
/**
@@ -1481,23 +1490,22 @@ public class MediaPlayer implements SubtitleController.Listener
public native void seekTo(int msec) throws IllegalStateException;
/**
- * Get current playback position.
+ * Get current playback position as a {@link MediaTimestamp}.
* <p>
* The MediaTimestamp represents how the media time correlates to the system time in
- * a linear fashion. It contains the media time and system timestamp of an anchor frame
- * ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime})
- * and the speed of the media clock ({@link MediaTimestamp#clockRate}).
+ * a linear fashion using an anchor and a clock rate. During regular playback, the media
+ * time moves fairly constantly (though the anchor frame may be rebased to a current
+ * system time, the linear correlation stays steady). Therefore, this method does not
+ * need to be called often.
* <p>
- * During regular playback, the media time moves fairly constantly (though the
- * anchor frame may be rebased to a current system time, the linear correlation stays
- * steady). Therefore, this method does not need to be called often.
- * <p>
- * To help users to get current playback position, this method always returns the timestamp of
- * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They
- * can be used as current playback position.
+ * To help users get current playback position, this method always anchors the timestamp
+ * to the current {@link System#nanoTime system time}, so
+ * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
*
* @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
* is available, e.g. because the media player has not been initialized.
+ *
+ * @see MediaTimestamp
*/
@Nullable
public MediaTimestamp getTimestamp()
diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java
index d9e554c..b07931d 100644
--- a/media/java/android/media/MediaSync.java
+++ b/media/java/android/media/MediaSync.java
@@ -352,89 +352,6 @@ public final class MediaSync {
public native final Surface createInputSurface();
/**
- * Resample audio data when changing playback speed.
- * <p>
- * Resample the waveform based on the requested playback rate to get
- * a new waveform, and play back the new waveform at the original sampling
- * frequency.
- * <p><ul>
- * <li>When rate is larger than 1.0, pitch becomes higher.
- * <li>When rate is smaller than 1.0, pitch becomes lower.
- * </ul>
- */
- public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2;
-
- /**
- * Time stretch audio when changing playback speed.
- * <p>
- * Time stretching changes the duration of the audio samples without
- * affecting their pitch. This is only supported for a limited range
- * of playback speeds, e.g. from 1/2x to 2x. If the rate is adjusted
- * beyond this limit, the rate change will fail.
- */
- public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1;
-
- /**
- * Time stretch audio when changing playback speed, and may mute if
- * stretching is no longer supported.
- * <p>
- * Time stretching changes the duration of the audio samples without
- * affecting their pitch. This is only supported for a limited range
- * of playback speeds, e.g. from 1/2x to 2x. When it is no longer
- * supported, the audio may be muted. Using this mode will not fail
- * for non-negative playback rates.
- */
- public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0;
-
- /** @hide */
- @IntDef(
- value = {
- PLAYBACK_RATE_AUDIO_MODE_DEFAULT,
- PLAYBACK_RATE_AUDIO_MODE_STRETCH,
- PLAYBACK_RATE_AUDIO_MODE_RESAMPLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface PlaybackRateAudioMode {}
-
- /**
- * Sets playback rate and audio mode.
- *
- * @param rate the ratio between desired playback rate and normal one. 1.0 means normal
- * playback speed. 0.0 means pause. Value larger than 1.0 means faster playback,
- * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate
- * does not change as a result of this call. To restore the original rate at any time,
- * use 1.0.
- * @param audioMode audio playback mode. Must be one of the supported
- * audio modes.
- *
- * @throws IllegalStateException if the internal sync engine or the audio track has not
- * been initialized.
- * @throws IllegalArgumentException if audioMode is not supported.
- */
- public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) {
- PlaybackParams rateParams = new PlaybackParams();
- rateParams.allowDefaults();
- switch (audioMode) {
- case PLAYBACK_RATE_AUDIO_MODE_DEFAULT:
- rateParams.setSpeed(rate).setPitch(1.0f);
- break;
- case PLAYBACK_RATE_AUDIO_MODE_STRETCH:
- rateParams.setSpeed(rate).setPitch(1.0f)
- .setAudioFallbackMode(rateParams.AUDIO_FALLBACK_MODE_FAIL);
- break;
- case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE:
- rateParams.setSpeed(rate).setPitch(rate);
- break;
- default:
- {
- final String msg = "Audio playback mode " + audioMode + " is not supported";
- throw new IllegalArgumentException(msg);
- }
- }
- setPlaybackParams(rateParams);
- }
-
- /**
* Sets playback rate using {@link PlaybackParams}.
* <p>
* When using MediaSync with {@link AudioTrack}, set playback params using this
@@ -524,24 +441,23 @@ public final class MediaSync {
}
/**
- * Get current playback position.
- * <p>
- * The MediaTimestamp represents how the media time correlates to the system time in
- * a linear fashion. It contains the media time and system timestamp of an anchor frame
- * ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime})
- * and the speed of the media clock ({@link MediaTimestamp#clockRate}).
- * <p>
- * During regular playback, the media time moves fairly constantly (though the
- * anchor frame may be rebased to a current system time, the linear correlation stays
- * steady). Therefore, this method does not need to be called often.
- * <p>
- * To help users to get current playback position, this method always returns the timestamp of
- * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They
- * can be used as current playback position.
- *
- * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
- * is available, e.g. because the media sync has not been initialized.
- */
+ * Get current playback position.
+ * <p>
+ * The MediaTimestamp represents how the media time correlates to the system time in
+ * a linear fashion using an anchor and a clock rate. During regular playback, the media
+ * time moves fairly constantly (though the anchor frame may be rebased to a current
+ * system time, the linear correlation stays steady). Therefore, this method does not
+ * need to be called often.
+ * <p>
+ * To help users get current playback position, this method always anchors the timestamp
+ * to the current {@link System#nanoTime system time}, so
+ * {@link MediaTimestamp#getAnchorMediaTimeUs} can be used as current playback position.
+ *
+ * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp
+ * is available, e.g. because the media player has not been initialized.
+ *
+ * @see MediaTimestamp
+ */
@Nullable
public MediaTimestamp getTimestamp()
{
diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java
index d3d5618..5ea6bbe 100644
--- a/media/java/android/media/MediaTimestamp.java
+++ b/media/java/android/media/MediaTimestamp.java
@@ -37,22 +37,36 @@ package android.media;
public final class MediaTimestamp
{
/**
- * Media time in microseconds.
+ * Get the media time of the anchor in microseconds.
*/
- public final long mediaTimeUs;
+ public long getAnchorMediaTimeUs() {
+ return mediaTimeUs;
+ }
/**
- * The {@link java.lang.System#nanoTime system time} corresponding to the media time
+ * Get the {@link java.lang.System#nanoTime system time} corresponding to the media time
* in nanoseconds.
*/
- public final long nanoTime;
+ public long getAnchorSytemNanoTime() {
+ return nanoTime;
+ }
/**
- * The rate of the media clock in relation to the system time.
+ * Get the rate of the media clock in relation to the system time.
+ * <p>
* It is 1.0 if media clock advances in sync with the system clock;
* greater than 1.0 if media clock is faster than the system clock;
* less than 1.0 if media clock is slower than the system clock.
*/
+ public float getMediaClockRate() {
+ return clockRate;
+ }
+
+ /** @hide - accessor shorthand */
+ public final long mediaTimeUs;
+ /** @hide - accessor shorthand */
+ public final long nanoTime;
+ /** @hide - accessor shorthand */
public final float clockRate;
/** @hide */
diff --git a/media/java/android/media/tv/DvbDeviceInfo.aidl b/media/java/android/media/tv/DvbDeviceInfo.aidl
new file mode 100644
index 0000000..4851050
--- /dev/null
+++ b/media/java/android/media/tv/DvbDeviceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+ *
+ * Copyright 2015, 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.tv;
+
+parcelable DvbDeviceInfo; \ No newline at end of file
diff --git a/media/java/android/media/tv/DvbDeviceInfo.java b/media/java/android/media/tv/DvbDeviceInfo.java
new file mode 100644
index 0000000..1885a34
--- /dev/null
+++ b/media/java/android/media/tv/DvbDeviceInfo.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 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.tv;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.media.tv.TvInputManager;
+import android.util.Log;
+
+import java.lang.IllegalArgumentException;
+
+/**
+ * Simple container for information about DVB device.
+ * Not for third-party developers.
+ *
+ * @hide
+ */
+public final class DvbDeviceInfo implements Parcelable {
+ static final String TAG = "DvbDeviceInfo";
+
+ public static final Parcelable.Creator<DvbDeviceInfo> CREATOR =
+ new Parcelable.Creator<DvbDeviceInfo>() {
+ @Override
+ public DvbDeviceInfo createFromParcel(Parcel source) {
+ try {
+ return new DvbDeviceInfo(source);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating DvbDeviceInfo from parcel", e);
+ return null;
+ }
+ }
+
+ @Override
+ public DvbDeviceInfo[] newArray(int size) {
+ return new DvbDeviceInfo[size];
+ }
+ };
+
+ private final int mAdapterId;
+ private final int mDeviceId;
+
+ private DvbDeviceInfo(Parcel source) {
+ mAdapterId = source.readInt();
+ mDeviceId = source.readInt();
+ }
+
+ /**
+ * Constructs a new {@link DvbDeviceInfo} with the given adapter ID and device ID.
+ */
+ public DvbDeviceInfo(int adapterId, int deviceId) {
+ mAdapterId = adapterId;
+ mDeviceId = deviceId;
+ }
+
+ /**
+ * Returns the adapter ID of DVB device, in terms of enumerating the DVB device adapters
+ * installed in the system. The adapter ID counts from zero.
+ */
+ public int getAdapterId() {
+ return mAdapterId;
+ }
+
+ /**
+ * Returns the device ID of DVB device, in terms of enumerating the DVB devices attached to
+ * the same device adapter. The device ID counts from zero.
+ */
+ public int getDeviceId() {
+ return mDeviceId;
+ }
+
+ // Parcelable
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mAdapterId);
+ dest.writeInt(mDeviceId);
+ }
+}
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 078fb2f..6fe5dbb 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -18,6 +18,7 @@ package android.media.tv;
import android.content.ComponentName;
import android.graphics.Rect;
+import android.media.tv.DvbDeviceInfo;
import android.media.tv.ITvInputClient;
import android.media.tv.ITvInputHardware;
import android.media.tv.ITvInputHardwareCallback;
@@ -29,6 +30,7 @@ import android.media.tv.TvStreamConfig;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.view.Surface;
/**
@@ -91,4 +93,8 @@ interface ITvInputManager {
boolean captureFrame(in String inputId, in Surface surface, in TvStreamConfig config,
int userId);
boolean isSingleSessionActive(int userId);
+
+ // For DVB device binding
+ List<DvbDeviceInfo> getDvbDeviceList();
+ ParcelFileDescriptor openDvbDevice(in DvbDeviceInfo info, int device);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 705aa3d6..e74860e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -21,12 +21,14 @@ import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.graphics.Rect;
import android.media.MediaPlayer;
+import android.media.tv.DvbDeviceInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
@@ -42,6 +44,7 @@ import android.view.View;
import com.android.internal.util.Preconditions;
+import java.lang.IllegalArgumentException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
@@ -55,6 +58,25 @@ import java.util.Map;
public final class TvInputManager {
private static final String TAG = "TvInputManager";
+ static final int DVB_DEVICE_START = 0;
+ static final int DVB_DEVICE_END = 2;
+
+ /**
+ * A demux device of DVB API for controlling the filters of DVB hardware/software.
+ * @hide
+ */
+ public static final int DVB_DEVICE_DEMUX = DVB_DEVICE_START;
+ /**
+ * A DVR device of DVB API for reading transport streams.
+ * @hide
+ */
+ public static final int DVB_DEVICE_DVR = 1;
+ /**
+ * A frontend device of DVB API for controlling the tuner and DVB demodulator hardware.
+ * @hide
+ */
+ public static final int DVB_DEVICE_FRONTEND = DVB_DEVICE_END;
+
static final int VIDEO_UNAVAILABLE_REASON_START = 0;
static final int VIDEO_UNAVAILABLE_REASON_END = 4;
@@ -1258,6 +1280,43 @@ public final class TvInputManager {
}
/**
+ * Returns the list of currently available DVB devices on the system.
+ *
+ * @return the list of {@link DvbDeviceInfo} objects representing available DVB devices.
+ * @hide
+ */
+ public List<DvbDeviceInfo> getDvbDeviceList() {
+ try {
+ return mService.getDvbDeviceList();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Returns a {@link ParcelFileDescriptor} of a specified DVB device for a given
+ * {@link DvbDeviceInfo}
+ *
+ * @param info A {@link DvbDeviceInfo} to open a DVB device.
+ * @param device A DVB device. The DVB device can be {@link DVB_DEVICE_DEMUX},
+ * {@link DVB_DEVICE_DVR} or {@link DVB_DEVICE_FRONTEND}.
+ * @return a {@link ParcelFileDescriptor} of a specified DVB device for a given
+ * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo} was
+ * invalid or the specified DVB device was busy with a previous request.
+ * @hide
+ */
+ public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device) {
+ try {
+ if (DVB_DEVICE_START > device || DVB_DEVICE_END < device) {
+ throw new IllegalArgumentException("Invalid DVB device: " + device);
+ }
+ return mService.openDvbDevice(info, device);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
* The Session provides the per-session functionality of TV inputs.
* @hide
*/
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 043e20b..49614bd 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -1222,6 +1222,19 @@ static jint Image_getHeight(JNIEnv* env, jobject thiz, jint format)
}
}
+static jint Image_getFormat(JNIEnv* env, jobject thiz, jint readerFormat)
+{
+ if (isFormatOpaque(readerFormat)) {
+ // Assuming opaque reader produce opaque images.
+ return static_cast<jint>(PublicFormat::PRIVATE);
+ } else {
+ CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+ PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
+ buffer->flexFormat, buffer->dataSpace);
+ return static_cast<jint>(publicFmt);
+ }
+}
+
} // extern "C"
// ----------------------------------------------------------------------------
@@ -1240,8 +1253,9 @@ static JNINativeMethod gImageMethods[] = {
{"nativeImageGetBuffer", "(II)Ljava/nio/ByteBuffer;", (void*)Image_getByteBuffer },
{"nativeCreatePlane", "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
(void*)Image_createSurfacePlane },
- {"nativeGetWidth", "(I)I", (void*)Image_getWidth },
- {"nativeGetHeight", "(I)I", (void*)Image_getHeight },
+ {"nativeGetWidth", "(I)I", (void*)Image_getWidth },
+ {"nativeGetHeight", "(I)I", (void*)Image_getHeight },
+ {"nativeGetFormat", "(I)I", (void*)Image_getFormat },
};
int register_android_media_ImageReader(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaDataSource.cpp b/media/jni/android_media_MediaDataSource.cpp
index 1e6d2af..025133f 100644
--- a/media/jni/android_media_MediaDataSource.cpp
+++ b/media/jni/android_media_MediaDataSource.cpp
@@ -39,7 +39,7 @@ JMediaDataSource::JMediaDataSource(JNIEnv* env, jobject source)
ScopedLocalRef<jclass> mediaDataSourceClass(env, env->GetObjectClass(mMediaDataSourceObj));
CHECK(mediaDataSourceClass.get() != NULL);
- mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BI)I");
+ mReadMethod = env->GetMethodID(mediaDataSourceClass.get(), "readAt", "(J[BII)I");
CHECK(mReadMethod != NULL);
mGetSizeMethod = env->GetMethodID(mediaDataSourceClass.get(), "getSize", "()J");
CHECK(mGetSizeMethod != NULL);
@@ -80,7 +80,7 @@ ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jint numread = env->CallIntMethod(mMediaDataSourceObj, mReadMethod,
- (jlong)offset, mByteArrayObj, (jint)size);
+ (jlong)offset, mByteArrayObj, (jint)0, (jint)size);
if (env->ExceptionCheck()) {
ALOGW("An exception occurred in readAt()");
LOGW_EX(env);
@@ -89,9 +89,14 @@ ssize_t JMediaDataSource::readAt(off64_t offset, size_t size) {
return -1;
}
if (numread < 0) {
- ALOGW("An error occurred in readAt()");
- mJavaObjStatus = UNKNOWN_ERROR;
- return -1;
+ if (numread != -1) {
+ ALOGW("An error occurred in readAt()");
+ mJavaObjStatus = UNKNOWN_ERROR;
+ return -1;
+ } else {
+ // numread == -1 indicates EOF
+ return 0;
+ }
}
if ((size_t)numread > size) {
ALOGE("readAt read too many bytes.");
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index b6b7a80..4e9b726 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -715,6 +715,11 @@ static void android_media_MediaExtractor_setDataSourceCallback(
status_t err = extractor->setDataSource(bridge);
if (err != OK) {
+ // Clear bridge so that JMediaDataSource::close() is called _before_
+ // we throw the IOException.
+ // Otherwise close() gets called when we go out of scope, it calls
+ // Java with a pending exception and crashes the process.
+ bridge.clear();
jniThrowException(
env,
"java/io/IOException",
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 84ae3b4..6c1bd97 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -738,12 +738,16 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
// do not create a new audio track if current track is compatible with sample parameters
#ifdef USE_SHARED_MEM_BUFFER
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
- channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData);
+ channelMask, sample->getIMemory(), AUDIO_OUTPUT_FLAG_FAST, callback, userData,
+ 0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
+ AudioTrack::TRANSFER_DEFAULT,
+ NULL /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, mSoundPool->attributes());
#else
uint32_t bufferFrames = (totalFrames + (kDefaultBufferCount - 1)) / kDefaultBufferCount;
newTrack = new AudioTrack(streamType, sampleRate, sample->format(),
channelMask, frameCount, AUDIO_OUTPUT_FLAG_FAST, callback, userData,
- bufferFrames);
+ bufferFrames, AUDIO_SESSION_ALLOCATE, AudioTrack::TRANSFER_DEFAULT,
+ NULL /*offloadInfo*/, -1 /*uid*/, -1 /*pid*/, mSoundPool->attributes());
#endif
oldTrack = mAudioTrack;
status = newTrack->initCheck();