Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95c8a181 authored by Zim's avatar Zim
Browse files

Avoid transcoding in MediaPlayers

Test: Manual
Bug: 158466177
Change-Id: I71776e1e81002b1505f5094c92fdd10706d1268e
parent ae31181f
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -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 {
+17 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }

+22 −3
Original line number Diff line number Diff line
@@ -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);
            }
+22 −3
Original line number Diff line number Diff line
@@ -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 {
        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;
            }
+1 −1
Original line number Diff line number Diff line
@@ -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},