Avoid transcoding in MediaPlayers
Test: Manual Bug: 158466177 Change-Id: I71776e1e81002b1505f5094c92fdd10706d1268e
This commit is contained in:
@@ -40,9 +40,16 @@ import static android.system.OsConstants.W_OK;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
import android.app.AppGlobals;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ProviderInfo;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.provider.MediaStore;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.StructStat;
|
||||
@@ -118,6 +125,7 @@ public final class FileUtils {
|
||||
|
||||
// non-final so it can be toggled by Robolectric's ShadowFileUtils
|
||||
private static boolean sEnableCopyOptimizations = true;
|
||||
private static volatile int sMediaProviderAppId = -1;
|
||||
|
||||
private static final long COPY_CHECKPOINT_BYTES = 524288;
|
||||
|
||||
@@ -1424,6 +1432,54 @@ public final class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public static FileDescriptor convertToModernFd(FileDescriptor fd) {
|
||||
try {
|
||||
Context context = AppGlobals.getInitialApplication();
|
||||
if (UserHandle.getAppId(Process.myUid()) == getMediaProviderAppId(context)) {
|
||||
// Never convert modern fd for MediaProvider, because this requires
|
||||
// MediaStore#scanFile and can cause infinite loops when MediaProvider scans
|
||||
return null;
|
||||
}
|
||||
File realFile = ParcelFileDescriptor.getFile(fd);
|
||||
Log.i(TAG, "Changing to modern format dataSource for: " + realFile);
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
|
||||
Uri uri = MediaStore.scanFile(resolver, realFile);
|
||||
if (uri != null) {
|
||||
Bundle opts = new Bundle();
|
||||
// TODO(b/158465539): Use API constant
|
||||
opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true);
|
||||
AssetFileDescriptor afd = resolver.openTypedAssetFileDescriptor(uri, "*/*", opts);
|
||||
Log.i(TAG, "Changed to modern format dataSource for: " + realFile);
|
||||
return afd.getFileDescriptor();
|
||||
} else {
|
||||
Log.i(TAG, "Failed to change to modern format dataSource for: " + realFile);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Failed to change to modern format dataSource");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int getMediaProviderAppId(Context context) {
|
||||
if (sMediaProviderAppId != -1) {
|
||||
return sMediaProviderAppId;
|
||||
}
|
||||
|
||||
PackageManager pm = context.getPackageManager();
|
||||
ProviderInfo provider = context.getPackageManager().resolveContentProvider(
|
||||
MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
|
||||
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
|
||||
| PackageManager.MATCH_SYSTEM_ONLY);
|
||||
if (provider == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sMediaProviderAppId = UserHandle.getAppId(provider.applicationInfo.uid);
|
||||
return sMediaProviderAppId;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@VisibleForTesting
|
||||
public static class MemoryPipe extends Thread implements AutoCloseable {
|
||||
|
||||
@@ -31,6 +31,8 @@ import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.FileUtils;
|
||||
import android.os.SystemProperties;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
@@ -1523,6 +1525,11 @@ public class ExifInterface {
|
||||
if (fileDescriptor == null) {
|
||||
throw new NullPointerException("fileDescriptor cannot be null");
|
||||
}
|
||||
boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_exif_optimize", false);
|
||||
FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fileDescriptor) : null;
|
||||
if (modernFd != null) {
|
||||
fileDescriptor = modernFd;
|
||||
}
|
||||
|
||||
mAssetInputStream = null;
|
||||
mFilename = null;
|
||||
@@ -2533,11 +2540,20 @@ public class ExifInterface {
|
||||
|
||||
private void initForFilename(String filename) throws IOException {
|
||||
FileInputStream in = null;
|
||||
FileInputStream legacyInputStream = null;
|
||||
mAssetInputStream = null;
|
||||
mFilename = filename;
|
||||
mIsInputStream = false;
|
||||
try {
|
||||
in = new FileInputStream(filename);
|
||||
boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_exif_optimize",
|
||||
false);
|
||||
FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(in.getFD()) : null;
|
||||
if (modernFd != null) {
|
||||
legacyInputStream = in;
|
||||
in = new FileInputStream(modernFd);
|
||||
}
|
||||
|
||||
if (isSeekableFD(in.getFD())) {
|
||||
mSeekableFileDescriptor = in.getFD();
|
||||
} else {
|
||||
@@ -2546,6 +2562,7 @@ public class ExifInterface {
|
||||
loadAttributes(in);
|
||||
} finally {
|
||||
closeQuietly(in);
|
||||
closeQuietly(legacyInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,10 @@ import android.content.res.AssetFileDescriptor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemProperties;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
@@ -48,7 +51,6 @@ import java.util.Map;
|
||||
* frame and meta data from an input media file.
|
||||
*/
|
||||
public class MediaMetadataRetriever implements AutoCloseable {
|
||||
|
||||
// borrowed from ExoPlayer
|
||||
private static final String[] STANDARD_GENRES = new String[] {
|
||||
// These are the official ID3v1 genres.
|
||||
@@ -296,7 +298,19 @@ public class MediaMetadataRetriever implements AutoCloseable {
|
||||
* non-negative.
|
||||
* @throws IllegalArgumentException if the arguments are invalid
|
||||
*/
|
||||
public native void setDataSource(FileDescriptor fd, long offset, long length)
|
||||
public void setDataSource(FileDescriptor fd, long offset, long length)
|
||||
throws IllegalArgumentException {
|
||||
boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize",
|
||||
false);
|
||||
FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fd) : null;
|
||||
if (modernFd == null) {
|
||||
_setDataSource(fd, offset, length);
|
||||
} else {
|
||||
_setDataSource(modernFd, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
private native void _setDataSource(FileDescriptor fd, long offset, long length)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
@@ -340,7 +354,12 @@ public class MediaMetadataRetriever implements AutoCloseable {
|
||||
try {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
try {
|
||||
fd = resolver.openAssetFileDescriptor(uri, "r");
|
||||
boolean optimize =
|
||||
SystemProperties.getBoolean("fuse.sys.transcode_retriever_optimize", false);
|
||||
Bundle opts = new Bundle();
|
||||
opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true);
|
||||
fd = optimize ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts)
|
||||
: resolver.openAssetFileDescriptor(uri, "r");
|
||||
} catch(FileNotFoundException e) {
|
||||
throw new IllegalArgumentException("could not access " + uri);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import android.graphics.SurfaceTexture;
|
||||
import android.media.SubtitleController.Anchor;
|
||||
import android.media.SubtitleTrack.RenderingWidget;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
@@ -1104,7 +1106,13 @@ public class MediaPlayer extends PlayerBase
|
||||
}
|
||||
|
||||
private boolean attemptDataSource(ContentResolver resolver, Uri uri) {
|
||||
try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
|
||||
boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize",
|
||||
false);
|
||||
Bundle opts = new Bundle();
|
||||
opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true);
|
||||
try (AssetFileDescriptor afd = optimize
|
||||
? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts)
|
||||
: resolver.openAssetFileDescriptor(uri, "r")) {
|
||||
setDataSource(afd);
|
||||
return true;
|
||||
} catch (NullPointerException | SecurityException | IOException ex) {
|
||||
@@ -1245,7 +1253,13 @@ public class MediaPlayer extends PlayerBase
|
||||
*/
|
||||
public void setDataSource(FileDescriptor fd, long offset, long length)
|
||||
throws IOException, IllegalArgumentException, IllegalStateException {
|
||||
_setDataSource(fd, offset, length);
|
||||
boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize", false);
|
||||
FileDescriptor modernFd = optimize ? FileUtils.convertToModernFd(fd) : null;
|
||||
if (modernFd == null) {
|
||||
_setDataSource(fd, offset, length);
|
||||
} else {
|
||||
_setDataSource(modernFd, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
private native void _setDataSource(FileDescriptor fd, long offset, long length)
|
||||
@@ -2899,8 +2913,13 @@ public class MediaPlayer extends PlayerBase
|
||||
|
||||
AssetFileDescriptor fd = null;
|
||||
try {
|
||||
boolean optimize = SystemProperties.getBoolean("fuse.sys.transcode_player_optimize",
|
||||
false);
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
fd = resolver.openAssetFileDescriptor(uri, "r");
|
||||
Bundle opts = new Bundle();
|
||||
opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true);
|
||||
fd = optimize ? resolver.openTypedAssetFileDescriptor(uri, "*/*", opts)
|
||||
: resolver.openAssetFileDescriptor(uri, "r");
|
||||
if (fd == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -704,7 +704,7 @@ static const JNINativeMethod nativeMethods[] = {
|
||||
(void *)android_media_MediaMetadataRetriever_setDataSourceAndHeaders
|
||||
},
|
||||
|
||||
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
|
||||
{"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
|
||||
(void *)android_media_MediaMetadataRetriever_setDataSourceFD},
|
||||
{"_setDataSource", "(Landroid/media/MediaDataSource;)V",
|
||||
(void *)android_media_MediaMetadataRetriever_setDataSourceCallback},
|
||||
|
||||
Reference in New Issue
Block a user