mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add MediaExtractor
contract test structure with one basic test
Additional tests will be added in future changes. PiperOrigin-RevId: 720555580
This commit is contained in:
parent
ddcf455d03
commit
8d22482f79
@ -0,0 +1,482 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* http://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.exoplayer;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
|
import android.media.MediaCodec;
|
||||||
|
import android.media.MediaDataSource;
|
||||||
|
import android.media.MediaExtractor;
|
||||||
|
import android.media.MediaFormat;
|
||||||
|
import android.media.metrics.LogSessionId;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.PersistableBundle;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameter;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contract tests for verifying consistent behavior across {@link MediaExtractor} implementations.
|
||||||
|
*
|
||||||
|
* <p>This tests both platform {@link MediaExtractor} and its compat implementation {@link
|
||||||
|
* MediaExtractorCompat}.
|
||||||
|
*/
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class MediaExtractorContractTest {
|
||||||
|
|
||||||
|
@Parameters(name = "{0}")
|
||||||
|
public static ImmutableList<Function<Context, MediaExtractorProxy>>
|
||||||
|
mediaExtractorProxyFactories() {
|
||||||
|
return ImmutableList.of(
|
||||||
|
new Function<Context, MediaExtractorProxy>() {
|
||||||
|
@Override
|
||||||
|
public MediaExtractorProxy apply(Context context) {
|
||||||
|
return new FrameworkMediaExtractorProxy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return FrameworkMediaExtractorProxy.class.getSimpleName();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Function<Context, MediaExtractorProxy>() {
|
||||||
|
@Override
|
||||||
|
public MediaExtractorProxy apply(Context context) {
|
||||||
|
return new CompatMediaExtractorProxy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return CompatMediaExtractorProxy.class.getSimpleName();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Parameter public Function<Context, MediaExtractorProxy> mediaExtractorProxyFactory;
|
||||||
|
|
||||||
|
private MediaExtractorProxy mediaExtractorProxy;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mediaExtractorProxy =
|
||||||
|
mediaExtractorProxyFactory.apply(ApplicationProvider.getApplicationContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
mediaExtractorProxy.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setDataSource_withAssetFileDescriptor_returnsCorrectTrackCount() throws IOException {
|
||||||
|
AssetFileDescriptor afd =
|
||||||
|
ApplicationProvider.getApplicationContext().getAssets().openFd("media/mp4/sample.mp4");
|
||||||
|
|
||||||
|
mediaExtractorProxy.setDataSource(afd);
|
||||||
|
|
||||||
|
assertThat(mediaExtractorProxy.getTrackCount()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FrameworkMediaExtractorProxy implements MediaExtractorProxy {
|
||||||
|
|
||||||
|
private final MediaExtractor mediaExtractor;
|
||||||
|
|
||||||
|
public FrameworkMediaExtractorProxy() {
|
||||||
|
this.mediaExtractor = new MediaExtractor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean advance() {
|
||||||
|
return mediaExtractor.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCachedDuration() {
|
||||||
|
return mediaExtractor.getCachedDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(24)
|
||||||
|
public Object getDrmInitData() {
|
||||||
|
return mediaExtractor.getDrmInitData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(31)
|
||||||
|
public LogSessionId getLogSessionId() {
|
||||||
|
return mediaExtractor.getLogSessionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(26)
|
||||||
|
public PersistableBundle getMetrics() {
|
||||||
|
return mediaExtractor.getMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<UUID, byte[]> getPsshInfo() {
|
||||||
|
return mediaExtractor.getPsshInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info) {
|
||||||
|
return mediaExtractor.getSampleCryptoInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSampleFlags() {
|
||||||
|
return mediaExtractor.getSampleFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(28)
|
||||||
|
public long getSampleSize() {
|
||||||
|
return mediaExtractor.getSampleSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSampleTime() {
|
||||||
|
return mediaExtractor.getSampleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSampleTrackIndex() {
|
||||||
|
return mediaExtractor.getSampleTrackIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTrackCount() {
|
||||||
|
return mediaExtractor.getTrackCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaFormat getTrackFormat(int trackIndex) {
|
||||||
|
return mediaExtractor.getTrackFormat(trackIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCacheReachedEndOfStream() {
|
||||||
|
return mediaExtractor.hasCacheReachedEndOfStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readSampleData(ByteBuffer buffer, int offset) {
|
||||||
|
return mediaExtractor.readSampleData(buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
mediaExtractor.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekTo(long timeUs, int mode) {
|
||||||
|
mediaExtractor.seekTo(timeUs, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectTrack(int trackIndex) {
|
||||||
|
mediaExtractor.selectTrack(trackIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(24)
|
||||||
|
public void setDataSource(AssetFileDescriptor assetFileDescriptor) throws IOException {
|
||||||
|
mediaExtractor.setDataSource(assetFileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(FileDescriptor fileDescriptor) throws IOException {
|
||||||
|
mediaExtractor.setDataSource(fileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(23)
|
||||||
|
public void setDataSource(MediaDataSource mediaDataSource) throws IOException {
|
||||||
|
mediaExtractor.setDataSource(mediaDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(Context context, Uri uri, @Nullable Map<String, String> headers)
|
||||||
|
throws IOException {
|
||||||
|
mediaExtractor.setDataSource(context, uri, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(FileDescriptor fileDescriptor, long offset, long length)
|
||||||
|
throws IOException {
|
||||||
|
mediaExtractor.setDataSource(fileDescriptor, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(String path) throws IOException {
|
||||||
|
mediaExtractor.setDataSource(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(String path, @Nullable Map<String, String> headers)
|
||||||
|
throws IOException {
|
||||||
|
mediaExtractor.setDataSource(path, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(31)
|
||||||
|
public void setLogSessionId(LogSessionId logSessionId) {
|
||||||
|
mediaExtractor.setLogSessionId(logSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unselectTrack(int trackIndex) {
|
||||||
|
mediaExtractor.unselectTrack(trackIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CompatMediaExtractorProxy implements MediaExtractorProxy {
|
||||||
|
|
||||||
|
private final MediaExtractorCompat mediaExtractorCompat;
|
||||||
|
|
||||||
|
public CompatMediaExtractorProxy(Context context) {
|
||||||
|
this.mediaExtractorCompat = new MediaExtractorCompat(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean advance() {
|
||||||
|
return mediaExtractorCompat.advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getCachedDuration() {
|
||||||
|
return mediaExtractorCompat.getCachedDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(24)
|
||||||
|
public Object getDrmInitData() {
|
||||||
|
return mediaExtractorCompat.getDrmInitData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(31)
|
||||||
|
public LogSessionId getLogSessionId() {
|
||||||
|
return mediaExtractorCompat.getLogSessionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(26)
|
||||||
|
public PersistableBundle getMetrics() {
|
||||||
|
return mediaExtractorCompat.getMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<UUID, byte[]> getPsshInfo() {
|
||||||
|
return mediaExtractorCompat.getPsshInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info) {
|
||||||
|
return mediaExtractorCompat.getSampleCryptoInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSampleFlags() {
|
||||||
|
return mediaExtractorCompat.getSampleFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(28)
|
||||||
|
public long getSampleSize() {
|
||||||
|
return mediaExtractorCompat.getSampleSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getSampleTime() {
|
||||||
|
return mediaExtractorCompat.getSampleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSampleTrackIndex() {
|
||||||
|
return mediaExtractorCompat.getSampleTrackIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTrackCount() {
|
||||||
|
return mediaExtractorCompat.getTrackCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MediaFormat getTrackFormat(int trackIndex) {
|
||||||
|
return mediaExtractorCompat.getTrackFormat(trackIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCacheReachedEndOfStream() {
|
||||||
|
return mediaExtractorCompat.hasCacheReachedEndOfStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int readSampleData(ByteBuffer buffer, int offset) {
|
||||||
|
return mediaExtractorCompat.readSampleData(buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void release() {
|
||||||
|
mediaExtractorCompat.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seekTo(long timeUs, int mode) {
|
||||||
|
mediaExtractorCompat.seekTo(timeUs, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selectTrack(int trackIndex) {
|
||||||
|
mediaExtractorCompat.selectTrack(trackIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(24)
|
||||||
|
public void setDataSource(AssetFileDescriptor assetFileDescriptor) throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(assetFileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(FileDescriptor fileDescriptor) throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(fileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(23)
|
||||||
|
public void setDataSource(MediaDataSource mediaDataSource) throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(mediaDataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(Context context, Uri uri, @Nullable Map<String, String> headers)
|
||||||
|
throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(context, uri, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(FileDescriptor fileDescriptor, long offset, long length)
|
||||||
|
throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(fileDescriptor, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(String path) throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDataSource(String path, @Nullable Map<String, String> headers)
|
||||||
|
throws IOException {
|
||||||
|
mediaExtractorCompat.setDataSource(path, headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@RequiresApi(31)
|
||||||
|
public void setLogSessionId(LogSessionId logSessionId) {
|
||||||
|
mediaExtractorCompat.setLogSessionId(logSessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unselectTrack(int trackIndex) {
|
||||||
|
mediaExtractorCompat.unselectTrack(trackIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") // TODO(b/392566318): Remove after adding tests for all methods.
|
||||||
|
private interface MediaExtractorProxy {
|
||||||
|
|
||||||
|
boolean advance();
|
||||||
|
|
||||||
|
long getCachedDuration();
|
||||||
|
|
||||||
|
@RequiresApi(24)
|
||||||
|
Object getDrmInitData();
|
||||||
|
|
||||||
|
@RequiresApi(31)
|
||||||
|
LogSessionId getLogSessionId();
|
||||||
|
|
||||||
|
@RequiresApi(26)
|
||||||
|
PersistableBundle getMetrics();
|
||||||
|
|
||||||
|
Map<UUID, byte[]> getPsshInfo();
|
||||||
|
|
||||||
|
boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info);
|
||||||
|
|
||||||
|
int getSampleFlags();
|
||||||
|
|
||||||
|
@RequiresApi(28)
|
||||||
|
long getSampleSize();
|
||||||
|
|
||||||
|
long getSampleTime();
|
||||||
|
|
||||||
|
int getSampleTrackIndex();
|
||||||
|
|
||||||
|
int getTrackCount();
|
||||||
|
|
||||||
|
MediaFormat getTrackFormat(int trackIndex);
|
||||||
|
|
||||||
|
boolean hasCacheReachedEndOfStream();
|
||||||
|
|
||||||
|
int readSampleData(ByteBuffer buffer, int offset);
|
||||||
|
|
||||||
|
void release();
|
||||||
|
|
||||||
|
void seekTo(long timeUs, @MediaExtractorCompat.SeekMode int mode);
|
||||||
|
|
||||||
|
void selectTrack(int trackIndex);
|
||||||
|
|
||||||
|
@RequiresApi(24)
|
||||||
|
void setDataSource(AssetFileDescriptor assetFileDescriptor) throws IOException;
|
||||||
|
|
||||||
|
void setDataSource(FileDescriptor fileDescriptor) throws IOException;
|
||||||
|
|
||||||
|
@RequiresApi(23)
|
||||||
|
void setDataSource(MediaDataSource mediaDataSource) throws IOException;
|
||||||
|
|
||||||
|
void setDataSource(Context context, Uri uri, @Nullable Map<String, String> headers)
|
||||||
|
throws IOException;
|
||||||
|
|
||||||
|
void setDataSource(FileDescriptor fileDescriptor, long offset, long length) throws IOException;
|
||||||
|
|
||||||
|
void setDataSource(String path) throws IOException;
|
||||||
|
|
||||||
|
void setDataSource(String path, @Nullable Map<String, String> headers) throws IOException;
|
||||||
|
|
||||||
|
@RequiresApi(31)
|
||||||
|
void setLogSessionId(LogSessionId logSessionId);
|
||||||
|
|
||||||
|
void unselectTrack(int trackIndex);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user