Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* Append content resume offset when skipping ad playback after seek
adjustment or auto transition
([2484](https://github.com/androidx/media/issues/2484)).
* Add API for setting and observing `MediaCodec` parameters dynamically
([#2794](https://github.com/androidx/media/pull/2794)).
* CompositionPlayer:
* Transformer:
* Track Selection:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2025 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
*
* https://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 androidx.media3.common;

import androidx.annotation.Nullable;
import androidx.media3.common.util.NullableType;
import androidx.media3.common.util.UnstableApi;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
* A collection of parameters to be applied to a {@link android.media.MediaCodec} instance.
*
* <p>This class provides type-safe methods to set and get codec parameters.
*/
@UnstableApi
public final class CodecParameters {

private final Map<String, @NullableType Object> params;

/** Creates an empty instance. */
public CodecParameters() {
params = new HashMap<>();
}

/**
* Creates a shallow copy of another {@link CodecParameters} instance.
*
* @param other The instance to copy.
*/
public CodecParameters(CodecParameters other) {
this();
params.putAll(other.params);
}

/**
* Sets an integer parameter value.
*
* @param key The parameter key.
* @param value The integer value.
*/
public void setInteger(String key, int value) {
params.put(key, value);
}

/**
* Sets a long parameter value.
*
* @param key The parameter key.
* @param value The long value.
*/
public void setLong(String key, long value) {
params.put(key, value);
}

/**
* Sets a float parameter value.
*
* @param key The parameter key.
* @param value The float value.
*/
public void setFloat(String key, float value) {
params.put(key, value);
}

/**
* Sets a string parameter value.
*
* @param key The parameter key.
* @param value The string value, or {@code null} to unset the key.
*/
public void setString(String key, @Nullable String value) {
params.put(key, value);
}

/**
* Sets a byte buffer parameter value.
*
* @param key The parameter key.
* @param value The ByteBuffer value, or {@code null} to unset the key.
*/
public void setByteBuffer(String key, @Nullable ByteBuffer value) {
params.put(key, value);
}

/**
* Retrieves a parameter value by its key.
*
* @param key A string representing the key of the codec parameter.
* @return The value of the requested parameter, or {@code null} if the key is not present.
*/
@Nullable
public Object get(String key) {
return params.get(key);
}

/**
* Returns a Set containing the Keys from this CodecParameters's mapping.
*
* @return a Set of String keys
*/
public Set<String> keySet() {
return Collections.unmodifiableSet(params.keySet());
}

@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof CodecParameters)) {
return false;
}
CodecParameters other = (CodecParameters) obj;
return Objects.equals(this.params, other.params);
}

@Override
public int hashCode() {
return Objects.hashCode(params);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2025 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
*
* https://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 androidx.media3.common;

import androidx.media3.common.util.UnstableApi;
import java.util.List;

/** A listener for changes to codec parameters. */
@UnstableApi
public interface CodecParametersChangeListener {

/**
* Called when any of the codec parameters that any listener is subscribed to have changed.
*
* <p>The provided {@link CodecParameters} object contains the most recent values for all keys
* that are currently set in the underlying {@link android.media.MediaFormat} AND were included in
* the union of keys from {@link #getSubscribedKeys()} across all registered listeners at the time
* the change was detected.
*
* @param codecParameters A {@link CodecParameters} instance representing the current state of
* potentially all keys subscribed to by any listener.
*/
void onCodecParametersChanged(CodecParameters codecParameters);

/**
* Returns a list of parameter keys that the listener is interested in observing.
*
* @return A {@link List} of the subscribed keys.
*/
List<String> getSubscribedKeys();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,14 @@
import android.view.TextureView;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.AuxEffectInfo;
import androidx.media3.common.C;
import androidx.media3.common.CodecParameters;
import androidx.media3.common.CodecParametersChangeListener;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
import androidx.media3.common.MediaItem;
Expand Down Expand Up @@ -2025,4 +2028,41 @@ void setVideoChangeFrameRateStrategy(
*/
@UnstableApi
void setImageOutput(@Nullable ImageOutput imageOutput);

/**
* Sets a collection of parameters on the underlying {@link android.media.MediaCodec} instances.
*
* <p>This method is asynchronous. The parameters will be applied to the renderers on the playback
* thread. If an underlying decoder does not support a parameter, it will be ignored.
*
* @param codecParameters The {@link CodecParameters} to set.
*/
@UnstableApi
@RequiresApi(29)
void setCodecParameters(CodecParameters codecParameters);

/**
* Adds a listener for codec parameter changes.
*
* <p>This method is asynchronous. The listener will be added on the playback thread.
*
* <p><b>Note:</b> Observing vendor-specific parameter changes requires API level 31 or higher. On
* API levels 29 and 30, any requested vendor-specific keys will be ignored.
*
* @param listener The {@link CodecParametersChangeListener} to add.
*/
@UnstableApi
@RequiresApi(29)
void addCodecParametersChangeListener(CodecParametersChangeListener listener);

/**
* Removes a listener for codec parameter changes.
*
* <p>This method is asynchronous. The listener will be removed on the playback thread.
*
* @param listener The {@link CodecParametersChangeListener} to remove.
*/
@UnstableApi
@RequiresApi(29)
void removeCodecParametersChangeListener(CodecParametersChangeListener listener);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
import static androidx.media3.common.C.TRACK_TYPE_IMAGE;
import static androidx.media3.common.C.TRACK_TYPE_VIDEO;
import static androidx.media3.common.util.Util.castNonNull;
import static androidx.media3.exoplayer.Renderer.MSG_ADD_CODEC_PARAMETERS_LISTENER;
import static androidx.media3.exoplayer.Renderer.MSG_REMOVE_CODEC_PARAMETERS_LISTENER;
import static androidx.media3.exoplayer.Renderer.MSG_SET_AUDIO_ATTRIBUTES;
import static androidx.media3.exoplayer.Renderer.MSG_SET_AUDIO_OUTPUT_PROVIDER;
import static androidx.media3.exoplayer.Renderer.MSG_SET_AUDIO_SESSION_ID;
import static androidx.media3.exoplayer.Renderer.MSG_SET_AUX_EFFECT_INFO;
import static androidx.media3.exoplayer.Renderer.MSG_SET_CAMERA_MOTION_LISTENER;
import static androidx.media3.exoplayer.Renderer.MSG_SET_CHANGE_FRAME_RATE_STRATEGY;
import static androidx.media3.exoplayer.Renderer.MSG_SET_CODEC_PARAMETERS;
import static androidx.media3.exoplayer.Renderer.MSG_SET_IMAGE_OUTPUT;
import static androidx.media3.exoplayer.Renderer.MSG_SET_PREFERRED_AUDIO_DEVICE;
import static androidx.media3.exoplayer.Renderer.MSG_SET_PRIORITY;
Expand Down Expand Up @@ -62,6 +65,8 @@
import androidx.media3.common.BasePlayer;
import androidx.media3.common.C;
import androidx.media3.common.C.TrackType;
import androidx.media3.common.CodecParameters;
import androidx.media3.common.CodecParametersChangeListener;
import androidx.media3.common.DeviceInfo;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
Expand Down Expand Up @@ -2054,6 +2059,42 @@ public void setImageOutput(@Nullable ImageOutput imageOutput) {
sendRendererMessage(TRACK_TYPE_IMAGE, MSG_SET_IMAGE_OUTPUT, imageOutput);
}

@Override
@RequiresApi(29)
public void setCodecParameters(CodecParameters codecParameters) {
verifyApplicationThread();
checkNotNull(codecParameters);
for (Renderer renderer : renderers) {
createMessage(renderer).setType(MSG_SET_CODEC_PARAMETERS).setPayload(codecParameters).send();
}
}

@Override
@RequiresApi(29)
public void addCodecParametersChangeListener(CodecParametersChangeListener listener) {
verifyApplicationThread();
checkNotNull(listener);
for (Renderer renderer : renderers) {
createMessage(renderer)
.setType(MSG_ADD_CODEC_PARAMETERS_LISTENER)
.setPayload(listener)
.send();
}
}

@Override
@RequiresApi(29)
public void removeCodecParametersChangeListener(CodecParametersChangeListener listener) {
verifyApplicationThread();
checkNotNull(listener);
for (Renderer renderer : renderers) {
createMessage(renderer)
.setType(MSG_REMOVE_CODEC_PARAMETERS_LISTENER)
.setPayload(listener)
.send();
}
}

@SuppressWarnings("deprecation") // Calling deprecated methods.
/* package */ void setThrowsWhenUsingWrongThread(boolean throwsWhenUsingWrongThread) {
this.throwsWhenUsingWrongThread = throwsWhenUsingWrongThread;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.AuxEffectInfo;
import androidx.media3.common.C;
import androidx.media3.common.CodecParameters;
import androidx.media3.common.CodecParametersChangeListener;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
import androidx.media3.common.Player;
Expand Down Expand Up @@ -198,8 +200,10 @@ interface WakeupListener {
* #MSG_SET_AUDIO_SESSION_ID}, {@link #MSG_SET_WAKEUP_LISTENER}, {@link
* #MSG_SET_PREFERRED_AUDIO_DEVICE}, {@link #MSG_SET_VIDEO_EFFECTS}, {@link
* #MSG_SET_VIDEO_OUTPUT_RESOLUTION}, {@link #MSG_SET_IMAGE_OUTPUT}, {@link #MSG_SET_PRIORITY},
* {@link #MSG_TRANSFER_RESOURCES}, {@link #MSG_SET_SCRUBBING_MODE} or {@link
* #MSG_SET_VIRTUAL_DEVICE_ID}. May also be an app-defined value (see {@link #MSG_CUSTOM_BASE}).
* {@link #MSG_TRANSFER_RESOURCES}, {@link #MSG_SET_SCRUBBING_MODE}, {@link
* #MSG_SET_VIRTUAL_DEVICE_ID}, {@link #MSG_SET_CODEC_PARAMETERS}, {@link
* #MSG_ADD_CODEC_PARAMETERS_LISTENER} or {@link #MSG_REMOVE_CODEC_PARAMETERS_LISTENER}. May also
* be an app-defined value (see {@link #MSG_CUSTOM_BASE}).
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
Expand All @@ -225,7 +229,10 @@ interface WakeupListener {
MSG_SET_PRIORITY,
MSG_TRANSFER_RESOURCES,
MSG_SET_SCRUBBING_MODE,
MSG_SET_VIRTUAL_DEVICE_ID
MSG_SET_VIRTUAL_DEVICE_ID,
MSG_SET_CODEC_PARAMETERS,
MSG_ADD_CODEC_PARAMETERS_LISTENER,
MSG_REMOVE_CODEC_PARAMETERS_LISTENER
})
public @interface MessageType {}

Expand Down Expand Up @@ -391,6 +398,26 @@ interface WakeupListener {
*/
int MSG_SET_AUDIO_OUTPUT_PROVIDER = 20;

/**
* The type of a message that can be passed to renderers via {@link
* ExoPlayer#createMessage(PlayerMessage.Target)}. The message payload should be a {@link
* CodecParameters} instance.
*/
int MSG_SET_CODEC_PARAMETERS = 21;

/**
* The type of a message that can be passed to renderers via {@link
* ExoPlayer#createMessage(PlayerMessage.Target)}. The message payload must be a {@link
* CodecParametersChangeListener} instance.
*/
int MSG_ADD_CODEC_PARAMETERS_LISTENER = 22;

/**
* A message to remove a {@link CodecParametersChangeListener}. The message payload will be the
* listener to remove.
*/
int MSG_REMOVE_CODEC_PARAMETERS_LISTENER = 23;

/**
* Applications or extensions may define custom {@code MSG_*} constants that can be passed to
* renderers. These custom constants must be greater than or equal to this value.
Expand Down
Loading