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

Commit f8289026 authored by Terry Heo's avatar Terry Heo Committed by Android Git Automerger
Browse files

am 4d85b87c: Merge "Add a frame capture API of TV input" into lmp-dev

* commit '4d85b87c91fe3cd39f052a2cb4fdbebbdf5eddcb':
  Add a frame capture API of TV input
parents d36795ea 9cc6b964
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -1095,6 +1095,13 @@
    <permission android:name="android.permission.TV_INPUT_HARDWARE"
        android:protectionLevel="signatureOrSystem" />

    <!-- @SystemApi Allows to capture a frame of TV input hardware such as
         built-in tuners and HDMI-in's.
         @hide <p>Not for use by third-party applications.
    -->
    <permission android:name="android.permission.CAPTURE_TV_INPUT"
        android:protectionLevel="signatureOrSystem" />

    <!-- @hide Allows enabling/disabling OEM unlock
   <p>Not for use by third-party applications. -->
    <permission android:name="android.permission.OEM_UNLOCK_STATE"
+6 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.media.tv.ITvInputHardwareCallback;
import android.media.tv.ITvInputManagerCallback;
import android.media.tv.TvInputHardwareInfo;
import android.media.tv.TvInputInfo;
import android.media.tv.TvStreamConfig;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
import android.os.Bundle;
@@ -67,4 +68,9 @@ interface ITvInputManager {
    ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback,
            in TvInputInfo info, int userId);
    void releaseTvInputHardware(int deviceId, in ITvInputHardware hardware, int userId);

    // For TV input capturing
    List<TvStreamConfig> getAvailableTvStreamConfigList(in String inputId, int userId);
    boolean captureFrame(in String inputId, in Surface surface, in TvStreamConfig config,
            int userId);
}
+35 −0
Original line number Diff line number Diff line
@@ -682,6 +682,41 @@ public final class TvInputManager {
        }
    }

    /**
     * Returns the TvStreamConfig list of the given TV input.
     *
     * @param inputId the id of the TV input.
     * @return List of {@link TvStreamConfig} which is available for capturing
     *   of the given TV input.
     * @hide
     */
    @SystemApi
    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId) {
        try {
            return mService.getAvailableTvStreamConfigList(inputId, mUserId);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Take a snapshot of the given TV input into the provided Surface.
     *
     * @param inputId the id of the TV input.
     * @param surface the {@link Surface} to which the snapshot is captured.
     * @param config the {@link TvStreamConfig} which is used for capturing.
     * @return true when the {@link Surface} is ready to be captured.
     * @hide
     */
    @SystemApi
    public boolean captureFrame(String inputId, Surface surface, TvStreamConfig config) {
        try {
            return mService.captureFrame(inputId, surface, config, mUserId);
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * The Session provides the per-session functionality of TV inputs.
     * @hide
+14 −1
Original line number Diff line number Diff line
@@ -40,16 +40,17 @@ final class TvInputHal implements Handler.Callback {
    public final static int ERROR_STALE_CONFIG = -2;
    public final static int ERROR_UNKNOWN = -3;

    // Below should be in sync with hardware/libhardware/include/hardware/tv_input.h
    public static final int EVENT_DEVICE_AVAILABLE = 1;
    public static final int EVENT_DEVICE_UNAVAILABLE = 2;
    public static final int EVENT_STREAM_CONFIGURATION_CHANGED = 3;
    public static final int EVENT_FIRST_FRAME_CAPTURED = 4;

    public interface Callback {
        public void onDeviceAvailable(
                TvInputHardwareInfo info, TvStreamConfig[] configs);
        public void onDeviceUnavailable(int deviceId);
        public void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs);
        public void onFirstFrameCaptured(int deviceId, int streamId);
    }

    private native long nativeOpen();
@@ -131,6 +132,11 @@ final class TvInputHal implements Handler.Callback {
        mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, 0).sendToTarget();
    }

    private void firstFrameCapturedFromNative(int deviceId, int streamId) {
        mHandler.sendMessage(
                mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId));
    }

    // Handler.Callback implementation

    private Queue<Message> mPendingMessageQueue = new LinkedList<Message>();
@@ -167,6 +173,13 @@ final class TvInputHal implements Handler.Callback {
                break;
            }

            case EVENT_FIRST_FRAME_CAPTURED: {
                int deviceId = msg.arg1;
                int streamId = msg.arg2;
                mCallback.onFirstFrameCaptured(deviceId, streamId);
                break;
            }

            default:
                Slog.e(TAG, "Unknown event: " + msg);
                return false;
+130 −0
Original line number Diff line number Diff line
@@ -172,6 +172,23 @@ class TvInputHardwareManager implements TvInputHal.Callback {
        }
    }

    @Override
    public void onFirstFrameCaptured(int deviceId, int streamId) {
        synchronized (mLock) {
            Connection connection = mConnections.get(deviceId);
            if (connection == null) {
                Slog.e(TAG, "FirstFrameCaptured: Cannot find a connection with "
                        + deviceId);
                return;
            }
            Runnable runnable = connection.getOnFirstFrameCapturedLocked();
            if (runnable != null) {
                runnable.run();
                connection.setOnFirstFrameCapturedLocked(null);
            }
        }
    }

    public List<TvInputHardwareInfo> getHardwareList() {
        synchronized (mLock) {
            return mInfoList;
@@ -337,6 +354,74 @@ class TvInputHardwareManager implements TvInputHal.Callback {
        return null;
    }

    private int findDeviceIdForInputIdLocked(String inputId) {
        for (int i = 0; i < mConnections.size(); ++i) {
            Connection connection = mConnections.get(i);
            if (connection.getInfoLocked().getId().equals(inputId)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * Get the list of TvStreamConfig which is buffered mode.
     */
    public List<TvStreamConfig> getAvailableTvStreamConfigList(String inputId, int callingUid,
            int resolvedUserId) {
        List<TvStreamConfig> configsList = new ArrayList<TvStreamConfig>();
        synchronized (mLock) {
            int deviceId = findDeviceIdForInputIdLocked(inputId);
            if (deviceId < 0) {
                Slog.e(TAG, "Invalid inputId : " + inputId);
                return configsList;
            }
            Connection connection = mConnections.get(deviceId);
            for (TvStreamConfig config : connection.getConfigsLocked()) {
                if (config.getType() == TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) {
                    configsList.add(config);
                }
            }
        }
        return configsList;
    }

    /**
     * Take a snapshot of the given TV input into the provided Surface.
     */
    public boolean captureFrame(String inputId, Surface surface, final TvStreamConfig config,
            int callingUid, int resolvedUserId) {
        synchronized (mLock) {
            int deviceId = findDeviceIdForInputIdLocked(inputId);
            if (deviceId < 0) {
                Slog.e(TAG, "Invalid inputId : " + inputId);
                return false;
            }
            Connection connection = mConnections.get(deviceId);
            final TvInputHardwareImpl hardwareImpl = connection.getHardwareImplLocked();
            if (hardwareImpl != null) {
                // Stop previous capture.
                Runnable runnable = connection.getOnFirstFrameCapturedLocked();
                if (runnable != null) {
                    runnable.run();
                    connection.setOnFirstFrameCapturedLocked(null);
                }

                boolean result = hardwareImpl.startCapture(surface, config);
                if (result) {
                    connection.setOnFirstFrameCapturedLocked(new Runnable() {
                        @Override
                        public void run() {
                            hardwareImpl.stopCapture(config);
                        }
                    });
                }
                return result;
            }
        }
        return false;
    }

    private class Connection implements IBinder.DeathRecipient {
        private final TvInputHardwareInfo mHardwareInfo;
        private TvInputInfo mInfo;
@@ -345,6 +430,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
        private TvStreamConfig[] mConfigs = null;
        private Integer mCallingUid = null;
        private Integer mResolvedUserId = null;
        private Runnable mOnFirstFrameCaptured;

        public Connection(TvInputHardwareInfo hardwareInfo) {
            mHardwareInfo = hardwareInfo;
@@ -367,6 +453,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            mInfo = info;
            mCallingUid = callingUid;
            mResolvedUserId = resolvedUserId;
            mOnFirstFrameCaptured = null;

            if (mHardware != null && mCallback != null) {
                try {
@@ -393,6 +480,10 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            return mHardware;
        }

        public TvInputHardwareImpl getHardwareImplLocked() {
            return mHardware;
        }

        public ITvInputHardwareCallback getCallbackLocked() {
            return mCallback;
        }
@@ -409,6 +500,14 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            return mResolvedUserId;
        }

        public void setOnFirstFrameCapturedLocked(Runnable runnable) {
            mOnFirstFrameCaptured = runnable;
        }

        public Runnable getOnFirstFrameCapturedLocked() {
            return mOnFirstFrameCaptured;
        }

        @Override
        public void binderDied() {
            synchronized (mLock) {
@@ -559,6 +658,37 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            // TODO(hdmi): mHdmiClient.sendKeyEvent(event);
            return false;
        }

        private boolean startCapture(Surface surface, TvStreamConfig config) {
            synchronized (mImplLock) {
                if (mReleased) {
                    return false;
                }
                if (surface == null || config == null) {
                    return false;
                }
                if (config.getType() != TvStreamConfig.STREAM_TYPE_BUFFER_PRODUCER) {
                    return false;
                }

                int result = mHal.addStream(mInfo.getDeviceId(), surface, config);
                return result == TvInputHal.SUCCESS;
            }
        }

        private boolean stopCapture(TvStreamConfig config) {
            synchronized (mImplLock) {
                if (mReleased) {
                    return false;
                }
                if (config == null) {
                    return false;
                }

                int result = mHal.removeStream(mInfo.getDeviceId(), config);
                return result == TvInputHal.SUCCESS;
            }
        }
    }

    interface Listener {
Loading