mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix setDataSourceFactory handling in DefaultMediaSourceFactory
The call doesn't currently reset the already loaded suppliers and factories. Also fix the supplier loading code to use a local copy of the current dataSourceFactory to avoid leaking an updated instance to a later invocation. Issue: androidx/media#116 #minor-release PiperOrigin-RevId: 460721541
This commit is contained in:
parent
9a616c0cee
commit
adc50515e9
@ -17,6 +17,9 @@
|
||||
* Use `SingleThreadExecutor` for releasing `AudioTrack` instances to avoid
|
||||
OutOfMemory errors when releasing multiple players at the same time
|
||||
([#10057](https://github.com/google/ExoPlayer/issues/10057)).
|
||||
* Fix implementation of `setDataSourceFactory` in
|
||||
`DefaultMediaSourceFactory`, which was non-functional in some cases
|
||||
([#116](https://github.com/androidx/media/issues/116)).
|
||||
* Extractors:
|
||||
* Add support for AVI
|
||||
([#2092](https://github.com/google/ExoPlayer/issues/2092)).
|
||||
|
@ -282,6 +282,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||
*/
|
||||
public DefaultMediaSourceFactory setDataSourceFactory(DataSource.Factory dataSourceFactory) {
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
delegateFactoryLoader.setDataSourceFactory(dataSourceFactory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -594,6 +595,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||
this.dataSourceFactory = dataSourceFactory;
|
||||
// TODO(b/233577470): Call MediaSource.Factory.setDataSourceFactory on each value when it
|
||||
// exists on the interface.
|
||||
mediaSourceFactorySuppliers.clear();
|
||||
mediaSourceFactories.clear();
|
||||
}
|
||||
}
|
||||
@ -627,6 +629,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||
}
|
||||
|
||||
@Nullable Supplier<MediaSource.Factory> mediaSourceFactorySupplier = null;
|
||||
DataSource.Factory dataSourceFactory = checkNotNull(this.dataSourceFactory);
|
||||
try {
|
||||
Class<? extends MediaSource.Factory> clazz;
|
||||
switch (contentType) {
|
||||
@ -634,19 +637,19 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||
clazz =
|
||||
Class.forName("androidx.media3.exoplayer.dash.DashMediaSource$Factory")
|
||||
.asSubclass(MediaSource.Factory.class);
|
||||
mediaSourceFactorySupplier = () -> newInstance(clazz, checkNotNull(dataSourceFactory));
|
||||
mediaSourceFactorySupplier = () -> newInstance(clazz, dataSourceFactory);
|
||||
break;
|
||||
case C.CONTENT_TYPE_SS:
|
||||
clazz =
|
||||
Class.forName("androidx.media3.exoplayer.smoothstreaming.SsMediaSource$Factory")
|
||||
.asSubclass(MediaSource.Factory.class);
|
||||
mediaSourceFactorySupplier = () -> newInstance(clazz, checkNotNull(dataSourceFactory));
|
||||
mediaSourceFactorySupplier = () -> newInstance(clazz, dataSourceFactory);
|
||||
break;
|
||||
case C.CONTENT_TYPE_HLS:
|
||||
clazz =
|
||||
Class.forName("androidx.media3.exoplayer.hls.HlsMediaSource$Factory")
|
||||
.asSubclass(MediaSource.Factory.class);
|
||||
mediaSourceFactorySupplier = () -> newInstance(clazz, checkNotNull(dataSourceFactory));
|
||||
mediaSourceFactorySupplier = () -> newInstance(clazz, dataSourceFactory);
|
||||
break;
|
||||
case C.CONTENT_TYPE_RTSP:
|
||||
clazz =
|
||||
@ -656,9 +659,7 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
|
||||
break;
|
||||
case C.CONTENT_TYPE_OTHER:
|
||||
mediaSourceFactorySupplier =
|
||||
() ->
|
||||
new ProgressiveMediaSource.Factory(
|
||||
checkNotNull(dataSourceFactory), extractorsFactory);
|
||||
() -> new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory);
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
|
@ -15,16 +15,21 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.dash;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.test.utils.FakeDataSource;
|
||||
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -82,4 +87,53 @@ public class DefaultMediaSourceFactoryTest {
|
||||
|
||||
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_DASH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMediaSource_withSetDataSourceFactory_usesDataSourceFactory() throws Exception {
|
||||
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext())
|
||||
.setDataSourceFactory(() -> fakeDataSource);
|
||||
|
||||
prepareDashUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
|
||||
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
createMediaSource_usingDefaultDataSourceFactoryAndSetDataSourceFactory_usesUpdatesDataSourceFactory()
|
||||
throws Exception {
|
||||
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||
|
||||
// Use default DataSource.Factory first.
|
||||
prepareDashUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
defaultMediaSourceFactory.setDataSourceFactory(() -> fakeDataSource);
|
||||
prepareDashUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
|
||||
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||
}
|
||||
|
||||
private static void prepareDashUrlAndWaitForPrepareError(
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory) throws Exception {
|
||||
MediaSource mediaSource =
|
||||
defaultMediaSourceFactory.createMediaSource(MediaItem.fromUri(URI_MEDIA + "/file.mpd"));
|
||||
getInstrumentation()
|
||||
.runOnMainSync(
|
||||
() ->
|
||||
mediaSource.prepareSource(
|
||||
(source, timeline) -> {}, /* mediaTransferListener= */ null, PlayerId.UNSET));
|
||||
// We don't expect this to prepare successfully.
|
||||
RobolectricUtil.runMainLooperUntil(
|
||||
() -> {
|
||||
try {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -15,16 +15,21 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.hls;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.test.utils.FakeDataSource;
|
||||
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -82,4 +87,53 @@ public class DefaultMediaSourceFactoryTest {
|
||||
|
||||
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_HLS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMediaSource_withSetDataSourceFactory_usesDataSourceFactory() throws Exception {
|
||||
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext())
|
||||
.setDataSourceFactory(() -> fakeDataSource);
|
||||
|
||||
prepareHlsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
|
||||
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
createMediaSource_usingDefaultDataSourceFactoryAndSetDataSourceFactory_usesUpdatesDataSourceFactory()
|
||||
throws Exception {
|
||||
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||
|
||||
// Use default DataSource.Factory first.
|
||||
prepareHlsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
defaultMediaSourceFactory.setDataSourceFactory(() -> fakeDataSource);
|
||||
prepareHlsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
|
||||
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||
}
|
||||
|
||||
private static void prepareHlsUrlAndWaitForPrepareError(
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory) throws Exception {
|
||||
MediaSource mediaSource =
|
||||
defaultMediaSourceFactory.createMediaSource(MediaItem.fromUri(URI_MEDIA + "/file.m3u8"));
|
||||
getInstrumentation()
|
||||
.runOnMainSync(
|
||||
() ->
|
||||
mediaSource.prepareSource(
|
||||
(source, timeline) -> {}, /* mediaTransferListener= */ null, PlayerId.UNSET));
|
||||
// We don't expect this to prepare successfully.
|
||||
RobolectricUtil.runMainLooperUntil(
|
||||
() -> {
|
||||
try {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ dependencies {
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:' + checkerframeworkCompatVersion
|
||||
compileOnly 'org.jetbrains.kotlin:kotlin-annotations-jvm:' + kotlinAnnotationsVersion
|
||||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||
testImplementation project(modulePrefix + 'test-utils-robolectric')
|
||||
testImplementation project(modulePrefix + 'test-utils')
|
||||
testImplementation 'org.robolectric:robolectric:' + robolectricVersion
|
||||
}
|
||||
|
@ -15,16 +15,21 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.smoothstreaming;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.exoplayer.analytics.PlayerId;
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
|
||||
import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.test.utils.FakeDataSource;
|
||||
import androidx.media3.test.utils.robolectric.RobolectricUtil;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.IOException;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@ -93,4 +98,53 @@ public class DefaultMediaSourceFactoryTest {
|
||||
|
||||
assertThat(supportedTypes).asList().containsExactly(C.CONTENT_TYPE_OTHER, C.CONTENT_TYPE_SS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMediaSource_withSetDataSourceFactory_usesDataSourceFactory() throws Exception {
|
||||
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext())
|
||||
.setDataSourceFactory(() -> fakeDataSource);
|
||||
|
||||
prepareSsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
|
||||
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
createMediaSource_usingDefaultDataSourceFactoryAndSetDataSourceFactory_usesUpdatesDataSourceFactory()
|
||||
throws Exception {
|
||||
FakeDataSource fakeDataSource = new FakeDataSource();
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory =
|
||||
new DefaultMediaSourceFactory((Context) ApplicationProvider.getApplicationContext());
|
||||
|
||||
// Use default DataSource.Factory first.
|
||||
prepareSsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
defaultMediaSourceFactory.setDataSourceFactory(() -> fakeDataSource);
|
||||
prepareSsUrlAndWaitForPrepareError(defaultMediaSourceFactory);
|
||||
|
||||
assertThat(fakeDataSource.getAndClearOpenedDataSpecs()).asList().isNotEmpty();
|
||||
}
|
||||
|
||||
private static void prepareSsUrlAndWaitForPrepareError(
|
||||
DefaultMediaSourceFactory defaultMediaSourceFactory) throws Exception {
|
||||
MediaSource mediaSource =
|
||||
defaultMediaSourceFactory.createMediaSource(MediaItem.fromUri(URI_MEDIA + "/file.ism"));
|
||||
getInstrumentation()
|
||||
.runOnMainSync(
|
||||
() ->
|
||||
mediaSource.prepareSource(
|
||||
(source, timeline) -> {}, /* mediaTransferListener= */ null, PlayerId.UNSET));
|
||||
// We don't expect this to prepare successfully.
|
||||
RobolectricUtil.runMainLooperUntil(
|
||||
() -> {
|
||||
try {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user