tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a20df35f4aa93c6d111a9482927db93ecb642b84
parent d3db46b73621b7fe59ae086f4855efc7363144fe
Author: Ryan VanderMeulen <rvandermeulen@mozilla.com>
Date:   Thu, 30 Oct 2025 11:50:57 +0000

Bug 1991789 - Remove JellyBeanAsyncCodec. r=geckoview-reviewers,media-playback-reviewers,alwu,ohall

Differential Revision: https://phabricator.services.mozilla.com/D270356

Diffstat:
Mmobile/android/geckoview/src/main/java/org/mozilla/gecko/media/AsyncCodec.java | 8++++++--
Dmobile/android/geckoview/src/main/java/org/mozilla/gecko/media/AsyncCodecFactory.java | 19-------------------
Mmobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java | 2+-
Dmobile/android/geckoview/src/main/java/org/mozilla/gecko/media/JellyBeanAsyncCodec.java | 481-------------------------------------------------------------------------------
Mmobile/android/geckoview/src/main/java/org/mozilla/gecko/media/LollipopAsyncCodec.java | 7+------
5 files changed, 8 insertions(+), 509 deletions(-)

diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/AsyncCodec.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/AsyncCodec.java @@ -10,11 +10,15 @@ import android.media.MediaCrypto; import android.media.MediaFormat; import android.os.Handler; import android.view.Surface; +import java.io.IOException; import java.nio.ByteBuffer; -// A wrapper interface that mimics the new {@link android.media.MediaCodec} -// asynchronous mode API in Lollipop. +// A wrapper interface that mimics the new {@link android.media.MediaCodec} asynchronous mode API. public interface AsyncCodec { + static AsyncCodec create(final String name) throws IOException { + return new LollipopAsyncCodec(name); + } + interface Callbacks { void onInputBufferAvailable(AsyncCodec codec, int index); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/AsyncCodecFactory.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/AsyncCodecFactory.java @@ -1,19 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.gecko.media; - -import android.os.Build; -import java.io.IOException; - -public final class AsyncCodecFactory { - public static AsyncCodec create(final String name) throws IOException { - // A bug that getInputBuffer() could fail after flush() then start() wasn't fixed until MR1. - // See: - // https://android.googlesource.com/platform/frameworks/av/+/d9e0603a1be07dbb347c55050c7d4629ea7492e8 - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 - ? new LollipopAsyncCodec(name) - : new JellyBeanAsyncCodec(name); - } -} diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/Codec.java @@ -518,7 +518,7 @@ import org.mozilla.gecko.gfx.GeckoSurface; final int flags, final String drmStubId) { try { - final AsyncCodec codec = AsyncCodecFactory.create(name); + final AsyncCodec codec = AsyncCodec.create(name); codec.setCallbacks(new Callbacks(), null); final MediaCrypto crypto = RemoteMediaDrmBridgeStub.getMediaCrypto(drmStubId); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/JellyBeanAsyncCodec.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/JellyBeanAsyncCodec.java @@ -1,481 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.gecko.media; - -import android.media.MediaCodec; -import android.media.MediaCodecInfo.CodecCapabilities; -import android.media.MediaCrypto; -import android.media.MediaFormat; -import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.util.Log; -import android.view.Surface; -import java.io.IOException; -import java.nio.ByteBuffer; -import org.mozilla.gecko.util.HardwareCodecCapabilityUtils; - -// Implement async API using MediaCodec sync mode (API v16). -// This class uses internal worker thread/handler (mBufferPoller) to poll -// input and output buffer and notifies the client through callbacks. -final class JellyBeanAsyncCodec implements AsyncCodec { - private static final String LOGTAG = "GeckoAsyncCodecAPIv16"; - private static final boolean DEBUG = false; - - private static final int ERROR_CODEC = -10000; - - private abstract class CancelableHandler extends Handler { - private static final int MSG_CANCELLATION = 0x434E434C; // 'CNCL' - - protected CancelableHandler(final Looper looper) { - super(looper); - } - - protected void cancel() { - removeCallbacksAndMessages(null); - sendEmptyMessage(MSG_CANCELLATION); - // Wait until handleMessageLocked() is done. - synchronized (this) { - } - } - - protected boolean isCanceled() { - return hasMessages(MSG_CANCELLATION); - } - - // Subclass should implement this and return true if it handles msg. - // Warning: Never, ever call super.handleMessage() in this method! - protected abstract boolean handleMessageLocked(Message msg); - - public final void handleMessage(final Message msg) { - // Block cancel() during handleMessageLocked(). - synchronized (this) { - if (isCanceled() || handleMessageLocked(msg)) { - return; - } - } - - switch (msg.what) { - case MSG_CANCELLATION: - // Just a marker. Nothing to do here. - if (DEBUG) { - Log.d( - LOGTAG, - "handler " + this + " done cancellation, codec=" + JellyBeanAsyncCodec.this); - } - break; - default: - super.handleMessage(msg); - break; - } - } - } - - // A handler to invoke AsyncCodec.Callbacks methods. - private final class CallbackSender extends CancelableHandler { - private static final int MSG_INPUT_BUFFER_AVAILABLE = 1; - private static final int MSG_OUTPUT_BUFFER_AVAILABLE = 2; - private static final int MSG_OUTPUT_FORMAT_CHANGE = 3; - private static final int MSG_ERROR = 4; - private Callbacks mCallbacks; - - private CallbackSender(final Looper looper, final Callbacks callbacks) { - super(looper); - mCallbacks = callbacks; - } - - public void notifyInputBuffer(final int index) { - if (isCanceled()) { - return; - } - - final Message msg = obtainMessage(MSG_INPUT_BUFFER_AVAILABLE); - msg.arg1 = index; - processMessage(msg); - } - - private void processMessage(final Message msg) { - if (Looper.myLooper() == getLooper()) { - handleMessage(msg); - } else { - sendMessage(msg); - } - } - - public void notifyOutputBuffer(final int index, final MediaCodec.BufferInfo info) { - if (isCanceled()) { - return; - } - - final Message msg = obtainMessage(MSG_OUTPUT_BUFFER_AVAILABLE, info); - msg.arg1 = index; - processMessage(msg); - } - - public void notifyOutputFormat(final MediaFormat format) { - if (isCanceled()) { - return; - } - processMessage(obtainMessage(MSG_OUTPUT_FORMAT_CHANGE, format)); - } - - public void notifyError(final int result) { - Log.e(LOGTAG, "codec error:" + result); - processMessage(obtainMessage(MSG_ERROR, result, 0)); - } - - protected boolean handleMessageLocked(final Message msg) { - switch (msg.what) { - case MSG_INPUT_BUFFER_AVAILABLE: // arg1: buffer index. - mCallbacks.onInputBufferAvailable(JellyBeanAsyncCodec.this, msg.arg1); - break; - case MSG_OUTPUT_BUFFER_AVAILABLE: // arg1: buffer index, obj: info. - mCallbacks.onOutputBufferAvailable( - JellyBeanAsyncCodec.this, msg.arg1, (MediaCodec.BufferInfo) msg.obj); - break; - case MSG_OUTPUT_FORMAT_CHANGE: // obj: output format. - mCallbacks.onOutputFormatChanged(JellyBeanAsyncCodec.this, (MediaFormat) msg.obj); - break; - case MSG_ERROR: // arg1: error code. - mCallbacks.onError(JellyBeanAsyncCodec.this, msg.arg1); - break; - default: - return false; - } - - return true; - } - } - - // Handler to poll input and output buffers using dequeue(Input|Output)Buffer(), - // with 10ms time-out. Once triggered and successfully gets a buffer, it - // will schedule next polling until EOS or failure. To prevent it from - // automatically polling more buffer, use cancel() it inherits from - // CancelableHandler. - private final class BufferPoller extends CancelableHandler { - private static final int MSG_POLL_INPUT_BUFFERS = 1; - private static final int MSG_POLL_OUTPUT_BUFFERS = 2; - - private static final long DEQUEUE_TIMEOUT_US = 10000; - - public BufferPoller(final Looper looper) { - super(looper); - } - - private void schedulePollingIfNotCanceled(final int what) { - if (isCanceled()) { - return; - } - - schedulePolling(what); - } - - private void schedulePolling(final int what) { - if (needsBuffer(what)) { - sendEmptyMessage(what); - } - } - - private boolean needsBuffer(final int what) { - if (mOutputEnded && (what == MSG_POLL_OUTPUT_BUFFERS)) { - return false; - } - - return !(mInputEnded && (what == MSG_POLL_INPUT_BUFFERS)); - } - - protected boolean handleMessageLocked(final Message msg) { - try { - switch (msg.what) { - case MSG_POLL_INPUT_BUFFERS: - pollInputBuffer(); - break; - case MSG_POLL_OUTPUT_BUFFERS: - pollOutputBuffer(); - break; - default: - return false; - } - } catch (final IllegalStateException e) { - e.printStackTrace(); - mCallbackSender.notifyError(ERROR_CODEC); - } - - return true; - } - - private void pollInputBuffer() { - final int result = mCodec.dequeueInputBuffer(DEQUEUE_TIMEOUT_US); - if (result >= 0) { - mCallbackSender.notifyInputBuffer(result); - } else if (result == MediaCodec.INFO_TRY_AGAIN_LATER) { - mBufferPoller.schedulePollingIfNotCanceled(BufferPoller.MSG_POLL_INPUT_BUFFERS); - } else { - mCallbackSender.notifyError(result); - } - } - - private void pollOutputBuffer() { - boolean dequeueMoreBuffer = true; - final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); - final int result = mCodec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT_US); - if (result >= 0) { - if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { - mOutputEnded = true; - } - mCallbackSender.notifyOutputBuffer(result, info); - } else if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { - mOutputBuffers = mCodec.getOutputBuffers(); - } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - mOutputBuffers = mCodec.getOutputBuffers(); - mCallbackSender.notifyOutputFormat(mCodec.getOutputFormat()); - } else if (result == MediaCodec.INFO_TRY_AGAIN_LATER) { - // When input ended, keep polling remaining output buffer until EOS. - dequeueMoreBuffer = mInputEnded; - } else { - mCallbackSender.notifyError(result); - dequeueMoreBuffer = false; - } - - if (dequeueMoreBuffer) { - schedulePollingIfNotCanceled(MSG_POLL_OUTPUT_BUFFERS); - } - } - } - - private MediaCodec mCodec; - private ByteBuffer[] mInputBuffers; - private ByteBuffer[] mOutputBuffers; - private AsyncCodec.Callbacks mCallbacks; - private CallbackSender mCallbackSender; - - private BufferPoller mBufferPoller; - private volatile boolean mInputEnded; - private volatile boolean mOutputEnded; - - // Must be called on a thread with looper. - /* package */ JellyBeanAsyncCodec(final String name) throws IOException { - mCodec = MediaCodec.createByCodecName(name); - initBufferPoller(name + " buffer poller"); - } - - private void initBufferPoller(final String name) { - if (mBufferPoller != null) { - Log.e(LOGTAG, "poller already initialized"); - return; - } - final HandlerThread thread = new HandlerThread(name); - thread.start(); - mBufferPoller = new BufferPoller(thread.getLooper()); - if (DEBUG) { - Log.d(LOGTAG, "start poller for codec:" + this + ", thread=" + thread.getThreadId()); - } - } - - @Override - public void setCallbacks(final AsyncCodec.Callbacks callbacks, final Handler handler) { - if (callbacks == null) { - return; - } - - Looper looper = (handler == null) ? null : handler.getLooper(); - if (looper == null) { - // Use this thread if no handler supplied. - looper = Looper.myLooper(); - } - if (looper == null) { - // This thread has no looper. Use poller thread. - looper = mBufferPoller.getLooper(); - } - mCallbackSender = new CallbackSender(looper, callbacks); - if (DEBUG) { - Log.d(LOGTAG, "setCallbacks(): sender=" + mCallbackSender); - } - } - - @Override - public void configure( - final MediaFormat format, final Surface surface, final MediaCrypto crypto, final int flags) { - assertCallbacks(); - - mCodec.configure(format, surface, crypto, flags); - } - - @Override - public boolean isAdaptivePlaybackSupported(final String mimeType) { - return HardwareCodecCapabilityUtils.checkSupportsAdaptivePlayback(mCodec, mimeType); - } - - @Override - public boolean isTunneledPlaybackSupported(final String mimeType) { - try { - return mCodec - .getCodecInfo() - .getCapabilitiesForType(mimeType) - .isFeatureSupported(CodecCapabilities.FEATURE_TunneledPlayback); - } catch (final Exception e) { - return false; - } - } - - private void assertCallbacks() { - if (mCallbackSender == null) { - throw new IllegalStateException(LOGTAG + ": callback must be supplied with setCallbacks()."); - } - } - - @Override - public void start() { - assertCallbacks(); - - mCodec.start(); - mInputEnded = false; - mOutputEnded = false; - mInputBuffers = mCodec.getInputBuffers(); - resumeReceivingInputs(); - mOutputBuffers = mCodec.getOutputBuffers(); - } - - @Override - public void resumeReceivingInputs() { - for (int i = 0; i < mInputBuffers.length; i++) { - mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_INPUT_BUFFERS); - } - } - - @Override - public final void setBitrate(final int bps) { - final Bundle params = new Bundle(); - params.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, bps); - mCodec.setParameters(params); - } - - @Override - public final void queueInputBuffer( - final int index, - final int offset, - final int size, - final long presentationTimeUs, - final int flags) { - assertCallbacks(); - - mInputEnded = (flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; - - if (((flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0)) { - final Bundle params = new Bundle(); - params.putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0); - mCodec.setParameters(params); - } - - try { - mCodec.queueInputBuffer(index, offset, size, presentationTimeUs, flags); - } catch (final IllegalStateException e) { - e.printStackTrace(); - mCallbackSender.notifyError(ERROR_CODEC); - return; - } - - mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_OUTPUT_BUFFERS); - mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_INPUT_BUFFERS); - } - - @Override - public final void queueSecureInputBuffer( - final int index, - final int offset, - final MediaCodec.CryptoInfo cryptoInfo, - final long presentationTimeUs, - final int flags) { - assertCallbacks(); - - mInputEnded = (flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; - - try { - mCodec.queueSecureInputBuffer(index, offset, cryptoInfo, presentationTimeUs, flags); - } catch (final IllegalStateException e) { - e.printStackTrace(); - mCallbackSender.notifyError(ERROR_CODEC); - return; - } - - mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_INPUT_BUFFERS); - mBufferPoller.schedulePolling(BufferPoller.MSG_POLL_OUTPUT_BUFFERS); - } - - @Override - public final void releaseOutputBuffer(final int index, final boolean render) { - assertCallbacks(); - - mCodec.releaseOutputBuffer(index, render); - } - - @Override - public final ByteBuffer getInputBuffer(final int index) { - assertCallbacks(); - - return mInputBuffers[index]; - } - - @Override - public final ByteBuffer getOutputBuffer(final int index) { - assertCallbacks(); - - return mOutputBuffers[index]; - } - - @Override - public MediaFormat getInputFormat() { - return null; - } - - @Override - public void flush() { - assertCallbacks(); - - mInputEnded = false; - mOutputEnded = false; - cancelPendingTasks(); - mCodec.flush(); - } - - private void cancelPendingTasks() { - mBufferPoller.cancel(); - mCallbackSender.cancel(); - } - - @Override - public void stop() { - assertCallbacks(); - - cancelPendingTasks(); - mCodec.stop(); - } - - @Override - public void release() { - assertCallbacks(); - - cancelPendingTasks(); - mCallbackSender = null; - mCodec.release(); - stopBufferPoller(); - } - - private void stopBufferPoller() { - if (mBufferPoller == null) { - Log.e(LOGTAG, "no initialized poller."); - return; - } - - mBufferPoller.getLooper().quit(); - mBufferPoller = null; - - if (DEBUG) { - Log.d(LOGTAG, "stop poller " + this); - } - } -} diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/LollipopAsyncCodec.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/media/LollipopAsyncCodec.java @@ -9,7 +9,6 @@ import android.media.MediaCodecInfo.CodecCapabilities; import android.media.MediaCrypto; import android.media.MediaFormat; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -86,11 +85,7 @@ import org.mozilla.gecko.util.HardwareCodecCapabilityUtils; private void onError(final MediaCodec.CodecException e) { e.printStackTrace(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - notify(obtainMessage(MSG_ERROR, e.getErrorCode())); - } else { - notify(obtainMessage(MSG_ERROR, e.getLocalizedMessage())); - } + notify(obtainMessage(MSG_ERROR, e.getErrorCode())); } }