scaleXY = Arrays.asList(selectedScale.split(", "));
+ checkState(scaleXY.size() == 2);
+ bundle.putFloat(SCALE_X, Float.valueOf(scaleXY.get(0)));
+ bundle.putFloat(SCALE_Y, Float.valueOf(scaleXY.get(1)));
+ }
+ String selectedRotate = String.valueOf(rotateSpinner.getSelectedItem());
+ if (!SAME_AS_INPUT_OPTION.equals(selectedRotate)) {
+ bundle.putFloat(ROTATE_DEGREES, Float.valueOf(selectedRotate));
+ }
+ transformerIntent.putExtras(bundle);
+
+ @Nullable Uri intentUri = getIntent().getData();
+ transformerIntent.setData(
+ intentUri != null ? intentUri : Uri.parse(INPUT_URIS[inputUriPosition]));
+
+ startActivity(transformerIntent);
+ }
+
+ private void chooseFile(View view) {
+ new AlertDialog.Builder(/* context= */ this)
+ .setTitle(R.string.choose_file_title)
+ .setSingleChoiceItems(URI_DESCRIPTIONS, inputUriPosition, this::selectFileInDialog)
+ .setPositiveButton(android.R.string.ok, /* listener= */ null)
+ .create()
+ .show();
+ }
+
+ @RequiresNonNull("chosenFileTextView")
+ private void selectFileInDialog(DialogInterface dialog, int which) {
+ inputUriPosition = which;
+ chosenFileTextView.setText(URI_DESCRIPTIONS[inputUriPosition]);
+ }
+
+ @RequiresNonNull({
+ "removeVideoCheckbox",
+ "audioMimeSpinner",
+ "videoMimeSpinner",
+ "resolutionHeightSpinner",
+ "translateSpinner",
+ "scaleSpinner",
+ "rotateSpinner"
+ })
+ private void onRemoveAudio(View view) {
+ if (((CheckBox) view).isChecked()) {
+ removeVideoCheckbox.setChecked(false);
+ enableTrackSpecificOptions(/* isAudioEnabled= */ false, /* isVideoEnabled= */ true);
+ } else {
+ enableTrackSpecificOptions(/* isAudioEnabled= */ true, /* isVideoEnabled= */ true);
+ }
+ }
+
+ @RequiresNonNull({
+ "removeAudioCheckbox",
+ "audioMimeSpinner",
+ "videoMimeSpinner",
+ "resolutionHeightSpinner",
+ "translateSpinner",
+ "scaleSpinner",
+ "rotateSpinner"
+ })
+ private void onRemoveVideo(View view) {
+ if (((CheckBox) view).isChecked()) {
+ removeAudioCheckbox.setChecked(false);
+ enableTrackSpecificOptions(/* isAudioEnabled= */ true, /* isVideoEnabled= */ false);
+ } else {
+ enableTrackSpecificOptions(/* isAudioEnabled= */ true, /* isVideoEnabled= */ true);
+ }
+ }
+
+ @RequiresNonNull({
+ "audioMimeSpinner",
+ "videoMimeSpinner",
+ "resolutionHeightSpinner",
+ "translateSpinner",
+ "scaleSpinner",
+ "rotateSpinner"
+ })
+ private void enableTrackSpecificOptions(boolean isAudioEnabled, boolean isVideoEnabled) {
+ audioMimeSpinner.setEnabled(isAudioEnabled);
+ videoMimeSpinner.setEnabled(isVideoEnabled);
+ resolutionHeightSpinner.setEnabled(isVideoEnabled);
+ translateSpinner.setEnabled(isVideoEnabled);
+ scaleSpinner.setEnabled(isVideoEnabled);
+ rotateSpinner.setEnabled(isVideoEnabled);
+
+ findViewById(R.id.audio_mime_text_view).setEnabled(isAudioEnabled);
+ findViewById(R.id.video_mime_text_view).setEnabled(isVideoEnabled);
+ findViewById(R.id.resolution_height_text_view).setEnabled(isVideoEnabled);
+ findViewById(R.id.translate).setEnabled(isVideoEnabled);
+ findViewById(R.id.scale).setEnabled(isVideoEnabled);
+ findViewById(R.id.rotate).setEnabled(isVideoEnabled);
+ }
+}
diff --git a/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java b/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java
new file mode 100644
index 0000000000..888ddd3edc
--- /dev/null
+++ b/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/TransformerActivity.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2021 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 com.google.android.exoplayer2.transformerdemo;
+
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
+import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Matrix;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.ExoPlayer;
+import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.transformer.ProgressHolder;
+import com.google.android.exoplayer2.transformer.TransformationException;
+import com.google.android.exoplayer2.transformer.TransformationRequest;
+import com.google.android.exoplayer2.transformer.Transformer;
+import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
+import com.google.android.exoplayer2.ui.StyledPlayerView;
+import com.google.android.exoplayer2.util.DebugTextViewHelper;
+import com.google.android.exoplayer2.util.Log;
+import com.google.android.exoplayer2.util.Util;
+import com.google.android.material.progressindicator.LinearProgressIndicator;
+import com.google.common.base.Stopwatch;
+import com.google.common.base.Ticker;
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
+import org.checkerframework.checker.nullness.qual.RequiresNonNull;
+
+/** An {@link Activity} that transforms and plays media using {@link Transformer}. */
+public final class TransformerActivity extends AppCompatActivity {
+ private static final String TAG = "TransformerActivity";
+
+ private @MonotonicNonNull StyledPlayerView playerView;
+ private @MonotonicNonNull TextView debugTextView;
+ private @MonotonicNonNull TextView informationTextView;
+ private @MonotonicNonNull ViewGroup progressViewGroup;
+ private @MonotonicNonNull LinearProgressIndicator progressIndicator;
+ private @MonotonicNonNull Stopwatch transformationStopwatch;
+ private @MonotonicNonNull AspectRatioFrameLayout debugFrame;
+
+ @Nullable private DebugTextViewHelper debugTextViewHelper;
+ @Nullable private ExoPlayer player;
+ @Nullable private Transformer transformer;
+ @Nullable private File externalCacheFile;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.transformer_activity);
+
+ playerView = findViewById(R.id.player_view);
+ debugTextView = findViewById(R.id.debug_text_view);
+ informationTextView = findViewById(R.id.information_text_view);
+ progressViewGroup = findViewById(R.id.progress_view_group);
+ progressIndicator = findViewById(R.id.progress_indicator);
+ debugFrame = findViewById(R.id.debug_aspect_ratio_frame_layout);
+
+ transformationStopwatch =
+ Stopwatch.createUnstarted(
+ new Ticker() {
+ public long read() {
+ return android.os.SystemClock.elapsedRealtimeNanos();
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ checkNotNull(progressIndicator);
+ checkNotNull(informationTextView);
+ checkNotNull(transformationStopwatch);
+ checkNotNull(playerView);
+ checkNotNull(debugTextView);
+ checkNotNull(progressViewGroup);
+ startTransformation();
+
+ playerView.onResume();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ checkNotNull(transformationStopwatch).reset();
+
+ checkNotNull(transformer).cancel();
+ transformer = null;
+
+ checkNotNull(playerView).onPause();
+ releasePlayer();
+
+ checkNotNull(externalCacheFile).delete();
+ externalCacheFile = null;
+ }
+
+ @RequiresNonNull({
+ "playerView",
+ "debugTextView",
+ "informationTextView",
+ "progressIndicator",
+ "transformationStopwatch",
+ "progressViewGroup",
+ })
+ private void startTransformation() {
+ requestTransformerPermissions();
+
+ Intent intent = getIntent();
+ Uri uri = checkNotNull(intent.getData());
+ try {
+ externalCacheFile = createExternalCacheFile("transformer-output.mp4");
+ String filePath = externalCacheFile.getAbsolutePath();
+ @Nullable Bundle bundle = intent.getExtras();
+ Transformer transformer = createTransformer(bundle, filePath);
+ transformationStopwatch.start();
+ transformer.startTransformation(MediaItem.fromUri(uri), filePath);
+ this.transformer = transformer;
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ informationTextView.setText(R.string.transformation_started);
+ Handler mainHandler = new Handler(getMainLooper());
+ ProgressHolder progressHolder = new ProgressHolder();
+ mainHandler.post(
+ new Runnable() {
+ @Override
+ public void run() {
+ if (transformer != null
+ && transformer.getProgress(progressHolder)
+ != Transformer.PROGRESS_STATE_NO_TRANSFORMATION) {
+ progressIndicator.setProgress(progressHolder.progress);
+ informationTextView.setText(
+ getString(
+ R.string.transformation_timer,
+ transformationStopwatch.elapsed(TimeUnit.SECONDS)));
+ mainHandler.postDelayed(/* r= */ this, /* delayMillis= */ 500);
+ }
+ }
+ });
+ }
+
+ // Create a cache file, resetting it if it already exists.
+ private File createExternalCacheFile(String fileName) throws IOException {
+ File file = new File(getExternalCacheDir(), fileName);
+ if (file.exists() && !file.delete()) {
+ throw new IllegalStateException("Could not delete the previous transformer output file");
+ }
+ if (!file.createNewFile()) {
+ throw new IllegalStateException("Could not create the transformer output file");
+ }
+ return file;
+ }
+
+ @RequiresNonNull({
+ "playerView",
+ "debugTextView",
+ "informationTextView",
+ "transformationStopwatch",
+ "progressViewGroup",
+ })
+ private Transformer createTransformer(@Nullable Bundle bundle, String filePath) {
+ Transformer.Builder transformerBuilder = new Transformer.Builder(/* context= */ this);
+ if (bundle != null) {
+ TransformationRequest.Builder requestBuilder = new TransformationRequest.Builder();
+ requestBuilder.setFlattenForSlowMotion(
+ bundle.getBoolean(ConfigurationActivity.SHOULD_FLATTEN_FOR_SLOW_MOTION));
+ @Nullable String audioMimeType = bundle.getString(ConfigurationActivity.AUDIO_MIME_TYPE);
+ if (audioMimeType != null) {
+ requestBuilder.setAudioMimeType(audioMimeType);
+ }
+ @Nullable String videoMimeType = bundle.getString(ConfigurationActivity.VIDEO_MIME_TYPE);
+ if (videoMimeType != null) {
+ requestBuilder.setVideoMimeType(videoMimeType);
+ }
+ int resolutionHeight =
+ bundle.getInt(
+ ConfigurationActivity.RESOLUTION_HEIGHT, /* defaultValue= */ C.LENGTH_UNSET);
+ if (resolutionHeight != C.LENGTH_UNSET) {
+ requestBuilder.setResolution(resolutionHeight);
+ }
+ Matrix transformationMatrix = getTransformationMatrix(bundle);
+ if (!transformationMatrix.isIdentity()) {
+ requestBuilder.setTransformationMatrix(transformationMatrix);
+ }
+ transformerBuilder
+ .setTransformationRequest(requestBuilder.build())
+ .setRemoveAudio(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_AUDIO))
+ .setRemoveVideo(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_VIDEO));
+ }
+ return transformerBuilder
+ .addListener(
+ new Transformer.Listener() {
+ @Override
+ public void onTransformationCompleted(MediaItem mediaItem) {
+ TransformerActivity.this.onTransformationCompleted(filePath);
+ }
+
+ @Override
+ public void onTransformationError(
+ MediaItem mediaItem, TransformationException exception) {
+ TransformerActivity.this.onTransformationError(exception);
+ }
+ })
+ .setDebugViewProvider(new DemoDebugViewProvider())
+ .build();
+ }
+
+ private static Matrix getTransformationMatrix(Bundle bundle) {
+ Matrix transformationMatrix = new Matrix();
+
+ float translateX = bundle.getFloat(ConfigurationActivity.TRANSLATE_X, /* defaultValue= */ 0);
+ float translateY = bundle.getFloat(ConfigurationActivity.TRANSLATE_Y, /* defaultValue= */ 0);
+ // TODO(b/213198690): Get resolution for aspect ratio and scale all translations' translateX
+ // by this aspect ratio.
+ transformationMatrix.postTranslate(translateX, translateY);
+
+ float scaleX = bundle.getFloat(ConfigurationActivity.SCALE_X, /* defaultValue= */ 1);
+ float scaleY = bundle.getFloat(ConfigurationActivity.SCALE_Y, /* defaultValue= */ 1);
+ transformationMatrix.postScale(scaleX, scaleY);
+
+ float rotateDegrees =
+ bundle.getFloat(ConfigurationActivity.ROTATE_DEGREES, /* defaultValue= */ 0);
+ transformationMatrix.postRotate(rotateDegrees);
+
+ return transformationMatrix;
+ }
+
+ @RequiresNonNull({
+ "informationTextView",
+ "progressViewGroup",
+ "transformationStopwatch",
+ })
+ private void onTransformationError(TransformationException exception) {
+ transformationStopwatch.stop();
+ informationTextView.setText(R.string.transformation_error);
+ progressViewGroup.setVisibility(View.GONE);
+ Toast.makeText(
+ TransformerActivity.this, "Transformation error: " + exception, Toast.LENGTH_LONG)
+ .show();
+ Log.e(TAG, "Transformation error", exception);
+ }
+
+ @RequiresNonNull({
+ "playerView",
+ "debugTextView",
+ "informationTextView",
+ "progressViewGroup",
+ "transformationStopwatch",
+ })
+ private void onTransformationCompleted(String filePath) {
+ transformationStopwatch.stop();
+ informationTextView.setText(
+ getString(
+ R.string.transformation_completed, transformationStopwatch.elapsed(TimeUnit.SECONDS)));
+ progressViewGroup.setVisibility(View.GONE);
+ playMediaItem(MediaItem.fromUri("file://" + filePath));
+ Log.d(TAG, "Output file path: file://" + filePath);
+ }
+
+ @RequiresNonNull({"playerView", "debugTextView"})
+ private void playMediaItem(MediaItem mediaItem) {
+ playerView.setPlayer(null);
+ releasePlayer();
+
+ ExoPlayer player = new ExoPlayer.Builder(/* context= */ this).build();
+ playerView.setPlayer(player);
+ player.setMediaItem(mediaItem);
+ player.play();
+ player.prepare();
+ this.player = player;
+ debugTextViewHelper = new DebugTextViewHelper(player, debugTextView);
+ debugTextViewHelper.start();
+ }
+
+ private void releasePlayer() {
+ if (debugTextViewHelper != null) {
+ debugTextViewHelper.stop();
+ debugTextViewHelper = null;
+ }
+ if (player != null) {
+ player.release();
+ player = null;
+ }
+ }
+
+ private void requestTransformerPermissions() {
+ if (Util.SDK_INT < 23) {
+ return;
+ }
+ if (checkSelfPermission(READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
+ || checkSelfPermission(WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(
+ new String[] {READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE}, /* requestCode= */ 0);
+ }
+ }
+
+ private final class DemoDebugViewProvider implements Transformer.DebugViewProvider {
+
+ @Nullable
+ @Override
+ public SurfaceView getDebugPreviewSurfaceView(int width, int height) {
+ // Update the UI on the main thread and wait for the output surface to be available.
+ CountDownLatch surfaceCreatedCountDownLatch = new CountDownLatch(1);
+ SurfaceView surfaceView = new SurfaceView(/* context= */ TransformerActivity.this);
+ runOnUiThread(
+ () -> {
+ AspectRatioFrameLayout debugFrame = checkNotNull(TransformerActivity.this.debugFrame);
+ debugFrame.addView(surfaceView);
+ debugFrame.setAspectRatio((float) width / height);
+ surfaceView
+ .getHolder()
+ .addCallback(
+ new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(SurfaceHolder surfaceHolder) {
+ surfaceCreatedCountDownLatch.countDown();
+ }
+
+ @Override
+ public void surfaceChanged(
+ SurfaceHolder surfaceHolder, int format, int width, int height) {
+ // Do nothing.
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
+ // Do nothing.
+ }
+ });
+ });
+ try {
+ surfaceCreatedCountDownLatch.await();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted waiting for debug surface.");
+ Thread.currentThread().interrupt();
+ return null;
+ }
+ return surfaceView;
+ }
+ }
+}
diff --git a/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/package-info.java b/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/package-info.java
new file mode 100644
index 0000000000..4996a4516d
--- /dev/null
+++ b/demos/transformer/src/main/java/com/google/android/exoplayer2/transformerdemo/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2021 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.
+ */
+@NonNullApi
+package com.google.android.exoplayer2.transformerdemo;
+
+import com.google.android.exoplayer2.util.NonNullApi;
diff --git a/demos/transformer/src/main/res/layout/configuration_activity.xml b/demos/transformer/src/main/res/layout/configuration_activity.xml
new file mode 100644
index 0000000000..a9a9410a35
--- /dev/null
+++ b/demos/transformer/src/main/res/layout/configuration_activity.xml
@@ -0,0 +1,179 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/transformer/src/main/res/layout/spinner_item.xml b/demos/transformer/src/main/res/layout/spinner_item.xml
new file mode 100644
index 0000000000..6c7dfaa6f7
--- /dev/null
+++ b/demos/transformer/src/main/res/layout/spinner_item.xml
@@ -0,0 +1,26 @@
+
+
+
diff --git a/demos/transformer/src/main/res/layout/transformer_activity.xml b/demos/transformer/src/main/res/layout/transformer_activity.xml
new file mode 100644
index 0000000000..9899f5146e
--- /dev/null
+++ b/demos/transformer/src/main/res/layout/transformer_activity.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/transformer/src/main/res/mipmap-hdpi/ic_launcher.png b/demos/transformer/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..adaa93220e
Binary files /dev/null and b/demos/transformer/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/demos/transformer/src/main/res/mipmap-mdpi/ic_launcher.png b/demos/transformer/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..9b6f7d5e80
Binary files /dev/null and b/demos/transformer/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/demos/transformer/src/main/res/mipmap-xhdpi/ic_launcher.png b/demos/transformer/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..2101026c9f
Binary files /dev/null and b/demos/transformer/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/demos/transformer/src/main/res/mipmap-xxhdpi/ic_launcher.png b/demos/transformer/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..223ec8bd11
Binary files /dev/null and b/demos/transformer/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/demos/transformer/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/demos/transformer/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..698ed68c42
Binary files /dev/null and b/demos/transformer/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/demos/transformer/src/main/res/values/strings.xml b/demos/transformer/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..39bd87ad8f
--- /dev/null
+++ b/demos/transformer/src/main/res/values/strings.xml
@@ -0,0 +1,37 @@
+
+
+
+ Transformer Demo
+ Configuration
+ Choose File
+ Remove audio
+ Remove video
+ Flatten for slow motion
+ Output audio MIME type
+ Output video MIME type
+ Output video resolution
+ Translate video
+ Scale video
+ Rotate video (degrees)
+ Transform
+ Debug preview:
+ No debug preview available
+ Transformation started
+ Transformation started %d seconds ago.
+ Transformation completed in %d seconds.
+ Transformation error
+
diff --git a/docs/glossary.md b/docs/glossary.md
index 3af6723dfb..1c7857a764 100644
--- a/docs/glossary.md
+++ b/docs/glossary.md
@@ -128,7 +128,7 @@ containing the same content at different bitrates.
An Android API for playing audio.
For more information, see the
-[Javadoc](https://developer.android.com/reference/android/media/AudioTrack).
+[Javadoc]({{ site.android_sdk }}/android/media/AudioTrack).
###### CDM
@@ -137,7 +137,7 @@ decrypting [DRM](#drm) protected content. CDMs are accessed via Android’s
[`MediaDrm`](#mediadrm) API.
For more information, see the
-[Javadoc](https://developer.android.com/reference/android/media/MediaDrm).
+[Javadoc]({{ site.android_sdk }}/android/media/MediaDrm).
###### IMA
@@ -153,14 +153,14 @@ An Android API for accessing media [codecs](#codec) (i.e. encoder and decoder
components) in the platform.
For more information, see the
-[Javadoc](https://developer.android.com/reference/android/media/MediaCodec).
+[Javadoc]({{ site.android_sdk }}/android/media/MediaCodec).
###### MediaDrm
An Android API for accessing [CDMs](#cdm) in the platform.
For more information, see the
-[Javadoc](https://developer.android.com/reference/android/media/MediaDrm).
+[Javadoc]({{ site.android_sdk }}/android/media/MediaDrm).
###### Audio offload
@@ -181,7 +181,7 @@ For more information, see the
###### Surface
-See the [Javadoc](https://developer.android.com/reference/android/view/Surface)
+See the [Javadoc]({{ site.android_sdk }}/android/view/Surface)
and the
[Android graphics documentation](https://source.android.com/devices/graphics/arch-sh).
@@ -212,14 +212,14 @@ transfers. In [adaptive streaming](#adaptive-streaming), bandwidth estimates can
be used to select between different bitrate [tracks](#track) during playback.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/upstream/BandwidthMeter.html).
+[Javadoc]({{ site.exo_sdk }}/upstream/BandwidthMeter.html).
###### DataSource
Component for requesting data (e.g. over HTTP, from a local file, etc).
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/upstream/DataSource.html).
+[Javadoc]({{ site.exo_sdk }}/upstream/DataSource.html).
###### Extractor
@@ -228,7 +228,7 @@ Component that parses a media [container](#container) format, outputting
belonging to each track suitable for consumption by a decoder.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/extractor/Extractor.html).
+[Javadoc]({{ site.exo_sdk }}/extractor/Extractor.html).
###### LoadControl
@@ -236,7 +236,7 @@ Component that decides when to start and stop loading, and when to start
playback.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/LoadControl.html).
+[Javadoc]({{ site.exo_sdk }}/LoadControl.html).
###### MediaSource
@@ -245,7 +245,7 @@ Provides high-level information about the structure of media (as a
(corresponding to periods of the `Timeline`) for playback.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/source/MediaSource.html).
+[Javadoc]({{ site.exo_sdk }}/source/MediaSource.html).
###### MediaPeriod
@@ -257,7 +257,7 @@ media are loaded and when loading starts and stops are made by the
respectively.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/source/MediaPeriod.html).
+[Javadoc]({{ site.exo_sdk }}/source/MediaPeriod.html).
###### Renderer
@@ -266,7 +266,7 @@ and [`AudioTrack`](#audiotrack) are the standard Android platform components to
which video and audio data are rendered.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Renderer.html).
+[Javadoc]({{ site.exo_sdk }}/Renderer.html).
###### Timeline
@@ -275,7 +275,7 @@ through to complex compositions of media such as playlists and streams with
inserted ads.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Timeline.html).
+[Javadoc]({{ site.exo_sdk }}/Timeline.html).
###### TrackGroup
@@ -284,7 +284,7 @@ content, normally at different bitrates for
[adaptive streaming](#adaptive-streaming).
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/source/TrackGroup.html).
+[Javadoc]({{ site.exo_sdk }}/source/TrackGroup.html).
###### TrackSelection
@@ -295,7 +295,7 @@ responsible for selecting the appropriate track whenever a new media chunk
starts being loaded.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelection.html).
+[Javadoc]({{ site.exo_sdk }}/trackselection/TrackSelection.html).
###### TrackSelector
@@ -305,4 +305,4 @@ player’s [`Renderers`](#renderer), a `TrackSelector` will generate a
[`TrackSelection`](#trackselection) for each `Renderer`.
For more information, see the component
-[Javadoc](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/trackselection/TrackSelector.html).
+[Javadoc]({{ site.exo_sdk }}/trackselection/TrackSelector.html).
diff --git a/docs/hello-world.md b/docs/hello-world.md
index 5b71f150ff..af7c58ceb9 100644
--- a/docs/hello-world.md
+++ b/docs/hello-world.md
@@ -119,11 +119,7 @@ which the player must be accessed can be queried using
If you see `IllegalStateException` being thrown with the message "Player is
accessed on the wrong thread", then some code in your app is accessing an
`ExoPlayer` instance on the wrong thread (the exception's stack trace shows you
-where). You can temporarily opt out from these exceptions being thrown by
-calling `ExoPlayer.setThrowsWhenUsingWrongThread(false)`, in which case the
-issue will be logged as a warning instead. Using this opt out is not safe and
-may result in unexpected or obscure errors. It will be removed in ExoPlayer
-2.16.
+where).
{:.info}
For more information about ExoPlayer's threading model, see the
diff --git a/docs/listening-to-player-events.md b/docs/listening-to-player-events.md
index 5bf7f7b53d..e3918dd942 100644
--- a/docs/listening-to-player-events.md
+++ b/docs/listening-to-player-events.md
@@ -12,7 +12,7 @@ events is easy:
// Add a listener to receive events from the player.
player.addListener(listener);
~~~
-{: .language-java}
+{: .language-java }
`Player.Listener` has empty default methods, so you only need to implement
the methods you're interested in. See the [Javadoc][] for a full description of
@@ -195,7 +195,7 @@ additional logging with a single line.
```
player.addAnalyticsListener(new EventLogger(trackSelector));
```
-{: .language-java}
+{: .language-java }
Passing the `trackSelector` enables additional logging, but is optional and so
`null` can be passed instead. See the [debug logging page][] for more details.
@@ -220,7 +220,7 @@ player
// Do something at the specified playback position.
})
.setLooper(Looper.getMainLooper())
- .setPosition(/* windowIndex= */ 0, /* positionMs= */ 120_000)
+ .setPosition(/* mediaItemIndex= */ 0, /* positionMs= */ 120_000)
.setPayload(customPayloadData)
.setDeleteAfterDelivery(false)
.send();
diff --git a/docs/live-streaming.md b/docs/live-streaming.md
index f9091ba261..27a10dee0a 100644
--- a/docs/live-streaming.md
+++ b/docs/live-streaming.md
@@ -51,9 +51,9 @@ methods, as listed below and shown in the following figure.
`Timeline`. The current `Timeline.Window` can be retrieved from the `Timeline`
using `Player.getCurrentWindowIndex` and `Timeline.getWindow`. Within the
`Window`:
- * `Window.liveConfiguration` contains the target live offset and and live
- offset adjustment parameters. These values are based on information in the
- media and any app-provided overrides set in `MediaItem.liveConfiguration`.
+ * `Window.liveConfiguration` contains the target live offset and live offset
+ adjustment parameters. These values are based on information in the media
+ and any app-provided overrides set in `MediaItem.liveConfiguration`.
* `Window.windowStartTimeMs` is the time since the Unix Epoch at which the
live window starts.
* `Window.getCurrentUnixTimeMs` is the time since the Unix Epoch of the
diff --git a/docs/media-items.md b/docs/media-items.md
index f57b3b9392..4845c062ac 100644
--- a/docs/media-items.md
+++ b/docs/media-items.md
@@ -153,4 +153,4 @@ the player also needs to have its `DefaultMediaSourceFactory`
[configured accordingly]({{ site.baseurl }}/ad-insertion.html#declarative-ad-support).
[playlist API]: {{ site.baseurl }}/playlists.html
-[`MediaItem.Builder` Javadoc]: {{ site.baseurl }}/doc/reference/com/google/android/exoplayer2/MediaItem.Builder.html
+[`MediaItem.Builder` Javadoc]: {{ site.exo_sdk }}/MediaItem.Builder.html
diff --git a/docs/media-sources.md b/docs/media-sources.md
index 15435baf74..1855abd6cb 100644
--- a/docs/media-sources.md
+++ b/docs/media-sources.md
@@ -44,7 +44,7 @@ ExoPlayer player = new ExoPlayer.Builder(context)
{: .language-java}
The
-[`DefaultMediaSourceFactory` JavaDoc]({{ site.baseurl }}/doc/reference/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.html)
+[`DefaultMediaSourceFactory` JavaDoc]({{ site.exo_sdk }}/source/DefaultMediaSourceFactory.html)
describes the available options in more detail.
It's also possible to inject a custom `MediaSource.Factory` implementation, for
@@ -79,4 +79,4 @@ exoPlayer.play();
[HLS]: {{ site.baseurl }}/hls.html
[RTSP]: {{ site.baseurl }}/rtsp.html
[regular media files]: {{ site.baseurl }}/progressive.html
-[`ExoPlayer`]: {{ site.baseurl }}/doc/reference/com/google/android/exoplayer2/ExoPlayer.html
+[`ExoPlayer`]: {{ site.exo_sdk }}/ExoPlayer.html
diff --git a/docs/retrieving-metadata.md b/docs/retrieving-metadata.md
index b0a288353a..c718baae7e 100644
--- a/docs/retrieving-metadata.md
+++ b/docs/retrieving-metadata.md
@@ -85,6 +85,6 @@ for (int i = 0; i < trackGroups.length; i++) {
{: .language-java}
[`MediaMetadata`]: {{ site.exo_sdk }}/MediaMetadata.html
-[`Metadata.Entry`]: {{ site.exo_sdk}}/metadata/Metadata.Entry.html
+[`Metadata.Entry`]: {{ site.exo_sdk }}/metadata/Metadata.Entry.html
[`MetadataRetriever`]: {{ site.exo_sdk }}/MetadataRetriever.html
[`MotionPhotoMetadata`]: {{ site.exo_sdk }}/metadata/mp4/MotionPhotoMetadata.html
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 0840c6b523..d547b285ff 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -164,7 +164,7 @@ from HTTPS to HTTP and so is a cross-protocol redirect. ExoPlayer will not
follow this redirect in its default configuration, meaning playback will fail.
If you need to, you can configure ExoPlayer to follow cross-protocol redirects
-when instantiating `DefaultHttpDataSourceFactory` instances used in your
+when instantiating [`DefaultHttpDataSource.Factory`][] instances used in your
application. Learn about selecting and configuring the network stack
[here]({{ site.base_url }}/customization.html#configuring-the-network-stack).
@@ -326,7 +326,7 @@ is the official way to play YouTube videos on Android.
[`setFragmentedMp4ExtractorFlags`]: {{ site.exo_sdk }}/extractor/DefaultExtractorsFactory#setFragmentedMp4ExtractorFlags(int)
[Wikipedia]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
[wget]: https://www.gnu.org/software/wget/manual/wget.html
-[`DefaultHttpDataSourceFactory`]: {{ site.exo_sdk }}/upstream/DefaultHttpDataSourceFactory.html
+[`DefaultHttpDataSource.Factory`]: {{ site.exo_sdk }}/upstream/DefaultHttpDataSource.Factory.html
[ExoPlayer module]: {{ site.base_url }}/hello-world.html#add-exoplayer-modules
[issue tracker]: https://github.com/google/ExoPlayer/issues
[`isCurrentWindowLive`]: {{ site.exo_sdk }}/Player.html#isCurrentWindowLive()
diff --git a/extensions/av1/README.md b/extensions/av1/README.md
index b5d16dca8f..5357cb724f 100644
--- a/extensions/av1/README.md
+++ b/extensions/av1/README.md
@@ -112,20 +112,20 @@ gets from the libgav1 decoder:
* GL rendering using GL shader for color space conversion
- * If you are using `ExoPlayer` with `PlayerView` or
- `StyledPlayerView`, enable this option by setting `surface_type` of view
- to be `video_decoder_gl_surface_view`.
+ * If you are using `ExoPlayer` with `PlayerView` or `StyledPlayerView`,
+ enable this option by setting `surface_type` of view to be
+ `video_decoder_gl_surface_view`.
* Otherwise, enable this option by sending `Libgav1VideoRenderer` a
message of type `Renderer.MSG_SET_VIDEO_OUTPUT` with an instance of
`VideoDecoderOutputBufferRenderer` as its object.
`VideoDecoderGLSurfaceView` is the concrete
- `VideoDecoderOutputBufferRenderer` implementation used by
- `PlayerView` and `StyledPlayerView`.
+ `VideoDecoderOutputBufferRenderer` implementation used by `PlayerView`
+ and `StyledPlayerView`.
* Native rendering using `ANativeWindow`
- * If you are using `ExoPlayer` with `PlayerView` or
- `StyledPlayerView`, this option is enabled by default.
+ * If you are using `ExoPlayer` with `PlayerView` or `StyledPlayerView`,
+ this option is enabled by default.
* Otherwise, enable this option by sending `Libgav1VideoRenderer` a
message of type `Renderer.MSG_SET_VIDEO_OUTPUT` with an instance of
`SurfaceView` as its object.
diff --git a/extensions/cast/build.gradle b/extensions/cast/build.gradle
index 3addcceaef..ba333edbe2 100644
--- a/extensions/cast/build.gradle
+++ b/extensions/cast/build.gradle
@@ -14,7 +14,7 @@
apply from: "$gradle.ext.exoplayerSettingsDir/common_library_config.gradle"
dependencies {
- api 'com.google.android.gms:play-services-cast-framework:20.1.0'
+ api 'com.google.android.gms:play-services-cast-framework:21.0.1'
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
implementation project(modulePrefix + 'library-common')
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java
index 31e3f6fca7..a1a78e91d7 100644
--- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java
+++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java
@@ -20,9 +20,11 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.util.Assertions;
+import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.gms.cast.MediaInfo;
import com.google.android.gms.cast.MediaMetadata;
import com.google.android.gms.cast.MediaQueueItem;
+import com.google.android.gms.common.images.WebImage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.UUID;
@@ -45,10 +47,43 @@ public final class DefaultMediaItemConverter implements MediaItemConverter {
@Override
public MediaItem toMediaItem(MediaQueueItem mediaQueueItem) {
- // `item` came from `toMediaQueueItem()` so the custom JSON data must be set.
- MediaInfo mediaInfo = mediaQueueItem.getMedia();
+ @Nullable MediaInfo mediaInfo = mediaQueueItem.getMedia();
Assertions.checkNotNull(mediaInfo);
- return getMediaItem(Assertions.checkNotNull(mediaInfo.getCustomData()));
+ com.google.android.exoplayer2.MediaMetadata.Builder metadataBuilder =
+ new com.google.android.exoplayer2.MediaMetadata.Builder();
+ @Nullable MediaMetadata metadata = mediaInfo.getMetadata();
+ if (metadata != null) {
+ if (metadata.containsKey(MediaMetadata.KEY_TITLE)) {
+ metadataBuilder.setTitle(metadata.getString(MediaMetadata.KEY_TITLE));
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_SUBTITLE)) {
+ metadataBuilder.setSubtitle(metadata.getString(MediaMetadata.KEY_SUBTITLE));
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_ARTIST)) {
+ metadataBuilder.setArtist(metadata.getString(MediaMetadata.KEY_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_ALBUM_ARTIST)) {
+ metadataBuilder.setAlbumArtist(metadata.getString(MediaMetadata.KEY_ALBUM_ARTIST));
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_ALBUM_TITLE)) {
+ metadataBuilder.setArtist(metadata.getString(MediaMetadata.KEY_ALBUM_TITLE));
+ }
+ if (!metadata.getImages().isEmpty()) {
+ metadataBuilder.setArtworkUri(metadata.getImages().get(0).getUrl());
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_COMPOSER)) {
+ metadataBuilder.setComposer(metadata.getString(MediaMetadata.KEY_COMPOSER));
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_DISC_NUMBER)) {
+ metadataBuilder.setDiscNumber(metadata.getInt(MediaMetadata.KEY_DISC_NUMBER));
+ }
+ if (metadata.containsKey(MediaMetadata.KEY_TRACK_NUMBER)) {
+ metadataBuilder.setTrackNumber(metadata.getInt(MediaMetadata.KEY_TRACK_NUMBER));
+ }
+ }
+ // `mediaQueueItem` came from `toMediaQueueItem()` so the custom JSON data must be set.
+ return getMediaItem(
+ Assertions.checkNotNull(mediaInfo.getCustomData()), metadataBuilder.build());
}
@Override
@@ -57,10 +92,41 @@ public final class DefaultMediaItemConverter implements MediaItemConverter {
if (mediaItem.localConfiguration.mimeType == null) {
throw new IllegalArgumentException("The item must specify its mimeType");
}
- MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
+ MediaMetadata metadata =
+ new MediaMetadata(
+ MimeTypes.isAudio(mediaItem.localConfiguration.mimeType)
+ ? MediaMetadata.MEDIA_TYPE_MUSIC_TRACK
+ : MediaMetadata.MEDIA_TYPE_MOVIE);
if (mediaItem.mediaMetadata.title != null) {
metadata.putString(MediaMetadata.KEY_TITLE, mediaItem.mediaMetadata.title.toString());
}
+ if (mediaItem.mediaMetadata.subtitle != null) {
+ metadata.putString(MediaMetadata.KEY_SUBTITLE, mediaItem.mediaMetadata.subtitle.toString());
+ }
+ if (mediaItem.mediaMetadata.artist != null) {
+ metadata.putString(MediaMetadata.KEY_ARTIST, mediaItem.mediaMetadata.artist.toString());
+ }
+ if (mediaItem.mediaMetadata.albumArtist != null) {
+ metadata.putString(
+ MediaMetadata.KEY_ALBUM_ARTIST, mediaItem.mediaMetadata.albumArtist.toString());
+ }
+ if (mediaItem.mediaMetadata.albumTitle != null) {
+ metadata.putString(
+ MediaMetadata.KEY_ALBUM_TITLE, mediaItem.mediaMetadata.albumTitle.toString());
+ }
+ if (mediaItem.mediaMetadata.artworkUri != null) {
+ metadata.addImage(new WebImage(mediaItem.mediaMetadata.artworkUri));
+ }
+ if (mediaItem.mediaMetadata.composer != null) {
+ metadata.putString(MediaMetadata.KEY_COMPOSER, mediaItem.mediaMetadata.composer.toString());
+ }
+ if (mediaItem.mediaMetadata.discNumber != null) {
+ metadata.putInt(MediaMetadata.KEY_DISC_NUMBER, mediaItem.mediaMetadata.discNumber);
+ }
+ if (mediaItem.mediaMetadata.trackNumber != null) {
+ metadata.putInt(MediaMetadata.KEY_TRACK_NUMBER, mediaItem.mediaMetadata.trackNumber);
+ }
+
MediaInfo mediaInfo =
new MediaInfo.Builder(mediaItem.localConfiguration.uri.toString())
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
@@ -73,19 +139,15 @@ public final class DefaultMediaItemConverter implements MediaItemConverter {
// Deserialization.
- private static MediaItem getMediaItem(JSONObject customData) {
+ private static MediaItem getMediaItem(
+ JSONObject customData, com.google.android.exoplayer2.MediaMetadata mediaMetadata) {
try {
JSONObject mediaItemJson = customData.getJSONObject(KEY_MEDIA_ITEM);
- MediaItem.Builder builder = new MediaItem.Builder();
- builder.setUri(Uri.parse(mediaItemJson.getString(KEY_URI)));
- builder.setMediaId(mediaItemJson.getString(KEY_MEDIA_ID));
- if (mediaItemJson.has(KEY_TITLE)) {
- com.google.android.exoplayer2.MediaMetadata mediaMetadata =
- new com.google.android.exoplayer2.MediaMetadata.Builder()
- .setTitle(mediaItemJson.getString(KEY_TITLE))
- .build();
- builder.setMediaMetadata(mediaMetadata);
- }
+ MediaItem.Builder builder =
+ new MediaItem.Builder()
+ .setUri(Uri.parse(mediaItemJson.getString(KEY_URI)))
+ .setMediaId(mediaItemJson.getString(KEY_MEDIA_ID))
+ .setMediaMetadata(mediaMetadata);
if (mediaItemJson.has(KEY_MIME_TYPE)) {
builder.setMimeType(mediaItemJson.getString(KEY_MIME_TYPE));
}
diff --git a/extensions/cronet/build.gradle b/extensions/cronet/build.gradle
index 09211ca4cb..f179fac8e2 100644
--- a/extensions/cronet/build.gradle
+++ b/extensions/cronet/build.gradle
@@ -20,7 +20,7 @@ android {
}
dependencies {
- api "com.google.android.gms:play-services-cronet:17.0.1"
+ api "com.google.android.gms:play-services-cronet:18.0.1"
implementation project(modulePrefix + 'library-common')
implementation project(modulePrefix + 'library-datasource')
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
diff --git a/extensions/ima/build.gradle b/extensions/ima/build.gradle
index 4a40f0afc9..95644aa368 100644
--- a/extensions/ima/build.gradle
+++ b/extensions/ima/build.gradle
@@ -25,7 +25,7 @@ android {
}
dependencies {
- api 'com.google.ads.interactivemedia.v3:interactivemedia:3.25.1'
+ api 'com.google.ads.interactivemedia.v3:interactivemedia:3.26.0'
implementation project(modulePrefix + 'library-core')
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
compileOnly 'org.checkerframework:checker-qual:' + checkerframeworkVersion
diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java
index f9564154ca..fe0df4e399 100644
--- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java
+++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsLoader.java
@@ -71,14 +71,15 @@ import java.util.Set;
* #setPlayer(Player)}. If the ads loader is no longer required, it must be released by calling
* {@link #release()}.
*
- * See https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
- * information on compatible ad tag formats. Pass the ad tag URI when setting media item playback
- * properties (if using the media item API) or as a {@link DataSpec} when constructing the {@link
- * AdsMediaSource} (if using media sources directly). For the latter case, please note that this
- * implementation delegates loading of the data spec to the IMA SDK, so range and headers
- * specifications will be ignored in ad tag URIs. Literal ads responses can be encoded as data
- * scheme data specs, for example, by constructing the data spec using a URI generated via {@link
- * Util#getDataUriForString(String, String)}.
+ *
See IMA's
+ * Support and compatibility page for information on compatible ad tag formats. Pass the ad tag
+ * URI when setting media item playback properties (if using the media item API) or as a {@link
+ * DataSpec} when constructing the {@link AdsMediaSource} (if using media sources directly). For the
+ * latter case, please note that this implementation delegates loading of the data spec to the IMA
+ * SDK, so range and headers specifications will be ignored in ad tag URIs. Literal ads responses
+ * can be encoded as data scheme data specs, for example, by constructing the data spec using a URI
+ * generated via {@link Util#getDataUriForString(String, String)}.
*
*
The IMA SDK can report obstructions to the ad view for accurate viewability measurement. This
* means that any overlay views that obstruct the ad overlay but are essential for playback need to
diff --git a/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java b/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java
index 755d62fc84..4a22f4e216 100644
--- a/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java
+++ b/extensions/media2/src/androidTest/java/com/google/android/exoplayer2/ext/media2/SessionPlayerConnectorTest.java
@@ -924,8 +924,7 @@ public class SessionPlayerConnectorTest {
assertThat(onPlaylistChangedLatch.getCount()).isEqualTo(1);
}
- // TODO(b/168860979): De-flake and re-enable.
- @Ignore
+ @Ignore("Internal ref: b/168860979")
@Test
@LargeTest
public void replacePlaylistItem_calledOnlyOnce_notifiesPlaylistChangeOnlyOnce() throws Exception {
diff --git a/extensions/vp9/README.md b/extensions/vp9/README.md
index 2e471ca118..891299d5ef 100644
--- a/extensions/vp9/README.md
+++ b/extensions/vp9/README.md
@@ -125,20 +125,20 @@ gets from the libvpx decoder:
* GL rendering using GL shader for color space conversion
- * If you are using `ExoPlayer` with `PlayerView` or
- `StyledPlayerView`, enable this option by setting `surface_type` of view
- to be `video_decoder_gl_surface_view`.
+ * If you are using `ExoPlayer` with `PlayerView` or `StyledPlayerView`,
+ enable this option by setting `surface_type` of view to be
+ `video_decoder_gl_surface_view`.
* Otherwise, enable this option by sending `LibvpxVideoRenderer` a message
of type `Renderer.MSG_SET_VIDEO_OUTPUT` with an instance of
`VideoDecoderOutputBufferRenderer` as its object.
`VideoDecoderGLSurfaceView` is the concrete
- `VideoDecoderOutputBufferRenderer` implementation used by
- `PlayerView` and `StyledPlayerView`.
+ `VideoDecoderOutputBufferRenderer` implementation used by `PlayerView`
+ and `StyledPlayerView`.
* Native rendering using `ANativeWindow`
- * If you are using `ExoPlayer` with `PlayerView` or
- `StyledPlayerView`, this option is enabled by default.
+ * If you are using `ExoPlayer` with `PlayerView` or `StyledPlayerView`,
+ this option is enabled by default.
* Otherwise, enable this option by sending `LibvpxVideoRenderer` a message
of type `Renderer.MSG_SET_VIDEO_OUTPUT` with an instance of
`SurfaceView` as its object.
diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java
index ebaa16fa73..5f9102a7fd 100644
--- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java
+++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/VpxLibrary.java
@@ -28,7 +28,7 @@ public final class VpxLibrary {
}
private static final LibraryLoader LOADER = new LibraryLoader("vpx", "vpxV2JNI");
- @C.CryptoType private static int cryptoType = C.CRYPTO_TYPE_UNSUPPORTED;
+ private static @C.CryptoType int cryptoType = C.CRYPTO_TYPE_UNSUPPORTED;
private VpxLibrary() {}
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/HeartRating.java b/library/common/src/main/java/com/google/android/exoplayer2/HeartRating.java
index b656d0bd35..8520125c38 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/HeartRating.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/HeartRating.java
@@ -100,7 +100,7 @@ public final class HeartRating extends Rating {
private static HeartRating fromBundle(Bundle bundle) {
checkArgument(
- bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
+ bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
boolean isRated = bundle.getBoolean(keyForField(FIELD_RATED), /* defaultValue= */ false);
return isRated
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/PercentageRating.java b/library/common/src/main/java/com/google/android/exoplayer2/PercentageRating.java
index 1953e7e1d1..3bdb1dd11c 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/PercentageRating.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/PercentageRating.java
@@ -96,7 +96,7 @@ public final class PercentageRating extends Rating {
private static PercentageRating fromBundle(Bundle bundle) {
checkArgument(
- bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
+ bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
float percent = bundle.getFloat(keyForField(FIELD_PERCENT), /* defaultValue= */ RATING_UNSET);
return percent == RATING_UNSET ? new PercentageRating() : new PercentageRating(percent);
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Rating.java b/library/common/src/main/java/com/google/android/exoplayer2/Rating.java
index 0477bbce0e..69886aafc3 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/Rating.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/Rating.java
@@ -41,7 +41,7 @@ public abstract class Rating implements Bundleable {
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
- RATING_TYPE_DEFAULT,
+ RATING_TYPE_UNSET,
RATING_TYPE_HEART,
RATING_TYPE_PERCENTAGE,
RATING_TYPE_STAR,
@@ -49,7 +49,7 @@ public abstract class Rating implements Bundleable {
})
/* package */ @interface RatingType {}
- /* package */ static final int RATING_TYPE_DEFAULT = -1;
+ /* package */ static final int RATING_TYPE_UNSET = -1;
/* package */ static final int RATING_TYPE_HEART = 0;
/* package */ static final int RATING_TYPE_PERCENTAGE = 1;
/* package */ static final int RATING_TYPE_STAR = 2;
@@ -68,7 +68,7 @@ public abstract class Rating implements Bundleable {
private static Rating fromBundle(Bundle bundle) {
@RatingType
int ratingType =
- bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT);
+ bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET);
switch (ratingType) {
case RATING_TYPE_HEART:
return HeartRating.CREATOR.fromBundle(bundle);
@@ -78,8 +78,9 @@ public abstract class Rating implements Bundleable {
return StarRating.CREATOR.fromBundle(bundle);
case RATING_TYPE_THUMB:
return ThumbRating.CREATOR.fromBundle(bundle);
+ case RATING_TYPE_UNSET:
default:
- throw new IllegalArgumentException("Encountered unknown rating type: " + ratingType);
+ throw new IllegalArgumentException("Unknown RatingType: " + ratingType);
}
}
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/StarRating.java b/library/common/src/main/java/com/google/android/exoplayer2/StarRating.java
index 543228185e..05736766b5 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/StarRating.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/StarRating.java
@@ -125,7 +125,7 @@ public final class StarRating extends Rating {
private static StarRating fromBundle(Bundle bundle) {
checkArgument(
- bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
+ bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
int maxStars =
bundle.getInt(keyForField(FIELD_MAX_STARS), /* defaultValue= */ MAX_STARS_DEFAULT);
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/ThumbRating.java b/library/common/src/main/java/com/google/android/exoplayer2/ThumbRating.java
index 07e0ee38d3..cc4b404f2c 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/ThumbRating.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/ThumbRating.java
@@ -97,7 +97,7 @@ public final class ThumbRating extends Rating {
private static ThumbRating fromBundle(Bundle bundle) {
checkArgument(
- bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_DEFAULT)
+ bundle.getInt(keyForField(FIELD_RATING_TYPE), /* defaultValue= */ RATING_TYPE_UNSET)
== TYPE);
boolean rated = bundle.getBoolean(keyForField(FIELD_RATED), /* defaultValue= */ false);
return rated
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java b/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java
index 328f8a4080..5a46825692 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java
@@ -25,7 +25,6 @@ import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.source.TrackGroup;
-import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Booleans;
@@ -35,11 +34,12 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;
-/** Immutable information ({@link TrackGroupInfo}) about tracks. */
+/** Information about groups of tracks. */
public final class TracksInfo implements Bundleable {
/**
- * Information about tracks in a {@link TrackGroup}: their {@link C.TrackType}, if their format is
- * supported by the player and if they are selected for playback.
+ * Information about a single group of tracks, including the underlying {@link TrackGroup}, the
+ * {@link C.TrackType type} of tracks it contains, and the level to which each track is supported
+ * by the player.
*/
public static final class TrackGroupInfo implements Bundleable {
private final TrackGroup trackGroup;
@@ -74,7 +74,7 @@ public final class TracksInfo implements Bundleable {
}
/**
- * Returns the level of support for a track in a {@link TrackGroup}.
+ * Returns the level of support for a specified track.
*
* @param trackIndex The index of the track in the {@link TrackGroup}.
* @return The {@link C.FormatSupport} of the track.
@@ -85,24 +85,58 @@ public final class TracksInfo implements Bundleable {
}
/**
- * Returns if a track in a {@link TrackGroup} is supported for playback.
+ * Returns whether a specified track is supported for playback, without exceeding the advertised
+ * capabilities of the device. Equivalent to {@code isTrackSupported(trackIndex, false)}.
*
* @param trackIndex The index of the track in the {@link TrackGroup}.
* @return True if the track's format can be played, false otherwise.
*/
public boolean isTrackSupported(int trackIndex) {
- return trackSupport[trackIndex] == C.FORMAT_HANDLED;
+ return isTrackSupported(trackIndex, /* allowExceedsCapabilities= */ false);
}
- /** Returns if at least one track in a {@link TrackGroup} is selected for playback. */
+ /**
+ * Returns whether a specified track is supported for playback.
+ *
+ * @param trackIndex The index of the track in the {@link TrackGroup}.
+ * @param allowExceedsCapabilities Whether to consider the track as supported if it has a
+ * supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised
+ * capabilities of the device. For example, a video track for which there's a corresponding
+ * decoder whose maximum advertised resolution is exceeded by the resolution of the track.
+ * Such tracks may be playable in some cases.
+ * @return True if the track's format can be played, false otherwise.
+ */
+ public boolean isTrackSupported(int trackIndex, boolean allowExceedsCapabilities) {
+ return trackSupport[trackIndex] == C.FORMAT_HANDLED
+ || (allowExceedsCapabilities
+ && trackSupport[trackIndex] == C.FORMAT_EXCEEDS_CAPABILITIES);
+ }
+
+ /** Returns whether at least one track in the group is selected for playback. */
public boolean isSelected() {
return Booleans.contains(trackSelected, true);
}
- /** Returns if at least one track in a {@link TrackGroup} is supported. */
+ /**
+ * Returns whether at least one track in the group is supported for playback, without exceeding
+ * the advertised capabilities of the device. Equivalent to {@code isSupported(false)}.
+ */
public boolean isSupported() {
+ return isSupported(/* allowExceedsCapabilities= */ false);
+ }
+
+ /**
+ * Returns whether at least one track in the group is supported for playback.
+ *
+ * @param allowExceedsCapabilities Whether to consider a track as supported if it has a
+ * supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised
+ * capabilities of the device. For example, a video track for which there's a corresponding
+ * decoder whose maximum advertised resolution is exceeded by the resolution of the track.
+ * Such tracks may be playable in some cases.
+ */
+ public boolean isSupported(boolean allowExceedsCapabilities) {
for (int i = 0; i < trackSupport.length; i++) {
- if (isTrackSupported(i)) {
+ if (isTrackSupported(i, allowExceedsCapabilities)) {
return true;
}
}
@@ -110,27 +144,24 @@ public final class TracksInfo implements Bundleable {
}
/**
- * Returns if a track in a {@link TrackGroup} is selected for playback.
+ * Returns whether a specified track is selected for playback.
*
- *
Multiple tracks of a track group may be selected. This is common in adaptive streaming,
- * where multiple tracks of different quality are selected and the player switches between them
- * depending on the network and the {@link TrackSelectionParameters}.
+ *
Note that multiple tracks in the group may be selected. This is common in adaptive
+ * streaming, where tracks of different qualities are selected and the player switches between
+ * them during playback (e.g., based on the available network bandwidth).
*
- *
While this class doesn't provide which selected track is currently playing, some player
- * implementations have ways of getting such information. For example ExoPlayer provides this
- * information in {@code ExoTrackSelection.getSelectedFormat}.
+ *
This class doesn't provide a way to determine which of the selected tracks is currently
+ * playing, however some player implementations have ways of getting such information. For
+ * example, ExoPlayer provides this information via {@code ExoTrackSelection.getSelectedFormat}.
*
* @param trackIndex The index of the track in the {@link TrackGroup}.
- * @return true if the track is selected, false otherwise.
+ * @return True if the track is selected, false otherwise.
*/
public boolean isTrackSelected(int trackIndex) {
return trackSelected[trackIndex];
}
- /**
- * Returns the {@link C.TrackType} of the tracks in the {@link TrackGroup}. Tracks in a group
- * are all of the same type.
- */
+ /** Returns the {@link C.TrackType} of the group. */
public @C.TrackType int getTrackType() {
return trackType;
}
@@ -212,28 +243,49 @@ public final class TracksInfo implements Bundleable {
private final ImmutableList trackGroupInfos;
- /** An empty {@code TrackInfo} containing no {@link TrackGroupInfo}. */
+ /** An {@code TrackInfo} that contains no tracks. */
public static final TracksInfo EMPTY = new TracksInfo(ImmutableList.of());
- /** Constructs {@code TracksInfo} from the provided {@link TrackGroupInfo}. */
+ /**
+ * Constructs an instance.
+ *
+ * @param trackGroupInfos The {@link TrackGroupInfo TrackGroupInfos} describing the groups of
+ * tracks.
+ */
public TracksInfo(List trackGroupInfos) {
this.trackGroupInfos = ImmutableList.copyOf(trackGroupInfos);
}
- /** Returns the {@link TrackGroupInfo TrackGroupInfos}, describing each {@link TrackGroup}. */
+ /** Returns the {@link TrackGroupInfo TrackGroupInfos} describing the groups of tracks. */
public ImmutableList getTrackGroupInfos() {
return trackGroupInfos;
}
/**
* Returns true if at least one track of type {@code trackType} is {@link
- * TrackGroupInfo#isTrackSupported(int) supported}, or there are no tracks of this type.
+ * TrackGroupInfo#isTrackSupported(int) supported} or if there are no tracks of this type.
*/
public boolean isTypeSupportedOrEmpty(@C.TrackType int trackType) {
+ return isTypeSupportedOrEmpty(trackType, /* allowExceedsCapabilities= */ false);
+ }
+
+ /**
+ * Returns true if at least one track of type {@code trackType} is {@link
+ * TrackGroupInfo#isTrackSupported(int, boolean) supported} or if there are no tracks of this
+ * type.
+ *
+ * @param allowExceedsCapabilities Whether to consider the track as supported if it has a
+ * supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised
+ * capabilities of the device. For example, a video track for which there's a corresponding
+ * decoder whose maximum advertised resolution is exceeded by the resolution of the track.
+ * Such tracks may be playable in some cases.
+ */
+ public boolean isTypeSupportedOrEmpty(
+ @C.TrackType int trackType, boolean allowExceedsCapabilities) {
boolean supported = true;
for (int i = 0; i < trackGroupInfos.size(); i++) {
if (trackGroupInfos.get(i).trackType == trackType) {
- if (trackGroupInfos.get(i).isSupported()) {
+ if (trackGroupInfos.get(i).isSupported(allowExceedsCapabilities)) {
return true;
} else {
supported = false;
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java b/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java
index 45b2293c24..2922e02648 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/util/MediaFormatUtil.java
@@ -220,6 +220,17 @@ public final class MediaFormatUtil {
case C.ENCODING_PCM_FLOAT:
mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_FLOAT;
break;
+ case C.ENCODING_PCM_24BIT:
+ mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_24BIT_PACKED;
+ break;
+ case C.ENCODING_PCM_32BIT:
+ mediaFormatPcmEncoding = AudioFormat.ENCODING_PCM_32BIT;
+ break;
+ case C.ENCODING_INVALID:
+ mediaFormatPcmEncoding = AudioFormat.ENCODING_INVALID;
+ break;
+ case Format.NO_VALUE:
+ case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
default:
// No matching value. Do nothing.
return;
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java
index 9dad181b91..b21b247f76 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/util/Util.java
@@ -2405,6 +2405,8 @@ public final class Util {
return "camera motion";
case C.TRACK_TYPE_NONE:
return "none";
+ case C.TRACK_TYPE_UNKNOWN:
+ return "unknown";
default:
return trackType >= C.TRACK_TYPE_CUSTOM_BASE ? "custom (" + trackType + ")" : "?";
}
@@ -2537,6 +2539,20 @@ public final class Util {
.build();
}
+ /**
+ * Returns the sum of all summands of the given array.
+ *
+ * @param summands The summands to calculate the sum from.
+ * @return The sum of all summands.
+ */
+ public static long sum(long... summands) {
+ long sum = 0;
+ for (long summand : summands) {
+ sum += summand;
+ }
+ return sum;
+ }
+
@Nullable
private static String getSystemProperty(String name) {
try {
diff --git a/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java b/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java
index d35cbe5853..68501f1055 100644
--- a/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java
+++ b/library/common/src/test/java/com/google/android/exoplayer2/util/MediaFormatUtilTest.java
@@ -146,10 +146,10 @@ public class MediaFormatUtilTest {
@Test
public void createMediaFormatFromFormat_withPcmEncoding_setsCustomPcmEncodingEntry() {
- Format format = new Format.Builder().setPcmEncoding(C.ENCODING_PCM_32BIT).build();
+ Format format = new Format.Builder().setPcmEncoding(C.ENCODING_PCM_16BIT_BIG_ENDIAN).build();
MediaFormat mediaFormat = MediaFormatUtil.createMediaFormatFromFormat(format);
assertThat(mediaFormat.getInteger(MediaFormatUtil.KEY_PCM_ENCODING_EXTENDED))
- .isEqualTo(C.ENCODING_PCM_32BIT);
+ .isEqualTo(C.ENCODING_PCM_16BIT_BIG_ENDIAN);
assertThat(mediaFormat.containsKey(MediaFormat.KEY_PCM_ENCODING)).isFalse();
}
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java
index 683db1ecbc..ac35a5148a 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java
@@ -99,10 +99,9 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
Assertions.checkState(state == STATE_DISABLED);
this.configuration = configuration;
state = STATE_ENABLED;
- lastResetPositionUs = positionUs;
onEnabled(joining, mayRenderStartOfStream);
replaceStream(formats, stream, startPositionUs, offsetUs);
- onPositionReset(positionUs, joining);
+ resetPosition(positionUs, joining);
}
@Override
@@ -159,10 +158,14 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
@Override
public final void resetPosition(long positionUs) throws ExoPlaybackException {
+ resetPosition(positionUs, /* joining= */ false);
+ }
+
+ private void resetPosition(long positionUs, boolean joining) throws ExoPlaybackException {
streamIsFinal = false;
lastResetPositionUs = positionUs;
readingPositionUs = positionUs;
- onPositionReset(positionUs, false);
+ onPositionReset(positionUs, joining);
}
@Override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
index 53b196fbb9..9a9a3fa1e2 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayer.java
@@ -1456,19 +1456,6 @@ public interface ExoPlayer extends Player {
*/
void setPriorityTaskManager(@Nullable PriorityTaskManager priorityTaskManager);
- /**
- * Sets whether the player should throw an {@link IllegalStateException} when methods are called
- * from a thread other than the one associated with {@link #getApplicationLooper()}.
- *
- * The default is {@code true} and this method will be removed in the future.
- *
- * @param throwsWhenUsingWrongThread Whether to throw when methods are called from a wrong thread.
- * @deprecated Disabling the enforcement can result in hard-to-detect bugs. Do not use this method
- * except to ease the transition while wrong thread access problems are fixed.
- */
- @Deprecated
- void setThrowsWhenUsingWrongThread(boolean throwsWhenUsingWrongThread);
-
/**
* Sets whether audio offload scheduling is enabled. If enabled, ExoPlayer's main loop will run as
* rarely as possible when playing an audio stream using audio offload.
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
index f1082e7533..c893d49864 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java
@@ -230,7 +230,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
BandwidthMeter bandwidthMeter,
@Player.RepeatMode int repeatMode,
boolean shuffleModeEnabled,
- @Nullable AnalyticsCollector analyticsCollector,
+ AnalyticsCollector analyticsCollector,
SeekParameters seekParameters,
LivePlaybackSpeedControl livePlaybackSpeedControl,
long releaseTimeoutMs,
@@ -1226,7 +1226,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
/* forceBufferingState= */ playbackInfo.playbackState == Player.STATE_ENDED);
seekPositionAdjusted |= periodPositionUs != newPeriodPositionUs;
periodPositionUs = newPeriodPositionUs;
- updateLivePlaybackSpeedControl(
+ updatePlaybackSpeedSettingsForNewPeriod(
/* newTimeline= */ playbackInfo.timeline,
/* newPeriodId= */ periodId,
/* oldTimeline= */ playbackInfo.timeline,
@@ -1866,7 +1866,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
newPositionUs = seekToPeriodPosition(newPeriodId, newPositionUs, forceBufferingState);
}
} finally {
- updateLivePlaybackSpeedControl(
+ updatePlaybackSpeedSettingsForNewPeriod(
/* newTimeline= */ timeline,
newPeriodId,
/* oldTimeline= */ playbackInfo.timeline,
@@ -1906,16 +1906,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- private void updateLivePlaybackSpeedControl(
+ private void updatePlaybackSpeedSettingsForNewPeriod(
Timeline newTimeline,
MediaPeriodId newPeriodId,
Timeline oldTimeline,
MediaPeriodId oldPeriodId,
long positionForTargetOffsetOverrideUs) {
- if (newTimeline.isEmpty() || !shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) {
- // Live playback speed control is unused for the current period, reset speed if adjusted.
- if (mediaClock.getPlaybackParameters().speed != playbackInfo.playbackParameters.speed) {
- mediaClock.setPlaybackParameters(playbackInfo.playbackParameters);
+ if (!shouldUseLivePlaybackSpeedControl(newTimeline, newPeriodId)) {
+ // Live playback speed control is unused for the current period, reset speed to user-defined
+ // playback parameters or 1.0 for ad playback.
+ PlaybackParameters targetPlaybackParameters =
+ newPeriodId.isAd() ? PlaybackParameters.DEFAULT : playbackInfo.playbackParameters;
+ if (!mediaClock.getPlaybackParameters().equals(targetPlaybackParameters)) {
+ mediaClock.setPlaybackParameters(targetPlaybackParameters);
}
return;
}
@@ -2046,10 +2049,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
return;
}
+ MediaPeriodHolder oldReadingPeriodHolder = readingPeriodHolder;
TrackSelectorResult oldTrackSelectorResult = readingPeriodHolder.getTrackSelectorResult();
readingPeriodHolder = queue.advanceReadingPeriod();
TrackSelectorResult newTrackSelectorResult = readingPeriodHolder.getTrackSelectorResult();
+ updatePlaybackSpeedSettingsForNewPeriod(
+ /* newTimeline= */ playbackInfo.timeline,
+ /* newPeriodId= */ readingPeriodHolder.info.id,
+ /* oldTimeline= */ playbackInfo.timeline,
+ /* oldPeriodId= */ oldReadingPeriodHolder.info.id,
+ /* positionForTargetOffsetOverrideUs= */ C.TIME_UNSET);
+
if (readingPeriodHolder.prepared
&& readingPeriodHolder.mediaPeriod.readDiscontinuity() != C.TIME_UNSET) {
// The new period starts with a discontinuity, so the renderers will play out all data, then
@@ -2134,7 +2145,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
// If we advance more than one period at a time, notify listeners after each update.
maybeNotifyPlaybackInfoChanged();
}
- MediaPeriodHolder oldPlayingPeriodHolder = queue.getPlayingPeriod();
MediaPeriodHolder newPlayingPeriodHolder = queue.advancePlayingPeriod();
playbackInfo =
handlePositionDiscontinuity(
@@ -2144,12 +2154,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
/* discontinuityStartPositionUs= */ newPlayingPeriodHolder.info.startPositionUs,
/* reportDiscontinuity= */ true,
Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
- updateLivePlaybackSpeedControl(
- /* newTimeline= */ playbackInfo.timeline,
- /* newPeriodId= */ newPlayingPeriodHolder.info.id,
- /* oldTimeline= */ playbackInfo.timeline,
- /* oldPeriodId= */ oldPlayingPeriodHolder.info.id,
- /* positionForTargetOffsetOverrideUs= */ C.TIME_UNSET);
resetPendingPauseAtEndOfPeriod();
updatePlaybackPositions();
advancedPlayingPeriod = true;
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java
index e34dffd595..797ec91add 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodQueue.java
@@ -66,7 +66,7 @@ import com.google.common.collect.ImmutableList;
private final Timeline.Period period;
private final Timeline.Window window;
- @Nullable private final AnalyticsCollector analyticsCollector;
+ private final AnalyticsCollector analyticsCollector;
private final Handler analyticsCollectorHandler;
private long nextWindowSequenceNumber;
@@ -82,13 +82,12 @@ import com.google.common.collect.ImmutableList;
/**
* Creates a new media period queue.
*
- * @param analyticsCollector An optional {@link AnalyticsCollector} to be informed of queue
- * changes.
+ * @param analyticsCollector An {@link AnalyticsCollector} to be informed of queue changes.
* @param analyticsCollectorHandler The {@link Handler} to call {@link AnalyticsCollector} methods
* on.
*/
public MediaPeriodQueue(
- @Nullable AnalyticsCollector analyticsCollector, Handler analyticsCollectorHandler) {
+ AnalyticsCollector analyticsCollector, Handler analyticsCollectorHandler) {
this.analyticsCollector = analyticsCollector;
this.analyticsCollectorHandler = analyticsCollectorHandler;
period = new Timeline.Period();
@@ -451,17 +450,15 @@ import com.google.common.collect.ImmutableList;
// Internal methods.
private void notifyQueueUpdate() {
- if (analyticsCollector != null) {
- ImmutableList.Builder builder = ImmutableList.builder();
- @Nullable MediaPeriodHolder period = playing;
- while (period != null) {
- builder.add(period.info.id);
- period = period.getNext();
- }
- @Nullable MediaPeriodId readingPeriodId = reading == null ? null : reading.info.id;
- analyticsCollectorHandler.post(
- () -> analyticsCollector.updateMediaPeriodQueueInfo(builder.build(), readingPeriodId));
+ ImmutableList.Builder builder = ImmutableList.builder();
+ @Nullable MediaPeriodHolder period = playing;
+ while (period != null) {
+ builder.add(period.info.id);
+ period = period.getNext();
}
+ @Nullable MediaPeriodId readingPeriodId = reading == null ? null : reading.info.id;
+ analyticsCollectorHandler.post(
+ () -> analyticsCollector.updateMediaPeriodQueueInfo(builder.build(), readingPeriodId));
}
/**
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java
index 95da840f95..389ae64b74 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaSourceList.java
@@ -91,15 +91,15 @@ import java.util.Set;
*
* @param listener The {@link MediaSourceListInfoRefreshListener} to be informed of timeline
* changes.
- * @param analyticsCollector An optional {@link AnalyticsCollector} to be registered for media
- * source events.
+ * @param analyticsCollector An {@link AnalyticsCollector} to be registered for media source
+ * events.
* @param analyticsCollectorHandler The {@link Handler} to call {@link AnalyticsCollector} methods
* on.
* @param playerId The {@link PlayerId} of the player using this list.
*/
public MediaSourceList(
MediaSourceListInfoRefreshListener listener,
- @Nullable AnalyticsCollector analyticsCollector,
+ AnalyticsCollector analyticsCollector,
Handler analyticsCollectorHandler,
PlayerId playerId) {
this.playerId = playerId;
@@ -112,10 +112,8 @@ import java.util.Set;
drmEventDispatcher = new DrmSessionEventListener.EventDispatcher();
childSources = new HashMap<>();
enabledMediaSourceHolders = new HashSet<>();
- if (analyticsCollector != null) {
- mediaSourceEventDispatcher.addEventListener(analyticsCollectorHandler, analyticsCollector);
- drmEventDispatcher.addEventListener(analyticsCollectorHandler, analyticsCollector);
- }
+ mediaSourceEventDispatcher.addEventListener(analyticsCollectorHandler, analyticsCollector);
+ drmEventDispatcher.addEventListener(analyticsCollectorHandler, analyticsCollector);
}
/**
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
index 519904bf2e..ed5d0ca1eb 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
@@ -1541,9 +1541,7 @@ public class SimpleExoPlayer extends BasePlayer
streamVolumeManager.setMuted(muted);
}
- @Deprecated
- @Override
- public void setThrowsWhenUsingWrongThread(boolean throwsWhenUsingWrongThread) {
+ /* package */ void setThrowsWhenUsingWrongThread(boolean throwsWhenUsingWrongThread) {
this.throwsWhenUsingWrongThread = throwsWhenUsingWrongThread;
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
index 2403f9bf77..b3393b67fd 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManager.java
@@ -177,7 +177,8 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
Iterator iterator = sessions.values().iterator();
while (iterator.hasNext()) {
SessionDescriptor session = iterator.next();
- if (!session.tryResolvingToNewTimeline(previousTimeline, currentTimeline)) {
+ if (!session.tryResolvingToNewTimeline(previousTimeline, currentTimeline)
+ || session.isFinishedAtEventTime(eventTime)) {
iterator.remove();
if (session.isCreated) {
if (session.sessionId.equals(currentSessionId)) {
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/MediaMetricsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/MediaMetricsListener.java
index 15340b4e30..e42a751a34 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/MediaMetricsListener.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/MediaMetricsListener.java
@@ -40,6 +40,7 @@ import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.C.ContentType;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.Format;
@@ -65,7 +66,6 @@ import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.UdpDataSource;
-import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.NetworkTypeObserver;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoSize;
@@ -74,6 +74,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
+import java.util.HashMap;
import java.util.UUID;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
@@ -112,7 +113,10 @@ public final class MediaMetricsListener
private final long startTimeMs;
private final Timeline.Window window;
private final Timeline.Period period;
+ private final HashMap bandwidthTimeMs;
+ private final HashMap bandwidthBytes;
+ @Nullable private String activeSessionId;
@Nullable private PlaybackMetrics.Builder metricsBuilder;
@Player.DiscontinuityReason private int discontinuityReason;
private int currentPlaybackState;
@@ -129,8 +133,6 @@ public final class MediaMetricsListener
private boolean hasFatalError;
private int droppedFrames;
private int playedFrames;
- private long bandwidthTimeMs;
- private long bandwidthBytes;
private int audioUnderruns;
/**
@@ -144,6 +146,8 @@ public final class MediaMetricsListener
this.playbackSession = playbackSession;
window = new Timeline.Window();
period = new Timeline.Period();
+ bandwidthBytes = new HashMap<>();
+ bandwidthTimeMs = new HashMap<>();
startTimeMs = SystemClock.elapsedRealtime();
currentPlaybackState = PlaybackStateEvent.STATE_NOT_STARTED;
currentNetworkType = NetworkEvent.NETWORK_TYPE_UNKNOWN;
@@ -168,6 +172,7 @@ public final class MediaMetricsListener
return;
}
finishCurrentSession();
+ activeSessionId = sessionId;
metricsBuilder =
new PlaybackMetrics.Builder()
.setPlayerName(ExoPlayerLibraryInfo.TAG)
@@ -182,11 +187,14 @@ public final class MediaMetricsListener
@Override
public void onSessionFinished(
EventTime eventTime, String sessionId, boolean automaticTransitionToNextPlayback) {
- if (eventTime.mediaPeriodId != null && eventTime.mediaPeriodId.isAd()) {
- // Ignore ad sessions.
- return;
+ if ((eventTime.mediaPeriodId != null && eventTime.mediaPeriodId.isAd())
+ || !sessionId.equals(activeSessionId)) {
+ // Ignore ad sessions and other sessions that are finished before becoming active.
+ } else {
+ finishCurrentSession();
}
- finishCurrentSession();
+ bandwidthTimeMs.remove(sessionId);
+ bandwidthBytes.remove(sessionId);
}
// AnalyticsListener implementation.
@@ -213,8 +221,17 @@ public final class MediaMetricsListener
@Override
public void onBandwidthEstimate(
EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {
- bandwidthTimeMs += totalLoadTimeMs;
- bandwidthBytes += totalBytesLoaded;
+ if (eventTime.mediaPeriodId != null) {
+ String sessionId =
+ sessionManager.getSessionForMediaPeriodId(
+ eventTime.timeline, checkNotNull(eventTime.mediaPeriodId));
+ @Nullable Long prevBandwidthBytes = bandwidthBytes.get(sessionId);
+ @Nullable Long prevBandwidthTimeMs = bandwidthTimeMs.get(sessionId);
+ bandwidthBytes.put(
+ sessionId, (prevBandwidthBytes == null ? 0 : prevBandwidthBytes) + totalBytesLoaded);
+ bandwidthTimeMs.put(
+ sessionId, (prevBandwidthTimeMs == null ? 0 : prevBandwidthTimeMs) + totalLoadTimeMs);
+ }
}
@Override
@@ -578,16 +595,25 @@ public final class MediaMetricsListener
metricsBuilder.setAudioUnderrunCount(audioUnderruns);
metricsBuilder.setVideoFramesDropped(droppedFrames);
metricsBuilder.setVideoFramesPlayed(playedFrames);
- metricsBuilder.setNetworkTransferDurationMillis(bandwidthTimeMs);
+ @Nullable Long networkTimeMs = bandwidthTimeMs.get(activeSessionId);
+ metricsBuilder.setNetworkTransferDurationMillis(networkTimeMs == null ? 0 : networkTimeMs);
// TODO(b/181121847): Report localBytesRead. This requires additional callbacks or plumbing.
- metricsBuilder.setNetworkBytesRead(bandwidthBytes);
+ @Nullable Long networkBytes = bandwidthBytes.get(activeSessionId);
+ metricsBuilder.setNetworkBytesRead(networkBytes == null ? 0 : networkBytes);
// TODO(b/181121847): Detect stream sources mixed and local depending on localBytesRead.
metricsBuilder.setStreamSource(
- bandwidthBytes > 0
+ networkBytes != null && networkBytes > 0
? PlaybackMetrics.STREAM_SOURCE_NETWORK
: PlaybackMetrics.STREAM_SOURCE_UNKNOWN);
playbackSession.reportPlaybackMetrics(metricsBuilder.build());
metricsBuilder = null;
+ activeSessionId = null;
+ audioUnderruns = 0;
+ droppedFrames = 0;
+ playedFrames = 0;
+ currentVideoFormat = null;
+ currentAudioFormat = null;
+ currentTextFormat = null;
}
private static int getTrackChangeReason(@C.SelectionReason int trackSelectionReason) {
@@ -636,19 +662,23 @@ public final class MediaMetricsListener
}
private static int getStreamType(MediaItem mediaItem) {
- if (mediaItem.localConfiguration == null || mediaItem.localConfiguration.mimeType == null) {
+ if (mediaItem.localConfiguration == null) {
return PlaybackMetrics.STREAM_TYPE_UNKNOWN;
}
- String mimeType = mediaItem.localConfiguration.mimeType;
- switch (mimeType) {
- case MimeTypes.APPLICATION_M3U8:
+ @ContentType
+ int contentType =
+ Util.inferContentTypeForUriAndMimeType(
+ mediaItem.localConfiguration.uri, mediaItem.localConfiguration.mimeType);
+ switch (contentType) {
+ case C.TYPE_HLS:
return PlaybackMetrics.STREAM_TYPE_HLS;
- case MimeTypes.APPLICATION_MPD:
+ case C.TYPE_DASH:
return PlaybackMetrics.STREAM_TYPE_DASH;
- case MimeTypes.APPLICATION_SS:
+ case C.TYPE_SS:
return PlaybackMetrics.STREAM_TYPE_SS;
+ case C.TYPE_RTSP:
default:
- return PlaybackMetrics.STREAM_TYPE_PROGRESSIVE;
+ return PlaybackMetrics.STREAM_TYPE_OTHER;
}
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
index 4105408289..2fa6c708aa 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java
@@ -404,6 +404,13 @@ public interface AudioSink {
*/
void setAudioAttributes(AudioAttributes audioAttributes);
+ /**
+ * Returns the audio attributes used for audio playback, or {@code null} if the sink does not use
+ * audio attributes.
+ */
+ @Nullable
+ AudioAttributes getAudioAttributes();
+
/** Sets the audio session id. */
void setAudioSessionId(int audioSessionId);
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
index f62e354daa..c799a5d341 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java
@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.audio;
import static com.google.android.exoplayer2.audio.AudioCapabilities.DEFAULT_AUDIO_CAPABILITIES;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
+import static com.google.android.exoplayer2.util.Util.constrainValue;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.Math.max;
import static java.lang.Math.min;
@@ -209,6 +210,39 @@ public final class DefaultAudioSink implements AudioSink {
}
}
+ /** Provides the buffer size to use when creating an {@link AudioTrack}. */
+ interface AudioTrackBufferSizeProvider {
+ /** Default instance. */
+ AudioTrackBufferSizeProvider DEFAULT =
+ new DefaultAudioTrackBufferSizeProvider.Builder().build();
+ /**
+ * Returns the buffer size to use when creating an {@link AudioTrack} for a specific format and
+ * output mode.
+ *
+ * @param minBufferSizeInBytes The minimum buffer size in bytes required to play this format.
+ * See {@link AudioTrack#getMinBufferSize}.
+ * @param encoding The {@link C.Encoding} of the format.
+ * @param outputMode How the audio will be played. One of the {@link OutputMode output modes}.
+ * @param pcmFrameSize The size of the PCM frames if the {@code encoding} is PCM, 1 otherwise,
+ * in bytes.
+ * @param sampleRate The sample rate of the format, in Hz.
+ * @param maxAudioTrackPlaybackSpeed The maximum speed the content will be played using {@link
+ * AudioTrack#setPlaybackParams}. 0.5 is 2x slow motion, 1 is real time, 2 is 2x fast
+ * forward, etc. This will be {@code 1} unless {@link
+ * Builder#setEnableAudioTrackPlaybackParams} is enabled.
+ * @return The computed buffer size in bytes. It should always be {@code >=
+ * minBufferSizeInBytes}. The computed buffer size must contain an integer number of frames:
+ * {@code bufferSizeInBytes % pcmFrameSize == 0}.
+ */
+ int getBufferSizeInBytes(
+ int minBufferSizeInBytes,
+ @C.Encoding int encoding,
+ @OutputMode int outputMode,
+ int pcmFrameSize,
+ int sampleRate,
+ double maxAudioTrackPlaybackSpeed);
+ }
+
/** A builder to create {@link DefaultAudioSink} instances. */
public static final class Builder {
@@ -217,11 +251,13 @@ public final class DefaultAudioSink implements AudioSink {
private boolean enableFloatOutput;
private boolean enableAudioTrackPlaybackParams;
private int offloadMode;
+ AudioTrackBufferSizeProvider audioTrackBufferSizeProvider;
/** Creates a new builder. */
public Builder() {
audioCapabilities = DEFAULT_AUDIO_CAPABILITIES;
offloadMode = OFFLOAD_MODE_DISABLED;
+ audioTrackBufferSizeProvider = AudioTrackBufferSizeProvider.DEFAULT;
}
/**
@@ -302,6 +338,18 @@ public final class DefaultAudioSink implements AudioSink {
return this;
}
+ /**
+ * Sets an {@link AudioTrackBufferSizeProvider} to compute the buffer size when {@link
+ * #configure} is called with {@code specifiedBufferSize == 0}.
+ *
+ * The default value is {@link AudioTrackBufferSizeProvider#DEFAULT}.
+ */
+ public Builder setAudioTrackBufferSizeProvider(
+ AudioTrackBufferSizeProvider audioTrackBufferSizeProvider) {
+ this.audioTrackBufferSizeProvider = audioTrackBufferSizeProvider;
+ return this;
+ }
+
/** Builds the {@link DefaultAudioSink}. Must only be called once per Builder instance. */
public DefaultAudioSink build() {
if (audioProcessorChain == null) {
@@ -362,31 +410,18 @@ public final class DefaultAudioSink implements AudioSink {
*/
public static final int OFFLOAD_MODE_ENABLED_GAPLESS_DISABLED = 3;
+ /** Output mode of the audio sink. */
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({OUTPUT_MODE_PCM, OUTPUT_MODE_OFFLOAD, OUTPUT_MODE_PASSTHROUGH})
- private @interface OutputMode {}
+ public @interface OutputMode {}
- private static final int OUTPUT_MODE_PCM = 0;
- private static final int OUTPUT_MODE_OFFLOAD = 1;
- private static final int OUTPUT_MODE_PASSTHROUGH = 2;
-
- /** A minimum length for the {@link AudioTrack} buffer, in microseconds. */
- private static final long MIN_BUFFER_DURATION_US = 250_000;
- /** A maximum length for the {@link AudioTrack} buffer, in microseconds. */
- private static final long MAX_BUFFER_DURATION_US = 750_000;
- /** The length for passthrough {@link AudioTrack} buffers, in microseconds. */
- private static final long PASSTHROUGH_BUFFER_DURATION_US = 250_000;
- /** The length for offload {@link AudioTrack} buffers, in microseconds. */
- private static final long OFFLOAD_BUFFER_DURATION_US = 50_000_000;
-
- /**
- * A multiplication factor to apply to the minimum buffer size requested by the underlying {@link
- * AudioTrack}.
- */
- private static final int BUFFER_MULTIPLICATION_FACTOR = 4;
- /** To avoid underruns on some devices (e.g., Broadcom 7271), scale up the AC3 buffer duration. */
- private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2;
+ /** The audio sink plays PCM audio. */
+ public static final int OUTPUT_MODE_PCM = 0;
+ /** The audio sink plays encoded audio in offload. */
+ public static final int OUTPUT_MODE_OFFLOAD = 1;
+ /** The audio sink plays encoded audio in passthrough. */
+ public static final int OUTPUT_MODE_PASSTHROUGH = 2;
/**
* Native error code equivalent of {@link AudioTrack#ERROR_DEAD_OBJECT} to workaround missing
@@ -433,6 +468,7 @@ public final class DefaultAudioSink implements AudioSink {
private final PendingExceptionHolder
initializationExceptionPendingExceptionHolder;
private final PendingExceptionHolder writeExceptionPendingExceptionHolder;
+ private final AudioTrackBufferSizeProvider audioTrackBufferSizeProvider;
@Nullable private PlayerId playerId;
@Nullable private Listener listener;
@@ -553,6 +589,7 @@ public final class DefaultAudioSink implements AudioSink {
enableFloatOutput = Util.SDK_INT >= 21 && builder.enableFloatOutput;
enableAudioTrackPlaybackParams = Util.SDK_INT >= 23 && builder.enableAudioTrackPlaybackParams;
offloadMode = Util.SDK_INT >= 29 ? builder.offloadMode : OFFLOAD_MODE_DISABLED;
+ audioTrackBufferSizeProvider = builder.audioTrackBufferSizeProvider;
releasingConditionVariable = new ConditionVariable(true);
audioTrackPositionTracker = new AudioTrackPositionTracker(new PositionTrackerListener());
channelMappingAudioProcessor = new ChannelMappingAudioProcessor();
@@ -715,6 +752,16 @@ public final class DefaultAudioSink implements AudioSink {
outputChannelConfig = encodingAndChannelConfig.second;
}
}
+ int bufferSize =
+ specifiedBufferSize != 0
+ ? specifiedBufferSize
+ : audioTrackBufferSizeProvider.getBufferSizeInBytes(
+ getAudioTrackMinBufferSize(outputSampleRate, outputChannelConfig, outputEncoding),
+ outputEncoding,
+ outputMode,
+ outputPcmFrameSize,
+ outputSampleRate,
+ enableAudioTrackPlaybackParams ? MAX_PLAYBACK_SPEED : DEFAULT_PLAYBACK_SPEED);
if (outputEncoding == C.ENCODING_INVALID) {
throw new ConfigurationException(
@@ -736,8 +783,7 @@ public final class DefaultAudioSink implements AudioSink {
outputSampleRate,
outputChannelConfig,
outputEncoding,
- specifiedBufferSize,
- enableAudioTrackPlaybackParams,
+ bufferSize,
availableAudioProcessors);
if (isAudioTrackInitialized()) {
this.pendingConfiguration = pendingConfiguration;
@@ -1198,8 +1244,8 @@ public final class DefaultAudioSink implements AudioSink {
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
playbackParameters =
new PlaybackParameters(
- Util.constrainValue(playbackParameters.speed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED),
- Util.constrainValue(playbackParameters.pitch, MIN_PITCH, MAX_PITCH));
+ constrainValue(playbackParameters.speed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED),
+ constrainValue(playbackParameters.pitch, MIN_PITCH, MAX_PITCH));
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
setAudioTrackPlaybackParametersV23(playbackParameters);
} else {
@@ -1239,6 +1285,11 @@ public final class DefaultAudioSink implements AudioSink {
flush();
}
+ @Override
+ public AudioAttributes getAudioAttributes() {
+ return audioAttributes;
+ }
+
@Override
public void setAudioSessionId(int audioSessionId) {
if (this.audioSessionId != audioSessionId) {
@@ -1775,47 +1826,6 @@ public final class DefaultAudioSink implements AudioSink {
return Util.SDK_INT >= 29 && audioTrack.isOffloadedPlayback();
}
- private static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding) {
- switch (encoding) {
- case C.ENCODING_MP3:
- return MpegAudioUtil.MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AAC_LC:
- return AacUtil.AAC_LC_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AAC_HE_V1:
- return AacUtil.AAC_HE_V1_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AAC_HE_V2:
- return AacUtil.AAC_HE_V2_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AAC_XHE:
- return AacUtil.AAC_XHE_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AAC_ELD:
- return AacUtil.AAC_ELD_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AC3:
- return Ac3Util.AC3_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_E_AC3:
- case C.ENCODING_E_AC3_JOC:
- return Ac3Util.E_AC3_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_AC4:
- return Ac4Util.MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_DTS:
- return DtsUtil.DTS_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_DTS_HD:
- return DtsUtil.DTS_HD_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_DOLBY_TRUEHD:
- return Ac3Util.TRUEHD_MAX_RATE_BYTES_PER_SECOND;
- case C.ENCODING_PCM_16BIT:
- case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
- case C.ENCODING_PCM_24BIT:
- case C.ENCODING_PCM_32BIT:
- case C.ENCODING_PCM_8BIT:
- case C.ENCODING_PCM_FLOAT:
- case C.ENCODING_AAC_ER_BSAC:
- case C.ENCODING_INVALID:
- case Format.NO_VALUE:
- default:
- throw new IllegalArgumentException();
- }
- }
-
private static int getFramesPerEncodedSample(@C.Encoding int encoding, ByteBuffer buffer) {
switch (encoding) {
case C.ENCODING_MP3:
@@ -2005,6 +2015,13 @@ public final class DefaultAudioSink implements AudioSink {
.build();
}
+ private static int getAudioTrackMinBufferSize(
+ int sampleRateInHz, int channelConfig, int encoding) {
+ int minBufferSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, encoding);
+ Assertions.checkState(minBufferSize != AudioTrack.ERROR_BAD_VALUE);
+ return minBufferSize;
+ }
+
private final class PositionTrackerListener implements AudioTrackPositionTracker.Listener {
@Override
@@ -2099,8 +2116,7 @@ public final class DefaultAudioSink implements AudioSink {
int outputSampleRate,
int outputChannelConfig,
int outputEncoding,
- int specifiedBufferSize,
- boolean enableAudioTrackPlaybackParams,
+ int bufferSize,
AudioProcessor[] availableAudioProcessors) {
this.inputFormat = inputFormat;
this.inputPcmFrameSize = inputPcmFrameSize;
@@ -2109,10 +2125,8 @@ public final class DefaultAudioSink implements AudioSink {
this.outputSampleRate = outputSampleRate;
this.outputChannelConfig = outputChannelConfig;
this.outputEncoding = outputEncoding;
+ this.bufferSize = bufferSize;
this.availableAudioProcessors = availableAudioProcessors;
-
- // Call computeBufferSize() last as it depends on the other configuration values.
- this.bufferSize = computeBufferSize(specifiedBufferSize, enableAudioTrackPlaybackParams);
}
/** Returns if the configurations are sufficiently compatible to reuse the audio track. */
@@ -2132,10 +2146,6 @@ public final class DefaultAudioSink implements AudioSink {
return (frameCount * C.MICROS_PER_SECOND) / outputSampleRate;
}
- public long durationUsToFrames(long durationUs) {
- return (durationUs * outputSampleRate) / C.MICROS_PER_SECOND;
- }
-
public AudioTrack buildAudioTrack(
boolean tunneling, AudioAttributes audioAttributes, int audioSessionId)
throws InitializationException {
@@ -2236,49 +2246,6 @@ public final class DefaultAudioSink implements AudioSink {
}
}
- private int computeBufferSize(
- int specifiedBufferSize, boolean enableAudioTrackPlaybackParameters) {
- if (specifiedBufferSize != 0) {
- return specifiedBufferSize;
- }
- switch (outputMode) {
- case OUTPUT_MODE_PCM:
- return getPcmDefaultBufferSize(
- enableAudioTrackPlaybackParameters ? MAX_PLAYBACK_SPEED : DEFAULT_PLAYBACK_SPEED);
- case OUTPUT_MODE_OFFLOAD:
- return getEncodedDefaultBufferSize(OFFLOAD_BUFFER_DURATION_US);
- case OUTPUT_MODE_PASSTHROUGH:
- return getEncodedDefaultBufferSize(PASSTHROUGH_BUFFER_DURATION_US);
- default:
- throw new IllegalStateException();
- }
- }
-
- private int getEncodedDefaultBufferSize(long bufferDurationUs) {
- int rate = getMaximumEncodedRateBytesPerSecond(outputEncoding);
- if (outputEncoding == C.ENCODING_AC3) {
- rate *= AC3_BUFFER_MULTIPLICATION_FACTOR;
- }
- return (int) (bufferDurationUs * rate / C.MICROS_PER_SECOND);
- }
-
- private int getPcmDefaultBufferSize(float maxAudioTrackPlaybackSpeed) {
- int minBufferSize =
- AudioTrack.getMinBufferSize(outputSampleRate, outputChannelConfig, outputEncoding);
- Assertions.checkState(minBufferSize != AudioTrack.ERROR_BAD_VALUE);
- int multipliedBufferSize = minBufferSize * BUFFER_MULTIPLICATION_FACTOR;
- int minAppBufferSize = (int) durationUsToFrames(MIN_BUFFER_DURATION_US) * outputPcmFrameSize;
- int maxAppBufferSize =
- max(minBufferSize, (int) durationUsToFrames(MAX_BUFFER_DURATION_US) * outputPcmFrameSize);
- int bufferSize =
- Util.constrainValue(multipliedBufferSize, minAppBufferSize, maxAppBufferSize);
- if (maxAudioTrackPlaybackSpeed != 1f) {
- // Maintain the buffer duration by scaling the size accordingly.
- bufferSize = Math.round(bufferSize * maxAudioTrackPlaybackSpeed);
- }
- return bufferSize;
- }
-
@RequiresApi(21)
private static android.media.AudioAttributes getAudioTrackAttributesV21(
AudioAttributes audioAttributes, boolean tunneling) {
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioTrackBufferSizeProvider.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioTrackBufferSizeProvider.java
new file mode 100644
index 0000000000..1f4cab21af
--- /dev/null
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioTrackBufferSizeProvider.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2021 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 com.google.android.exoplayer2.audio;
+
+import static com.google.android.exoplayer2.audio.DefaultAudioSink.OUTPUT_MODE_OFFLOAD;
+import static com.google.android.exoplayer2.audio.DefaultAudioSink.OUTPUT_MODE_PASSTHROUGH;
+import static com.google.android.exoplayer2.audio.DefaultAudioSink.OUTPUT_MODE_PCM;
+import static com.google.android.exoplayer2.util.Util.constrainValue;
+import static com.google.common.primitives.Ints.checkedCast;
+import static java.lang.Math.max;
+
+import android.media.AudioTrack;
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.audio.DefaultAudioSink.OutputMode;
+
+/** Provide the buffer size to use when creating an {@link AudioTrack}. */
+public class DefaultAudioTrackBufferSizeProvider
+ implements DefaultAudioSink.AudioTrackBufferSizeProvider {
+
+ /** Default minimum length for the {@link AudioTrack} buffer, in microseconds. */
+ private static final int MIN_PCM_BUFFER_DURATION_US = 250_000;
+ /** Default maximum length for the {@link AudioTrack} buffer, in microseconds. */
+ private static final int MAX_PCM_BUFFER_DURATION_US = 750_000;
+ /** Default multiplication factor to apply to the minimum buffer size requested. */
+ private static final int PCM_BUFFER_MULTIPLICATION_FACTOR = 4;
+ /** Default length for passthrough {@link AudioTrack} buffers, in microseconds. */
+ private static final int PASSTHROUGH_BUFFER_DURATION_US = 250_000;
+ /** Default length for offload {@link AudioTrack} buffers, in microseconds. */
+ private static final int OFFLOAD_BUFFER_DURATION_US = 50_000_000;
+ /**
+ * Default multiplication factor to apply to AC3 passthrough buffer to avoid underruns on some
+ * devices (e.g., Broadcom 7271).
+ */
+ private static final int AC3_BUFFER_MULTIPLICATION_FACTOR = 2;
+
+ /** A builder to create {@link DefaultAudioTrackBufferSizeProvider} instances. */
+ public static class Builder {
+
+ private int minPcmBufferDurationUs;
+ private int maxPcmBufferDurationUs;
+ private int pcmBufferMultiplicationFactor;
+ private int passthroughBufferDurationUs;
+ private int offloadBufferDurationUs;
+ private int ac3BufferMultiplicationFactor;
+
+ /** Creates a new builder. */
+ public Builder() {
+ minPcmBufferDurationUs = MIN_PCM_BUFFER_DURATION_US;
+ maxPcmBufferDurationUs = MAX_PCM_BUFFER_DURATION_US;
+ pcmBufferMultiplicationFactor = PCM_BUFFER_MULTIPLICATION_FACTOR;
+ passthroughBufferDurationUs = PASSTHROUGH_BUFFER_DURATION_US;
+ offloadBufferDurationUs = OFFLOAD_BUFFER_DURATION_US;
+ ac3BufferMultiplicationFactor = AC3_BUFFER_MULTIPLICATION_FACTOR;
+ }
+
+ /**
+ * Sets the minimum length for PCM {@link AudioTrack} buffers, in microseconds. Default is
+ * {@value #MIN_PCM_BUFFER_DURATION_US}.
+ */
+ public Builder setMinPcmBufferDurationUs(int minPcmBufferDurationUs) {
+ this.minPcmBufferDurationUs = minPcmBufferDurationUs;
+ return this;
+ }
+
+ /**
+ * Sets the maximum length for PCM {@link AudioTrack} buffers, in microseconds. Default is
+ * {@value #MAX_PCM_BUFFER_DURATION_US}.
+ */
+ public Builder setMaxPcmBufferDurationUs(int maxPcmBufferDurationUs) {
+ this.maxPcmBufferDurationUs = maxPcmBufferDurationUs;
+ return this;
+ }
+
+ /**
+ * Sets the multiplication factor to apply to the minimum buffer size requested. Default is
+ * {@value #PCM_BUFFER_MULTIPLICATION_FACTOR}.
+ */
+ public Builder setPcmBufferMultiplicationFactor(int pcmBufferMultiplicationFactor) {
+ this.pcmBufferMultiplicationFactor = pcmBufferMultiplicationFactor;
+ return this;
+ }
+
+ /**
+ * Sets the length for passthrough {@link AudioTrack} buffers, in microseconds. Default is
+ * {@value #PASSTHROUGH_BUFFER_DURATION_US}.
+ */
+ public Builder setPassthroughBufferDurationUs(int passthroughBufferDurationUs) {
+ this.passthroughBufferDurationUs = passthroughBufferDurationUs;
+ return this;
+ }
+
+ /**
+ * The length for offload {@link AudioTrack} buffers, in microseconds. Default is {@value
+ * #OFFLOAD_BUFFER_DURATION_US}.
+ */
+ public Builder setOffloadBufferDurationUs(int offloadBufferDurationUs) {
+ this.offloadBufferDurationUs = offloadBufferDurationUs;
+ return this;
+ }
+
+ /**
+ * Sets the multiplication factor to apply to the passthrough buffer for AC3 to avoid underruns
+ * on some devices (e.g., Broadcom 7271). Default is {@value #AC3_BUFFER_MULTIPLICATION_FACTOR}.
+ */
+ public Builder setAc3BufferMultiplicationFactor(int ac3BufferMultiplicationFactor) {
+ this.ac3BufferMultiplicationFactor = ac3BufferMultiplicationFactor;
+ return this;
+ }
+
+ /** Build the {@link DefaultAudioTrackBufferSizeProvider}. */
+ public DefaultAudioTrackBufferSizeProvider build() {
+ return new DefaultAudioTrackBufferSizeProvider(this);
+ }
+ }
+
+ /** The minimum length for PCM {@link AudioTrack} buffers, in microseconds. */
+ protected final int minPcmBufferDurationUs;
+ /** The maximum length for PCM {@link AudioTrack} buffers, in microseconds. */
+ protected final int maxPcmBufferDurationUs;
+ /** The multiplication factor to apply to the minimum buffer size requested. */
+ protected final int pcmBufferMultiplicationFactor;
+ /** The length for passthrough {@link AudioTrack} buffers, in microseconds. */
+ protected final int passthroughBufferDurationUs;
+ /** The length for offload {@link AudioTrack} buffers, in microseconds. */
+ protected final int offloadBufferDurationUs;
+ /**
+ * The multiplication factor to apply to AC3 passthrough buffer to avoid underruns on some devices
+ * (e.g., Broadcom 7271).
+ */
+ public final int ac3BufferMultiplicationFactor;
+
+ protected DefaultAudioTrackBufferSizeProvider(Builder builder) {
+ minPcmBufferDurationUs = builder.minPcmBufferDurationUs;
+ maxPcmBufferDurationUs = builder.maxPcmBufferDurationUs;
+ pcmBufferMultiplicationFactor = builder.pcmBufferMultiplicationFactor;
+ passthroughBufferDurationUs = builder.passthroughBufferDurationUs;
+ offloadBufferDurationUs = builder.offloadBufferDurationUs;
+ ac3BufferMultiplicationFactor = builder.ac3BufferMultiplicationFactor;
+ }
+
+ @Override
+ public int getBufferSizeInBytes(
+ int minBufferSizeInBytes,
+ @C.Encoding int encoding,
+ @OutputMode int outputMode,
+ int pcmFrameSize,
+ int sampleRate,
+ double maxAudioTrackPlaybackSpeed) {
+ int bufferSize =
+ get1xBufferSizeInBytes(
+ minBufferSizeInBytes, encoding, outputMode, pcmFrameSize, sampleRate);
+ // Maintain the buffer duration by scaling the size accordingly.
+ bufferSize = (int) (bufferSize * maxAudioTrackPlaybackSpeed);
+ // Buffer size must not be lower than the AudioTrack min buffer size for this format.
+ bufferSize = max(minBufferSizeInBytes, bufferSize);
+ // Increase if needed to make sure the buffers contains an integer number of frames.
+ return (bufferSize + pcmFrameSize - 1) / pcmFrameSize * pcmFrameSize;
+ }
+
+ /** Returns the buffer size for playback at 1x speed. */
+ protected int get1xBufferSizeInBytes(
+ int minBufferSizeInBytes, int encoding, int outputMode, int pcmFrameSize, int sampleRate) {
+ switch (outputMode) {
+ case OUTPUT_MODE_PCM:
+ return getPcmBufferSizeInBytes(minBufferSizeInBytes, sampleRate, pcmFrameSize);
+ case OUTPUT_MODE_PASSTHROUGH:
+ return getPassthroughBufferSizeInBytes(encoding);
+ case OUTPUT_MODE_OFFLOAD:
+ return getOffloadBufferSizeInBytes(encoding);
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /** Returns the buffer size for PCM playback. */
+ protected int getPcmBufferSizeInBytes(int minBufferSizeInBytes, int samplingRate, int frameSize) {
+ int targetBufferSize = minBufferSizeInBytes * pcmBufferMultiplicationFactor;
+ int minAppBufferSize = durationUsToBytes(minPcmBufferDurationUs, samplingRate, frameSize);
+ int maxAppBufferSize = durationUsToBytes(maxPcmBufferDurationUs, samplingRate, frameSize);
+ return constrainValue(targetBufferSize, minAppBufferSize, maxAppBufferSize);
+ }
+
+ /** Returns the buffer size for passthrough playback. */
+ protected int getPassthroughBufferSizeInBytes(@C.Encoding int encoding) {
+ int bufferSizeUs = passthroughBufferDurationUs;
+ if (encoding == C.ENCODING_AC3) {
+ bufferSizeUs *= ac3BufferMultiplicationFactor;
+ }
+ int maxByteRate = getMaximumEncodedRateBytesPerSecond(encoding);
+ return checkedCast((long) bufferSizeUs * maxByteRate / C.MICROS_PER_SECOND);
+ }
+
+ /** Returns the buffer size for offload playback. */
+ protected int getOffloadBufferSizeInBytes(@C.Encoding int encoding) {
+ int maxByteRate = getMaximumEncodedRateBytesPerSecond(encoding);
+ return checkedCast((long) offloadBufferDurationUs * maxByteRate / C.MICROS_PER_SECOND);
+ }
+
+ protected static int durationUsToBytes(int durationUs, int samplingRate, int frameSize) {
+ return checkedCast((long) durationUs * samplingRate * frameSize / C.MICROS_PER_SECOND);
+ }
+
+ protected static int getMaximumEncodedRateBytesPerSecond(@C.Encoding int encoding) {
+ switch (encoding) {
+ case C.ENCODING_MP3:
+ return MpegAudioUtil.MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AAC_LC:
+ return AacUtil.AAC_LC_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AAC_HE_V1:
+ return AacUtil.AAC_HE_V1_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AAC_HE_V2:
+ return AacUtil.AAC_HE_V2_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AAC_XHE:
+ return AacUtil.AAC_XHE_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AAC_ELD:
+ return AacUtil.AAC_ELD_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AC3:
+ return Ac3Util.AC3_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_E_AC3:
+ case C.ENCODING_E_AC3_JOC:
+ return Ac3Util.E_AC3_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_AC4:
+ return Ac4Util.MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_DTS:
+ return DtsUtil.DTS_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_DTS_HD:
+ return DtsUtil.DTS_HD_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_DOLBY_TRUEHD:
+ return Ac3Util.TRUEHD_MAX_RATE_BYTES_PER_SECOND;
+ case C.ENCODING_PCM_16BIT:
+ case C.ENCODING_PCM_16BIT_BIG_ENDIAN:
+ case C.ENCODING_PCM_24BIT:
+ case C.ENCODING_PCM_32BIT:
+ case C.ENCODING_PCM_8BIT:
+ case C.ENCODING_PCM_FLOAT:
+ case C.ENCODING_AAC_ER_BSAC:
+ case C.ENCODING_INVALID:
+ case Format.NO_VALUE:
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java
index f1b0af2dd5..ea248840de 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/ForwardingAudioSink.java
@@ -119,6 +119,12 @@ public class ForwardingAudioSink implements AudioSink {
sink.setAudioAttributes(audioAttributes);
}
+ @Override
+ @Nullable
+ public AudioAttributes getAudioAttributes() {
+ return sink.getAudioAttributes();
+ }
+
@Override
public void setAudioSessionId(int audioSessionId) {
sink.setAudioSessionId(audioSessionId);
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
index 42a5945f00..8275c6dbcb 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.audio;
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
import static com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.REUSE_RESULT_NO;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
+import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.Math.max;
@@ -29,7 +30,9 @@ import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Handler;
import androidx.annotation.CallSuper;
+import androidx.annotation.DoNotInline;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
@@ -57,8 +60,10 @@ import com.google.android.exoplayer2.util.MediaFormatUtil;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
+import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
import java.util.List;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* Decodes and renders audio using {@link MediaCodec} and an {@link AudioSink}.
@@ -94,6 +99,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private final Context context;
private final EventDispatcher eventDispatcher;
private final AudioSink audioSink;
+ private final SpatializationHelper spatializationHelper;
private int codecMaxInputSize;
private boolean codecNeedsDiscardChannelsWorkaround;
@@ -249,9 +255,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
mediaCodecSelector,
enableDecoderFallback,
/* assumedMinimumCodecOperatingRate= */ 44100);
- this.context = context.getApplicationContext();
+ context = context.getApplicationContext();
+ this.context = context;
this.audioSink = audioSink;
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
+ spatializationHelper = new SpatializationHelper(context, audioSink.getAudioAttributes());
audioSink.setListener(new AudioSinkListener());
}
@@ -410,6 +418,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return audioSink.supportsFormat(format);
}
+ @Override
+ protected boolean shouldReinitCodec() {
+ return spatializationHelper.shouldReinitCodec();
+ }
+
@Override
protected MediaCodecAdapter.Configuration getMediaCodecConfiguration(
MediaCodecInfo codecInfo,
@@ -470,7 +483,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override
protected void onCodecInitialized(
- String name, long initializedTimestampMs, long initializationDurationMs) {
+ String name,
+ MediaCodecAdapter.Configuration configuration,
+ long initializedTimestampMs,
+ long initializationDurationMs) {
+ spatializationHelper.onCodecInitialized(configuration);
eventDispatcher.decoderInitialized(name, initializedTimestampMs, initializationDurationMs);
}
@@ -561,6 +578,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
audioSink.disableTunneling();
}
audioSink.setPlayerId(getPlayerId());
+ spatializationHelper.enable();
}
@Override
@@ -613,6 +631,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
audioSinkNeedsReset = false;
audioSink.reset();
}
+ spatializationHelper.reset();
}
}
@@ -737,6 +756,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
case MSG_SET_AUDIO_ATTRIBUTES:
AudioAttributes audioAttributes = (AudioAttributes) message;
audioSink.setAudioAttributes(audioAttributes);
+ spatializationHelper.setAudioAttributes(audioSink.getAudioAttributes());
break;
case MSG_SET_AUX_EFFECT_INFO:
AuxEffectInfo auxEffectInfo = (AuxEffectInfo) message;
@@ -848,14 +868,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
== AudioSink.SINK_FORMAT_SUPPORTED_DIRECTLY) {
mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_FLOAT);
}
+ spatializationHelper.configureForSpatialization(mediaFormat, format);
- if (Util.SDK_INT >= 32) {
- // Disable down-mixing in the decoder (for decoders that read the max-output-channel-count
- // key).
- // TODO[b/190759307]: Update key to use MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT once the
- // compile SDK target is set to 32.
- mediaFormat.setInteger("max-output-channel-count", 99);
- }
return mediaFormat;
}
@@ -939,4 +953,163 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
eventDispatcher.audioSinkError(audioSinkError);
}
}
+
+ /**
+ * A helper class that signals whether the codec needs to be re-initialized because spatialization
+ * properties changed.
+ */
+ private static final class SpatializationHelper implements SpatializerDelegate.Listener {
+ // TODO[b/190759307] Remove and use MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT once the
+ // compile SDK target is set to 32.
+ private static final String KEY_MAX_OUTPUT_CHANNEL_COUNT = "max-output-channel-count";
+ private static final int SPATIALIZATION_CHANNEL_COUNT = 99;
+
+ @Nullable private final SpatializerDelegate spatializerDelegate;
+
+ private @MonotonicNonNull Handler handler;
+ @Nullable private AudioAttributes audioAttributes;
+ @Nullable private Format inputFormat;
+ private boolean codecConfiguredForSpatialization;
+ private boolean codecNeedsReinit;
+ private boolean listenerAdded;
+
+ /** Creates a new instance. */
+ public SpatializationHelper(Context context, @Nullable AudioAttributes audioAttributes) {
+ this.spatializerDelegate = maybeCreateSpatializer(context);
+ this.audioAttributes = audioAttributes;
+ }
+
+ /** Enables this helper. Call this method when the renderer is enabled. */
+ public void enable() {
+ maybeAddSpatalizationListener();
+ }
+
+ /** Resets the helper and releases any resources. Call this method when renderer is reset. */
+ public void reset() {
+ maybeRemoveSpatalizationListener();
+ }
+
+ /** Sets the audio attributes set by the player. */
+ public void setAudioAttributes(@Nullable AudioAttributes audioAttributes) {
+ if (Util.areEqual(this.audioAttributes, audioAttributes)) {
+ return;
+ }
+
+ this.audioAttributes = audioAttributes;
+ updateCodecNeedsReinit();
+ }
+
+ /**
+ * Sets keys for audio spatialization on the {@code mediaFormat} if the platform can apply
+ * spatialization to this {@code format}.
+ */
+ public void configureForSpatialization(MediaFormat mediaFormat, Format format) {
+ if (canBeSpatialized(format)) {
+ mediaFormat.setInteger(KEY_MAX_OUTPUT_CHANNEL_COUNT, SPATIALIZATION_CHANNEL_COUNT);
+ }
+ }
+
+ /** Informs the helper that a codec was initialized. */
+ public void onCodecInitialized(MediaCodecAdapter.Configuration configuration) {
+ codecNeedsReinit = false;
+ inputFormat = configuration.format;
+ codecConfiguredForSpatialization =
+ configuration.mediaFormat.containsKey(KEY_MAX_OUTPUT_CHANNEL_COUNT)
+ && configuration.mediaFormat.getInteger(KEY_MAX_OUTPUT_CHANNEL_COUNT)
+ == SPATIALIZATION_CHANNEL_COUNT;
+ }
+
+ /**
+ * Returns whether the codec should be re-initialized, caused by a change in the spatialization
+ * properties.
+ */
+ public boolean shouldReinitCodec() {
+ return codecNeedsReinit;
+ }
+
+ // SpatializerDelegate.Listener
+
+ @Override
+ public void onSpatializerEnabledChanged(SpatializerDelegate spatializer, boolean enabled) {
+ updateCodecNeedsReinit();
+ }
+
+ @Override
+ public void onSpatializerAvailableChanged(SpatializerDelegate spatializer, boolean available) {
+ updateCodecNeedsReinit();
+ }
+
+ // Other internal methods
+
+ /** Returns whether this format can be spatialized by the platform. */
+ private boolean canBeSpatialized(@Nullable Format format) {
+ if (Util.SDK_INT < 32
+ || format == null
+ || audioAttributes == null
+ || spatializerDelegate == null
+ || spatializerDelegate.getImmersiveAudioLevel()
+ != SpatializerDelegate.SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL
+ || !spatializerDelegate.isAvailable()
+ || !spatializerDelegate.isEnabled()) {
+ return false;
+ }
+ AudioFormat.Builder audioFormatBuilder =
+ new AudioFormat.Builder()
+ .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+ .setChannelMask(Util.getAudioTrackChannelConfig(format.channelCount));
+ if (format.sampleRate != Format.NO_VALUE) {
+ audioFormatBuilder.setSampleRate(format.sampleRate);
+ }
+ return spatializerDelegate.canBeSpatialized(
+ audioAttributes.getAudioAttributesV21(), audioFormatBuilder.build());
+ }
+
+ private void maybeAddSpatalizationListener() {
+ if (!listenerAdded && spatializerDelegate != null && Util.SDK_INT >= 32) {
+ if (handler == null) {
+ // Route callbacks to the playback thread.
+ handler = Util.createHandlerForCurrentLooper();
+ }
+ spatializerDelegate.addOnSpatializerStateChangedListener(handler::post, this);
+ listenerAdded = true;
+ }
+ }
+
+ private void maybeRemoveSpatalizationListener() {
+ if (listenerAdded && spatializerDelegate != null && Util.SDK_INT >= 32) {
+ spatializerDelegate.removeOnSpatializerStateChangedListener(this);
+ checkStateNotNull(handler).removeCallbacksAndMessages(null);
+ }
+ }
+
+ private void updateCodecNeedsReinit() {
+ codecNeedsReinit = codecConfiguredForSpatialization != canBeSpatialized(inputFormat);
+ }
+
+ @Nullable
+ private static SpatializerDelegate maybeCreateSpatializer(Context context) {
+ if (Util.SDK_INT >= 32) {
+ return Api32.createSpatializer(context);
+ }
+ return null;
+ }
+ }
+
+ @RequiresApi(32)
+ private static final class Api32 {
+ private Api32() {}
+
+ @DoNotInline
+ @Nullable
+ public static SpatializerDelegate createSpatializer(Context context) {
+ try {
+ return new SpatializerDelegate(context);
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
+ // Do nothing for these cases.
+ } catch (InvocationTargetException e) {
+ Log.w(TAG, "Failed to load Spatializer with reflection", e);
+ }
+ return null;
+ }
+ }
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
index ebebd0aee6..656ebe8fb0 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
@@ -564,6 +564,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return true;
}
+ /**
+ * Returns whether the renderer needs to re-initialize the codec, possibly as a result of a change
+ * in device capabilities.
+ */
+ protected boolean shouldReinitCodec() {
+ return false;
+ }
+
/**
* Returns whether the codec needs the renderer to propagate the end-of-stream signal directly,
* rather than by using an end-of-stream buffer queued to the codec.
@@ -1118,7 +1126,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
decoderCounters.decoderInitCount++;
long elapsed = codecInitializedTimestamp - codecInitializingTimestamp;
- onCodecInitialized(codecName, codecInitializedTimestamp, elapsed);
+ onCodecInitialized(codecName, configuration, codecInitializedTimestamp, elapsed);
}
private boolean shouldContinueRendering(long renderStartTimeMs) {
@@ -1158,6 +1166,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (codec == null || codecDrainState == DRAIN_STATE_WAIT_END_OF_STREAM || inputStreamEnded) {
return false;
}
+ if (codecDrainState == DRAIN_STATE_NONE && shouldReinitCodec()) {
+ drainAndReinitializeCodec();
+ }
if (inputIndex < 0) {
inputIndex = codec.dequeueInputBufferIndex();
@@ -1352,12 +1363,16 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* The default implementation is a no-op.
*
* @param name The name of the codec that was initialized.
+ * @param configuration The {@link MediaCodecAdapter.Configuration} used to configure the codec.
* @param initializedTimestampMs {@link SystemClock#elapsedRealtime()} when initialization
* finished.
* @param initializationDurationMs The time taken to initialize the codec in milliseconds.
*/
protected void onCodecInitialized(
- String name, long initializedTimestampMs, long initializationDurationMs) {
+ String name,
+ MediaCodecAdapter.Configuration configuration,
+ long initializedTimestampMs,
+ long initializationDurationMs) {
// Do nothing.
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java
index 4f1443c7d1..d6d3eb65c7 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecUtil.java
@@ -142,7 +142,7 @@ public final class MediaCodecUtil {
return decoderInfos.isEmpty() ? null : decoderInfos.get(0);
}
- /*
+ /**
* Returns all {@link MediaCodecInfo}s for the given mime type, in the order given by {@link
* MediaCodecList}.
*
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java
index 1b421de43b..0aef44fb6f 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DefaultMediaSourceFactory.java
@@ -365,15 +365,14 @@ public final class DefaultMediaSourceFactory implements MediaSourceFactory {
};
mediaSources[i + 1] =
new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)
+ .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
.createMediaSource(
MediaItem.fromUri(subtitleConfigurations.get(i).uri.toString()));
} else {
- SingleSampleMediaSource.Factory singleSampleSourceFactory =
- new SingleSampleMediaSource.Factory(dataSourceFactory)
- .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy);
mediaSources[i + 1] =
- singleSampleSourceFactory.createMediaSource(
- subtitleConfigurations.get(i), /* durationUs= */ C.TIME_UNSET);
+ new SingleSampleMediaSource.Factory(dataSourceFactory)
+ .setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
+ .createMediaSource(subtitleConfigurations.get(i), /* durationUs= */ C.TIME_UNSET);
}
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleDataQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleDataQueue.java
index 5cf5660b02..00b1943533 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleDataQueue.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleDataQueue.java
@@ -66,7 +66,7 @@ import java.util.Arrays;
/** Clears all sample data. */
public void reset() {
clearAllocationNodes(firstAllocationNode);
- firstAllocationNode = new AllocationNode(0, allocationLength);
+ firstAllocationNode.reset(/* startPosition= */ 0, allocationLength);
readAllocationNode = firstAllocationNode;
writeAllocationNode = firstAllocationNode;
totalBytesWritten = 0;
@@ -462,9 +462,9 @@ import java.util.Arrays;
private static final class AllocationNode implements Allocator.AllocationNode {
/** The absolute position of the start of the data (inclusive). */
- public final long startPosition;
+ public long startPosition;
/** The absolute position of the end of the data (exclusive). */
- public final long endPosition;
+ public long endPosition;
/**
* The {@link Allocation}, or {@code null} if the node is not {@link #initialize initialized}.
*/
@@ -481,6 +481,17 @@ import java.util.Arrays;
* initialized.
*/
public AllocationNode(long startPosition, int allocationLength) {
+ reset(startPosition, allocationLength);
+ }
+
+ /**
+ * Sets the {@link #startPosition} and the {@link Allocation} length.
+ *
+ *
Must only be called for uninitialized instances, where {@link #allocation} is {@code
+ * null}.
+ */
+ public void reset(long startPosition, int allocationLength) {
+ Assertions.checkState(allocation == null);
this.startPosition = startPosition;
this.endPosition = startPosition + allocationLength;
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSource.java
index c663b1aa3d..7d5ddd2c55 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSource.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSource.java
@@ -991,7 +991,6 @@ public final class ServerSideAdInsertionMediaSource extends BaseMediaSource
public ServerSideAdInsertionTimeline(
Timeline contentTimeline, ImmutableMap adPlaybackStates) {
super(contentTimeline);
- checkState(contentTimeline.getPeriodCount() == 1);
checkState(contentTimeline.getWindowCount() == 1);
Period period = new Period();
for (int i = 0; i < contentTimeline.getPeriodCount(); i++) {
@@ -1005,25 +1004,23 @@ public final class ServerSideAdInsertionMediaSource extends BaseMediaSource
public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) {
super.getWindow(windowIndex, window, defaultPositionProjectionUs);
Object firstPeriodUid =
- checkNotNull(getPeriod(/* periodIndex= */ 0, new Period(), /* setIds= */ true).uid);
- AdPlaybackState adPlaybackState = checkNotNull(adPlaybackStates.get(firstPeriodUid));
+ checkNotNull(getPeriod(window.firstPeriodIndex, new Period(), /* setIds= */ true).uid);
+ AdPlaybackState firstAdPlaybackState = checkNotNull(adPlaybackStates.get(firstPeriodUid));
long positionInPeriodUs =
getMediaPeriodPositionUsForContent(
window.positionInFirstPeriodUs,
/* nextAdGroupIndex= */ C.INDEX_UNSET,
- adPlaybackState);
+ firstAdPlaybackState);
if (window.durationUs == C.TIME_UNSET) {
- if (adPlaybackState.contentDurationUs != C.TIME_UNSET) {
- window.durationUs = adPlaybackState.contentDurationUs - positionInPeriodUs;
+ if (firstAdPlaybackState.contentDurationUs != C.TIME_UNSET) {
+ window.durationUs = firstAdPlaybackState.contentDurationUs - positionInPeriodUs;
}
} else {
- long actualWindowEndPositionInPeriodUs = window.positionInFirstPeriodUs + window.durationUs;
- long windowEndPositionInPeriodUs =
- getMediaPeriodPositionUsForContent(
- actualWindowEndPositionInPeriodUs,
- /* nextAdGroupIndex= */ C.INDEX_UNSET,
- adPlaybackState);
- window.durationUs = windowEndPositionInPeriodUs - positionInPeriodUs;
+ Period lastPeriod = getPeriod(/* periodIndex= */ window.lastPeriodIndex, new Period());
+ window.durationUs =
+ lastPeriod.durationUs == C.TIME_UNSET
+ ? C.TIME_UNSET
+ : lastPeriod.positionInWindowUs + lastPeriod.durationUs;
}
window.positionInFirstPeriodUs = positionInPeriodUs;
return window;
@@ -1041,11 +1038,26 @@ public final class ServerSideAdInsertionMediaSource extends BaseMediaSource
getMediaPeriodPositionUsForContent(
durationUs, /* nextAdGroupIndex= */ C.INDEX_UNSET, adPlaybackState);
}
- long positionInWindowUs =
- -getMediaPeriodPositionUsForContent(
- -period.getPositionInWindowUs(),
- /* nextAdGroupIndex= */ C.INDEX_UNSET,
- adPlaybackState);
+ long positionInWindowUs = 0;
+ Period innerPeriod = new Period();
+ for (int i = 0; i < periodIndex + 1; i++) {
+ timeline.getPeriod(/* periodIndex= */ i, innerPeriod, /* setIds= */ true);
+ AdPlaybackState innerAdPlaybackState = checkNotNull(adPlaybackStates.get(innerPeriod.uid));
+ if (i == 0) {
+ positionInWindowUs =
+ -getMediaPeriodPositionUsForContent(
+ -innerPeriod.getPositionInWindowUs(),
+ /* nextAdGroupIndex= */ C.INDEX_UNSET,
+ innerAdPlaybackState);
+ }
+ if (i != periodIndex) {
+ positionInWindowUs +=
+ getMediaPeriodPositionUsForContent(
+ innerPeriod.durationUs,
+ /* nextAdGroupIndex= */ C.INDEX_UNSET,
+ innerAdPlaybackState);
+ }
+ }
period.set(
period.id,
period.uid,
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtil.java
index d7609848af..06aa3ef87b 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtil.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtil.java
@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source.ads;
+import static com.google.android.exoplayer2.util.Util.sum;
import static java.lang.Math.max;
import androidx.annotation.CheckResult;
@@ -33,23 +34,25 @@ public final class ServerSideAdInsertionUtil {
/**
* Adds a new server-side inserted ad group to an {@link AdPlaybackState}.
*
+ * If the first ad with a non-zero duration is not the first ad in the group, all ads before
+ * that ad are marked as skipped.
+ *
* @param adPlaybackState The existing {@link AdPlaybackState}.
* @param fromPositionUs The position in the underlying server-side inserted ads stream at which
* the ad group starts, in microseconds.
- * @param toPositionUs The position in the underlying server-side inserted ads stream at which the
- * ad group ends, in microseconds.
* @param contentResumeOffsetUs The timestamp offset which should be added to the content stream
* when resuming playback after the ad group. An offset of 0 collapses the ad group to a
* single insertion point, an offset of {@code toPositionUs-fromPositionUs} keeps the original
* stream timestamps after the ad group.
+ * @param adDurationsUs The durations of the ads to be added to the group, in microseconds.
* @return The updated {@link AdPlaybackState}.
*/
@CheckResult
public static AdPlaybackState addAdGroupToAdPlaybackState(
AdPlaybackState adPlaybackState,
long fromPositionUs,
- long toPositionUs,
- long contentResumeOffsetUs) {
+ long contentResumeOffsetUs,
+ long... adDurationsUs) {
long adGroupInsertionPositionUs =
getMediaPeriodPositionUsForContent(
fromPositionUs, /* nextAdGroupIndex= */ C.INDEX_UNSET, adPlaybackState);
@@ -59,39 +62,21 @@ public final class ServerSideAdInsertionUtil {
&& adPlaybackState.getAdGroup(insertionIndex).timeUs <= adGroupInsertionPositionUs) {
insertionIndex++;
}
- long adDurationUs = toPositionUs - fromPositionUs;
adPlaybackState =
adPlaybackState
.withNewAdGroup(insertionIndex, adGroupInsertionPositionUs)
.withIsServerSideInserted(insertionIndex, /* isServerSideInserted= */ true)
- .withAdCount(insertionIndex, /* adCount= */ 1)
- .withAdDurationsUs(insertionIndex, adDurationUs)
+ .withAdCount(insertionIndex, /* adCount= */ adDurationsUs.length)
+ .withAdDurationsUs(insertionIndex, adDurationsUs)
.withContentResumeOffsetUs(insertionIndex, contentResumeOffsetUs);
+ // Mark all ads as skipped that are before the first ad with a non-zero duration.
+ int adIndex = 0;
+ while (adIndex < adDurationsUs.length && adDurationsUs[adIndex] == 0) {
+ adPlaybackState =
+ adPlaybackState.withSkippedAd(insertionIndex, /* adIndexInAdGroup= */ adIndex++);
+ }
return correctFollowingAdGroupTimes(
- adPlaybackState, insertionIndex, adDurationUs, contentResumeOffsetUs);
- }
-
- /**
- * Returns the duration of the underlying server-side inserted ads stream for the current {@link
- * Timeline.Period} in the {@link Player}.
- *
- * @param player The {@link Player}.
- * @param adPlaybackState The {@link AdPlaybackState} defining the ad groups.
- * @return The duration of the underlying server-side inserted ads stream, in microseconds, or
- * {@link C#TIME_UNSET} if it can't be determined.
- */
- public static long getStreamDurationUs(Player player, AdPlaybackState adPlaybackState) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty()) {
- return C.TIME_UNSET;
- }
- Timeline.Period period =
- timeline.getPeriod(player.getCurrentPeriodIndex(), new Timeline.Period());
- if (period.durationUs == C.TIME_UNSET) {
- return C.TIME_UNSET;
- }
- return getStreamPositionUsForContent(
- period.durationUs, /* nextAdGroupIndex= */ C.INDEX_UNSET, adPlaybackState);
+ adPlaybackState, insertionIndex, sum(adDurationsUs), contentResumeOffsetUs);
}
/**
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java
index 21e05f33bb..f10f0b765a 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java
@@ -15,6 +15,9 @@
*/
package com.google.android.exoplayer2.trackselection;
+import static java.util.Collections.max;
+
+import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Point;
import android.os.Bundle;
@@ -42,6 +45,7 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.BundleableUtil;
+import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
@@ -52,8 +56,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -104,11 +108,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private boolean exceedVideoConstraintsIfNecessary;
private boolean allowVideoMixedMimeTypeAdaptiveness;
private boolean allowVideoNonSeamlessAdaptiveness;
+ private boolean allowVideoMixedDecoderSupportAdaptiveness;
// Audio
private boolean exceedAudioConstraintsIfNecessary;
private boolean allowAudioMixedMimeTypeAdaptiveness;
private boolean allowAudioMixedSampleRateAdaptiveness;
private boolean allowAudioMixedChannelCountAdaptiveness;
+ private boolean allowAudioMixedDecoderSupportAdaptiveness;
// Text
@C.SelectionFlags private int disabledTextTrackSelectionFlags;
// General
@@ -157,12 +163,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
exceedVideoConstraintsIfNecessary = initialValues.exceedVideoConstraintsIfNecessary;
allowVideoMixedMimeTypeAdaptiveness = initialValues.allowVideoMixedMimeTypeAdaptiveness;
allowVideoNonSeamlessAdaptiveness = initialValues.allowVideoNonSeamlessAdaptiveness;
+ allowVideoMixedDecoderSupportAdaptiveness =
+ initialValues.allowVideoMixedDecoderSupportAdaptiveness;
// Audio
exceedAudioConstraintsIfNecessary = initialValues.exceedAudioConstraintsIfNecessary;
allowAudioMixedMimeTypeAdaptiveness = initialValues.allowAudioMixedMimeTypeAdaptiveness;
allowAudioMixedSampleRateAdaptiveness = initialValues.allowAudioMixedSampleRateAdaptiveness;
allowAudioMixedChannelCountAdaptiveness =
initialValues.allowAudioMixedChannelCountAdaptiveness;
+ allowAudioMixedDecoderSupportAdaptiveness =
+ initialValues.allowAudioMixedDecoderSupportAdaptiveness;
// General
exceedRendererCapabilitiesIfNecessary = initialValues.exceedRendererCapabilitiesIfNecessary;
tunnelingEnabled = initialValues.tunnelingEnabled;
@@ -189,6 +199,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
bundle.getBoolean(
Parameters.keyForField(Parameters.FIELD_ALLOW_VIDEO_NON_SEAMLESS_ADAPTIVENESS),
defaultValue.allowVideoNonSeamlessAdaptiveness));
+ setAllowVideoMixedDecoderSupportAdaptiveness(
+ bundle.getBoolean(
+ Parameters.keyForField(
+ Parameters.FIELD_ALLOW_VIDEO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
+ defaultValue.allowVideoMixedDecoderSupportAdaptiveness));
// Audio
setExceedAudioConstraintsIfNecessary(
bundle.getBoolean(
@@ -206,6 +221,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
bundle.getBoolean(
Parameters.keyForField(Parameters.FIELD_ALLOW_AUDIO_MIXED_CHANNEL_COUNT_ADAPTIVENESS),
defaultValue.allowAudioMixedChannelCountAdaptiveness));
+ setAllowAudioMixedDecoderSupportAdaptiveness(
+ bundle.getBoolean(
+ Parameters.keyForField(
+ Parameters.FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
+ defaultValue.allowAudioMixedDecoderSupportAdaptiveness));
// Text
setDisabledTextTrackSelectionFlags(
bundle.getInt(
@@ -337,6 +357,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this;
}
+ /**
+ * Sets whether to allow adaptive video selections with mixed levels of {@link
+ * RendererCapabilities.DecoderSupport} and {@link
+ * RendererCapabilities.HardwareAccelerationSupport}.
+ *
+ * @param allowVideoMixedDecoderSupportAdaptiveness Whether to allow adaptive video selections
+ * with mixed levels of decoder and hardware acceleration support.
+ * @return This builder.
+ */
+ public ParametersBuilder setAllowVideoMixedDecoderSupportAdaptiveness(
+ boolean allowVideoMixedDecoderSupportAdaptiveness) {
+ this.allowVideoMixedDecoderSupportAdaptiveness = allowVideoMixedDecoderSupportAdaptiveness;
+ return this;
+ }
+
@Override
public ParametersBuilder setViewportSizeToPhysicalDisplaySize(
Context context, boolean viewportOrientationMayChange) {
@@ -467,6 +502,21 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return this;
}
+ /**
+ * Sets whether to allow adaptive audio selections with mixed levels of {@link
+ * RendererCapabilities.DecoderSupport} and {@link
+ * RendererCapabilities.HardwareAccelerationSupport}.
+ *
+ * @param allowAudioMixedDecoderSupportAdaptiveness Whether to allow adaptive audio selections
+ * with mixed levels of decoder and hardware acceleration support.
+ * @return This builder.
+ */
+ public ParametersBuilder setAllowAudioMixedDecoderSupportAdaptiveness(
+ boolean allowAudioMixedDecoderSupportAdaptiveness) {
+ this.allowAudioMixedDecoderSupportAdaptiveness = allowAudioMixedDecoderSupportAdaptiveness;
+ return this;
+ }
+
@Override
public ParametersBuilder setPreferredAudioMimeType(@Nullable String mimeType) {
super.setPreferredAudioMimeType(mimeType);
@@ -737,11 +787,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
exceedVideoConstraintsIfNecessary = true;
allowVideoMixedMimeTypeAdaptiveness = false;
allowVideoNonSeamlessAdaptiveness = true;
+ allowVideoMixedDecoderSupportAdaptiveness = false;
// Audio
exceedAudioConstraintsIfNecessary = true;
allowAudioMixedMimeTypeAdaptiveness = false;
allowAudioMixedSampleRateAdaptiveness = false;
allowAudioMixedChannelCountAdaptiveness = false;
+ allowAudioMixedDecoderSupportAdaptiveness = false;
// Text
disabledTextTrackSelectionFlags = 0;
// General
@@ -861,6 +913,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* The default value is {@code true}.
*/
public final boolean allowVideoNonSeamlessAdaptiveness;
+ /**
+ * Whether to allow adaptive video selections with mixed levels of {@link
+ * RendererCapabilities.DecoderSupport} and {@link
+ * RendererCapabilities.HardwareAccelerationSupport}.
+ */
+ public final boolean allowVideoMixedDecoderSupportAdaptiveness;
/**
* Whether to exceed the {@link #maxAudioChannelCount} and {@link #maxAudioBitrate} constraints
* when no selection can be made otherwise. The default value is {@code true}.
@@ -882,6 +940,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* false}.
*/
public final boolean allowAudioMixedChannelCountAdaptiveness;
+ /**
+ * Whether to allow adaptive audio selections with mixed levels of {@link
+ * RendererCapabilities.DecoderSupport} and {@link
+ * RendererCapabilities.HardwareAccelerationSupport}.
+ */
+ public final boolean allowAudioMixedDecoderSupportAdaptiveness;
/**
* Whether to exceed renderer capabilities when no selection can be made otherwise.
*
@@ -915,11 +979,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
exceedVideoConstraintsIfNecessary = builder.exceedVideoConstraintsIfNecessary;
allowVideoMixedMimeTypeAdaptiveness = builder.allowVideoMixedMimeTypeAdaptiveness;
allowVideoNonSeamlessAdaptiveness = builder.allowVideoNonSeamlessAdaptiveness;
+ allowVideoMixedDecoderSupportAdaptiveness = builder.allowVideoMixedDecoderSupportAdaptiveness;
// Audio
exceedAudioConstraintsIfNecessary = builder.exceedAudioConstraintsIfNecessary;
allowAudioMixedMimeTypeAdaptiveness = builder.allowAudioMixedMimeTypeAdaptiveness;
allowAudioMixedSampleRateAdaptiveness = builder.allowAudioMixedSampleRateAdaptiveness;
allowAudioMixedChannelCountAdaptiveness = builder.allowAudioMixedChannelCountAdaptiveness;
+ allowAudioMixedDecoderSupportAdaptiveness = builder.allowAudioMixedDecoderSupportAdaptiveness;
// Text
disabledTextTrackSelectionFlags = builder.disabledTextTrackSelectionFlags;
// General
@@ -997,12 +1063,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& exceedVideoConstraintsIfNecessary == other.exceedVideoConstraintsIfNecessary
&& allowVideoMixedMimeTypeAdaptiveness == other.allowVideoMixedMimeTypeAdaptiveness
&& allowVideoNonSeamlessAdaptiveness == other.allowVideoNonSeamlessAdaptiveness
+ && allowVideoMixedDecoderSupportAdaptiveness
+ == other.allowVideoMixedDecoderSupportAdaptiveness
// Audio
&& exceedAudioConstraintsIfNecessary == other.exceedAudioConstraintsIfNecessary
&& allowAudioMixedMimeTypeAdaptiveness == other.allowAudioMixedMimeTypeAdaptiveness
&& allowAudioMixedSampleRateAdaptiveness == other.allowAudioMixedSampleRateAdaptiveness
&& allowAudioMixedChannelCountAdaptiveness
== other.allowAudioMixedChannelCountAdaptiveness
+ && allowAudioMixedDecoderSupportAdaptiveness
+ == other.allowAudioMixedDecoderSupportAdaptiveness
// Text
&& disabledTextTrackSelectionFlags == other.disabledTextTrackSelectionFlags
// General
@@ -1022,11 +1092,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + (exceedVideoConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (allowVideoMixedMimeTypeAdaptiveness ? 1 : 0);
result = 31 * result + (allowVideoNonSeamlessAdaptiveness ? 1 : 0);
+ result = 31 * result + (allowVideoMixedDecoderSupportAdaptiveness ? 1 : 0);
// Audio
result = 31 * result + (exceedAudioConstraintsIfNecessary ? 1 : 0);
result = 31 * result + (allowAudioMixedMimeTypeAdaptiveness ? 1 : 0);
result = 31 * result + (allowAudioMixedSampleRateAdaptiveness ? 1 : 0);
result = 31 * result + (allowAudioMixedChannelCountAdaptiveness ? 1 : 0);
+ result = 31 * result + (allowAudioMixedDecoderSupportAdaptiveness ? 1 : 0);
// Text
result = 31 * result + disabledTextTrackSelectionFlags;
// General
@@ -1057,6 +1129,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
FIELD_SELECTION_OVERRIDES_TRACK_GROUP_ARRAYS,
FIELD_SELECTION_OVERRIDES,
FIELD_RENDERER_DISABLED_INDICES,
+ FIELD_ALLOW_VIDEO_MIXED_DECODER_SUPPORT_ADAPTIVENESS,
+ FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS
})
private @interface FieldNumber {}
@@ -1076,6 +1150,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static final int FIELD_SELECTION_OVERRIDES_TRACK_GROUP_ARRAYS = 1012;
private static final int FIELD_SELECTION_OVERRIDES = 1013;
private static final int FIELD_RENDERER_DISABLED_INDICES = 1014;
+ private static final int FIELD_ALLOW_VIDEO_MIXED_DECODER_SUPPORT_ADAPTIVENESS = 1015;
+ private static final int FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS = 1016;
@Override
public Bundle toBundle() {
@@ -1091,6 +1167,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
bundle.putBoolean(
keyForField(FIELD_ALLOW_VIDEO_NON_SEAMLESS_ADAPTIVENESS),
allowVideoNonSeamlessAdaptiveness);
+ bundle.putBoolean(
+ keyForField(FIELD_ALLOW_VIDEO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
+ allowVideoMixedDecoderSupportAdaptiveness);
// Audio
bundle.putBoolean(
keyForField(FIELD_EXCEED_AUDIO_CONSTRAINTS_IF_NCESSARY),
@@ -1104,6 +1183,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
bundle.putBoolean(
keyForField(FIELD_ALLOW_AUDIO_MIXED_CHANNEL_COUNT_ADAPTIVENESS),
allowAudioMixedChannelCountAdaptiveness);
+ bundle.putBoolean(
+ keyForField(FIELD_ALLOW_AUDIO_MIXED_DECODER_SUPPORT_ADAPTIVENESS),
+ allowAudioMixedDecoderSupportAdaptiveness);
// Text
bundle.putInt(
keyForField(FIELD_DISABLED_TEXT_TRACK_SELECTION_FLAGS), disabledTextTrackSelectionFlags);
@@ -1327,6 +1409,26 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
}
+ /**
+ * The extent to which tracks are eligible for selection. One of {@link
+ * #SELECTION_ELIGIBILITY_NO}, {@link #SELECTION_ELIGIBILITY_FIXED} or {@link
+ * #SELECTION_ELIGIBILITY_ADAPTIVE}.
+ */
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SELECTION_ELIGIBILITY_NO, SELECTION_ELIGIBILITY_FIXED, SELECTION_ELIGIBILITY_ADAPTIVE})
+ protected @interface SelectionEligibility {}
+
+ /** Track is not eligible for selection. */
+ protected static final int SELECTION_ELIGIBILITY_NO = 0;
+ /** Track is eligible for a fixed selection with one track. */
+ protected static final int SELECTION_ELIGIBILITY_FIXED = 1;
+ /**
+ * Track is eligible for both a fixed selection and as part of an adaptive selection with multiple
+ * tracks.
+ */
+ protected static final int SELECTION_ELIGIBILITY_ADAPTIVE = 2;
+
/**
* If a dimension (i.e. width or height) of a video is greater or equal to this fraction of the
* corresponding viewport dimension, then the video is considered as filling the viewport (in that
@@ -1334,7 +1436,6 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/
private static final float FRACTION_TO_CONSIDER_FULLSCREEN = 0.98f;
- private static final int[] NO_TRACKS = new int[0];
/** Ordering of two format values. A known value is considered greater than Format#NO_VALUE. */
private static final Ordering FORMAT_VALUE_ORDERING =
Ordering.from(
@@ -1626,92 +1727,48 @@ public class DefaultTrackSelector extends MappingTrackSelector {
ExoTrackSelection.@NullableType Definition[] definitions =
new ExoTrackSelection.Definition[rendererCount];
- boolean seenVideoRendererWithMappedTracks = false;
- boolean selectedVideoTracks = false;
- for (int i = 0; i < rendererCount; i++) {
- if (C.TRACK_TYPE_VIDEO == mappedTrackInfo.getRendererType(i)) {
- if (!selectedVideoTracks) {
- definitions[i] =
- selectVideoTrack(
- mappedTrackInfo.getTrackGroups(i),
- rendererFormatSupports[i],
- rendererMixedMimeTypeAdaptationSupports[i],
- params,
- /* enableAdaptiveTrackSelection= */ true);
- selectedVideoTracks = definitions[i] != null;
- }
- seenVideoRendererWithMappedTracks |= mappedTrackInfo.getTrackGroups(i).length > 0;
- }
+ @Nullable
+ Pair selectedVideo =
+ selectVideoTrack(
+ mappedTrackInfo,
+ rendererFormatSupports,
+ rendererMixedMimeTypeAdaptationSupports,
+ params);
+ if (selectedVideo != null) {
+ definitions[selectedVideo.second] = selectedVideo.first;
}
- @Nullable AudioTrackScore selectedAudioTrackScore = null;
- @Nullable String selectedAudioLanguage = null;
- int selectedAudioRendererIndex = C.INDEX_UNSET;
- for (int i = 0; i < rendererCount; i++) {
- if (C.TRACK_TYPE_AUDIO == mappedTrackInfo.getRendererType(i)) {
- boolean enableAdaptiveTrackSelection =
- params.allowMultipleAdaptiveSelections || !seenVideoRendererWithMappedTracks;
- @Nullable
- Pair audioSelection =
- selectAudioTrack(
- mappedTrackInfo.getTrackGroups(i),
- rendererFormatSupports[i],
- rendererMixedMimeTypeAdaptationSupports[i],
- params,
- enableAdaptiveTrackSelection);
- if (audioSelection != null
- && (selectedAudioTrackScore == null
- || audioSelection.second.compareTo(selectedAudioTrackScore) > 0)) {
- if (selectedAudioRendererIndex != C.INDEX_UNSET) {
- // We've already made a selection for another audio renderer, but it had a lower
- // score. Clear the selection for that renderer.
- definitions[selectedAudioRendererIndex] = null;
- }
- ExoTrackSelection.Definition definition = audioSelection.first;
- definitions[i] = definition;
- // We assume that audio tracks in the same group have matching language.
- selectedAudioLanguage = definition.group.getFormat(definition.tracks[0]).language;
- selectedAudioTrackScore = audioSelection.second;
- selectedAudioRendererIndex = i;
- }
- }
+ @Nullable
+ Pair selectedAudio =
+ selectAudioTrack(
+ mappedTrackInfo,
+ rendererFormatSupports,
+ rendererMixedMimeTypeAdaptationSupports,
+ params);
+ if (selectedAudio != null) {
+ definitions[selectedAudio.second] = selectedAudio.first;
+ }
+
+ @Nullable
+ String selectedAudioLanguage =
+ selectedAudio == null
+ ? null
+ : selectedAudio.first.group.getFormat(selectedAudio.first.tracks[0]).language;
+ @Nullable
+ Pair selectedText =
+ selectTextTrack(mappedTrackInfo, rendererFormatSupports, params, selectedAudioLanguage);
+ if (selectedText != null) {
+ definitions[selectedText.second] = selectedText.first;
}
- @Nullable TextTrackScore selectedTextTrackScore = null;
- int selectedTextRendererIndex = C.INDEX_UNSET;
for (int i = 0; i < rendererCount; i++) {
int trackType = mappedTrackInfo.getRendererType(i);
- switch (trackType) {
- case C.TRACK_TYPE_VIDEO:
- case C.TRACK_TYPE_AUDIO:
- // Already done. Do nothing.
- break;
- case C.TRACK_TYPE_TEXT:
- @Nullable
- Pair textSelection =
- selectTextTrack(
- mappedTrackInfo.getTrackGroups(i),
- rendererFormatSupports[i],
- params,
- selectedAudioLanguage);
- if (textSelection != null
- && (selectedTextTrackScore == null
- || textSelection.second.compareTo(selectedTextTrackScore) > 0)) {
- if (selectedTextRendererIndex != C.INDEX_UNSET) {
- // We've already made a selection for another text renderer, but it had a lower score.
- // Clear the selection for that renderer.
- definitions[selectedTextRendererIndex] = null;
- }
- definitions[i] = textSelection.first;
- selectedTextTrackScore = textSelection.second;
- selectedTextRendererIndex = i;
- }
- break;
- default:
- definitions[i] =
- selectOtherTrack(
- trackType, mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params);
- break;
+ if (trackType != C.TRACK_TYPE_VIDEO
+ && trackType != C.TRACK_TYPE_AUDIO
+ && trackType != C.TRACK_TYPE_TEXT) {
+ definitions[i] =
+ selectOtherTrack(
+ trackType, mappedTrackInfo.getTrackGroups(i), rendererFormatSupports[i], params);
}
}
@@ -1722,490 +1779,114 @@ public class DefaultTrackSelector extends MappingTrackSelector {
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
- * {@link ExoTrackSelection} for a video renderer.
+ * {@link ExoTrackSelection.Definition} for a video track selection.
*
- * @param groups The {@link TrackGroupArray} mapped to the renderer.
- * @param formatSupport The {@link Capabilities} for each mapped track, indexed by track group and
- * track (in that order).
- * @param mixedMimeTypeAdaptationSupports The {@link AdaptiveSupport} for mixed MIME type
- * adaptation for the renderer.
+ * @param mappedTrackInfo Mapped track information.
+ * @param rendererFormatSupports The {@link Capabilities} for each mapped track, indexed by
+ * renderer, track group and track (in that order).
+ * @param mixedMimeTypeSupports The {@link AdaptiveSupport} for mixed MIME type adaptation for the
+ * renderer.
* @param params The selector's current constraint parameters.
- * @param enableAdaptiveTrackSelection Whether adaptive track selection is allowed.
- * @return The {@link ExoTrackSelection.Definition} for the renderer, or null if no selection was
- * made.
+ * @return A pair of the selected {@link ExoTrackSelection.Definition} and the corresponding
+ * renderer index, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
+ @SuppressLint("WrongConstant") // Lint doesn't understand arrays of IntDefs.
@Nullable
- protected ExoTrackSelection.Definition selectVideoTrack(
- TrackGroupArray groups,
- @Capabilities int[][] formatSupport,
- @AdaptiveSupport int mixedMimeTypeAdaptationSupports,
- Parameters params,
- boolean enableAdaptiveTrackSelection)
+ protected Pair selectVideoTrack(
+ MappedTrackInfo mappedTrackInfo,
+ @Capabilities int[][][] rendererFormatSupports,
+ @AdaptiveSupport int[] mixedMimeTypeSupports,
+ Parameters params)
throws ExoPlaybackException {
- ExoTrackSelection.Definition definition = null;
- if (!params.forceHighestSupportedBitrate
- && !params.forceLowestBitrate
- && enableAdaptiveTrackSelection) {
- definition =
- selectAdaptiveVideoTrack(groups, formatSupport, mixedMimeTypeAdaptationSupports, params);
- }
- if (definition == null) {
- definition = selectFixedVideoTrack(groups, formatSupport, params);
- }
- return definition;
- }
-
- @Nullable
- private static ExoTrackSelection.Definition selectAdaptiveVideoTrack(
- TrackGroupArray groups,
- @Capabilities int[][] formatSupport,
- @AdaptiveSupport int mixedMimeTypeAdaptationSupports,
- Parameters params) {
- int requiredAdaptiveSupport =
- params.allowVideoNonSeamlessAdaptiveness
- ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS)
- : RendererCapabilities.ADAPTIVE_SEAMLESS;
- boolean allowMixedMimeTypes =
- params.allowVideoMixedMimeTypeAdaptiveness
- && (mixedMimeTypeAdaptationSupports & requiredAdaptiveSupport) != 0;
- for (int i = 0; i < groups.length; i++) {
- TrackGroup group = groups.get(i);
- int[] adaptiveTracks =
- getAdaptiveVideoTracksForGroup(
- group,
- formatSupport[i],
- allowMixedMimeTypes,
- requiredAdaptiveSupport,
- params.maxVideoWidth,
- params.maxVideoHeight,
- params.maxVideoFrameRate,
- params.maxVideoBitrate,
- params.minVideoWidth,
- params.minVideoHeight,
- params.minVideoFrameRate,
- params.minVideoBitrate,
- params.viewportWidth,
- params.viewportHeight,
- params.viewportOrientationMayChange);
- if (adaptiveTracks.length > 0) {
- return new ExoTrackSelection.Definition(group, adaptiveTracks);
- }
- }
- return null;
- }
-
- private static int[] getAdaptiveVideoTracksForGroup(
- TrackGroup group,
- @Capabilities int[] formatSupport,
- boolean allowMixedMimeTypes,
- int requiredAdaptiveSupport,
- int maxVideoWidth,
- int maxVideoHeight,
- int maxVideoFrameRate,
- int maxVideoBitrate,
- int minVideoWidth,
- int minVideoHeight,
- int minVideoFrameRate,
- int minVideoBitrate,
- int viewportWidth,
- int viewportHeight,
- boolean viewportOrientationMayChange) {
- if (group.length < 2) {
- return NO_TRACKS;
- }
-
- List selectedTrackIndices =
- getViewportFilteredTrackIndices(
- group, viewportWidth, viewportHeight, viewportOrientationMayChange);
- if (selectedTrackIndices.size() < 2) {
- return NO_TRACKS;
- }
-
- String selectedMimeType = null;
- if (!allowMixedMimeTypes) {
- // Select the mime type for which we have the most adaptive tracks.
- HashSet<@NullableType String> seenMimeTypes = new HashSet<>();
- int selectedMimeTypeTrackCount = 0;
- for (int i = 0; i < selectedTrackIndices.size(); i++) {
- int trackIndex = selectedTrackIndices.get(i);
- String sampleMimeType = group.getFormat(trackIndex).sampleMimeType;
- if (seenMimeTypes.add(sampleMimeType)) {
- int countForMimeType =
- getAdaptiveVideoTrackCountForMimeType(
- group,
- formatSupport,
- requiredAdaptiveSupport,
- sampleMimeType,
- maxVideoWidth,
- maxVideoHeight,
- maxVideoFrameRate,
- maxVideoBitrate,
- minVideoWidth,
- minVideoHeight,
- minVideoFrameRate,
- minVideoBitrate,
- selectedTrackIndices);
- if (countForMimeType > selectedMimeTypeTrackCount) {
- selectedMimeType = sampleMimeType;
- selectedMimeTypeTrackCount = countForMimeType;
- }
- }
- }
- }
-
- // Filter by the selected mime type.
- filterAdaptiveVideoTrackCountForMimeType(
- group,
- formatSupport,
- requiredAdaptiveSupport,
- selectedMimeType,
- maxVideoWidth,
- maxVideoHeight,
- maxVideoFrameRate,
- maxVideoBitrate,
- minVideoWidth,
- minVideoHeight,
- minVideoFrameRate,
- minVideoBitrate,
- selectedTrackIndices);
-
- return selectedTrackIndices.size() < 2 ? NO_TRACKS : Ints.toArray(selectedTrackIndices);
- }
-
- private static int getAdaptiveVideoTrackCountForMimeType(
- TrackGroup group,
- @Capabilities int[] formatSupport,
- int requiredAdaptiveSupport,
- @Nullable String mimeType,
- int maxVideoWidth,
- int maxVideoHeight,
- int maxVideoFrameRate,
- int maxVideoBitrate,
- int minVideoWidth,
- int minVideoHeight,
- int minVideoFrameRate,
- int minVideoBitrate,
- List selectedTrackIndices) {
- int adaptiveTrackCount = 0;
- for (int i = 0; i < selectedTrackIndices.size(); i++) {
- int trackIndex = selectedTrackIndices.get(i);
- if (isSupportedAdaptiveVideoTrack(
- group.getFormat(trackIndex),
- mimeType,
- formatSupport[trackIndex],
- requiredAdaptiveSupport,
- maxVideoWidth,
- maxVideoHeight,
- maxVideoFrameRate,
- maxVideoBitrate,
- minVideoWidth,
- minVideoHeight,
- minVideoFrameRate,
- minVideoBitrate)) {
- adaptiveTrackCount++;
- }
- }
- return adaptiveTrackCount;
- }
-
- private static void filterAdaptiveVideoTrackCountForMimeType(
- TrackGroup group,
- @Capabilities int[] formatSupport,
- int requiredAdaptiveSupport,
- @Nullable String mimeType,
- int maxVideoWidth,
- int maxVideoHeight,
- int maxVideoFrameRate,
- int maxVideoBitrate,
- int minVideoWidth,
- int minVideoHeight,
- int minVideoFrameRate,
- int minVideoBitrate,
- List selectedTrackIndices) {
- for (int i = selectedTrackIndices.size() - 1; i >= 0; i--) {
- int trackIndex = selectedTrackIndices.get(i);
- if (!isSupportedAdaptiveVideoTrack(
- group.getFormat(trackIndex),
- mimeType,
- formatSupport[trackIndex],
- requiredAdaptiveSupport,
- maxVideoWidth,
- maxVideoHeight,
- maxVideoFrameRate,
- maxVideoBitrate,
- minVideoWidth,
- minVideoHeight,
- minVideoFrameRate,
- minVideoBitrate)) {
- selectedTrackIndices.remove(i);
- }
- }
- }
-
- private static boolean isSupportedAdaptiveVideoTrack(
- Format format,
- @Nullable String mimeType,
- @Capabilities int formatSupport,
- int requiredAdaptiveSupport,
- int maxVideoWidth,
- int maxVideoHeight,
- int maxVideoFrameRate,
- int maxVideoBitrate,
- int minVideoWidth,
- int minVideoHeight,
- int minVideoFrameRate,
- int minVideoBitrate) {
- if ((format.roleFlags & C.ROLE_FLAG_TRICK_PLAY) != 0) {
- // Ignore trick-play tracks for now.
- return false;
- }
- return isSupported(formatSupport, /* allowExceedsCapabilities= */ false)
- && ((formatSupport & requiredAdaptiveSupport) != 0)
- && (mimeType == null || Util.areEqual(format.sampleMimeType, mimeType))
- && (format.width == Format.NO_VALUE
- || (minVideoWidth <= format.width && format.width <= maxVideoWidth))
- && (format.height == Format.NO_VALUE
- || (minVideoHeight <= format.height && format.height <= maxVideoHeight))
- && (format.frameRate == Format.NO_VALUE
- || (minVideoFrameRate <= format.frameRate && format.frameRate <= maxVideoFrameRate))
- && format.bitrate != Format.NO_VALUE
- && minVideoBitrate <= format.bitrate
- && format.bitrate <= maxVideoBitrate;
- }
-
- @Nullable
- private static ExoTrackSelection.Definition selectFixedVideoTrack(
- TrackGroupArray groups, @Capabilities int[][] formatSupport, Parameters params) {
- int selectedTrackIndex = C.INDEX_UNSET;
- @Nullable TrackGroup selectedGroup = null;
- @Nullable VideoTrackScore selectedTrackScore = null;
- for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
- TrackGroup trackGroup = groups.get(groupIndex);
- List viewportFilteredTrackIndices =
- getViewportFilteredTrackIndices(
- trackGroup,
- params.viewportWidth,
- params.viewportHeight,
- params.viewportOrientationMayChange);
- @Capabilities int[] trackFormatSupport = formatSupport[groupIndex];
- for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
- Format format = trackGroup.getFormat(trackIndex);
- if ((format.roleFlags & C.ROLE_FLAG_TRICK_PLAY) != 0) {
- // Ignore trick-play tracks for now.
- continue;
- }
- if (isSupported(
- trackFormatSupport[trackIndex], params.exceedRendererCapabilitiesIfNecessary)) {
- VideoTrackScore trackScore =
- new VideoTrackScore(
- format,
- params,
- trackFormatSupport[trackIndex],
- viewportFilteredTrackIndices.contains(trackIndex));
- if (!trackScore.isWithinMaxConstraints && !params.exceedVideoConstraintsIfNecessary) {
- // Track should not be selected.
- continue;
- }
- if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) {
- selectedGroup = trackGroup;
- selectedTrackIndex = trackIndex;
- selectedTrackScore = trackScore;
- }
- }
- }
- }
-
- return selectedGroup == null
- ? null
- : new ExoTrackSelection.Definition(selectedGroup, selectedTrackIndex);
+ return selectTracksForType(
+ C.TRACK_TYPE_VIDEO,
+ mappedTrackInfo,
+ rendererFormatSupports,
+ (rendererIndex, group, support) ->
+ VideoTrackInfo.createForTrackGroup(
+ rendererIndex, group, params, support, mixedMimeTypeSupports[rendererIndex]),
+ VideoTrackInfo::compareSelections);
}
// Audio track selection implementation.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
- * {@link ExoTrackSelection} for an audio renderer.
+ * {@link ExoTrackSelection.Definition} for an audio track selection.
*
- * @param groups The {@link TrackGroupArray} mapped to the renderer.
- * @param formatSupport The {@link Capabilities} for each mapped track, indexed by track group and
- * track (in that order).
- * @param mixedMimeTypeAdaptationSupports The {@link AdaptiveSupport} for mixed MIME type
+ * @param mappedTrackInfo Mapped track information.
+ * @param rendererFormatSupports The {@link Capabilities} for each mapped track, indexed by
+ * renderer, track group and track (in that order).
+ * @param rendererMixedMimeTypeAdaptationSupports The {@link AdaptiveSupport} for mixed MIME type
* adaptation for the renderer.
* @param params The selector's current constraint parameters.
- * @param enableAdaptiveTrackSelection Whether adaptive track selection is allowed.
- * @return The {@link ExoTrackSelection.Definition} and corresponding {@link AudioTrackScore}, or
- * null if no selection was made.
+ * @return A pair of the selected {@link ExoTrackSelection.Definition} and the corresponding
+ * renderer index, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
- @SuppressWarnings("unused")
+ @SuppressLint("WrongConstant") // Lint doesn't understand arrays of IntDefs.
@Nullable
- protected Pair selectAudioTrack(
- TrackGroupArray groups,
- @Capabilities int[][] formatSupport,
- @AdaptiveSupport int mixedMimeTypeAdaptationSupports,
- Parameters params,
- boolean enableAdaptiveTrackSelection)
+ protected Pair selectAudioTrack(
+ MappedTrackInfo mappedTrackInfo,
+ @Capabilities int[][][] rendererFormatSupports,
+ @AdaptiveSupport int[] rendererMixedMimeTypeAdaptationSupports,
+ Parameters params)
throws ExoPlaybackException {
- int selectedTrackIndex = C.INDEX_UNSET;
- int selectedGroupIndex = C.INDEX_UNSET;
- @Nullable AudioTrackScore selectedTrackScore = null;
- for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
- TrackGroup trackGroup = groups.get(groupIndex);
- @Capabilities int[] trackFormatSupport = formatSupport[groupIndex];
- for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
- if (isSupported(
- trackFormatSupport[trackIndex], params.exceedRendererCapabilitiesIfNecessary)) {
- Format format = trackGroup.getFormat(trackIndex);
- AudioTrackScore trackScore =
- new AudioTrackScore(format, params, trackFormatSupport[trackIndex]);
- if (!trackScore.isWithinConstraints && !params.exceedAudioConstraintsIfNecessary) {
- // Track should not be selected.
- continue;
- }
- if (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0) {
- selectedGroupIndex = groupIndex;
- selectedTrackIndex = trackIndex;
- selectedTrackScore = trackScore;
- }
- }
+ boolean hasVideoRendererWithMappedTracks = false;
+ for (int i = 0; i < mappedTrackInfo.getRendererCount(); i++) {
+ if (C.TRACK_TYPE_VIDEO == mappedTrackInfo.getRendererType(i)
+ && mappedTrackInfo.getTrackGroups(i).length > 0) {
+ hasVideoRendererWithMappedTracks = true;
+ break;
}
}
-
- if (selectedGroupIndex == C.INDEX_UNSET) {
- return null;
- }
-
- TrackGroup selectedGroup = groups.get(selectedGroupIndex);
-
- ExoTrackSelection.Definition definition = null;
- if (!params.forceHighestSupportedBitrate
- && !params.forceLowestBitrate
- && enableAdaptiveTrackSelection) {
- // If the group of the track with the highest score allows it, try to enable adaptation.
- int[] adaptiveTracks =
- getAdaptiveAudioTracks(
- selectedGroup,
- formatSupport[selectedGroupIndex],
- selectedTrackIndex,
- params.maxAudioBitrate,
- params.allowAudioMixedMimeTypeAdaptiveness,
- params.allowAudioMixedSampleRateAdaptiveness,
- params.allowAudioMixedChannelCountAdaptiveness);
- if (adaptiveTracks.length > 1) {
- definition = new ExoTrackSelection.Definition(selectedGroup, adaptiveTracks);
- }
- }
- if (definition == null) {
- // We didn't make an adaptive selection, so make a fixed one instead.
- definition = new ExoTrackSelection.Definition(selectedGroup, selectedTrackIndex);
- }
-
- return Pair.create(definition, Assertions.checkNotNull(selectedTrackScore));
- }
-
- private static int[] getAdaptiveAudioTracks(
- TrackGroup group,
- @Capabilities int[] formatSupport,
- int primaryTrackIndex,
- int maxAudioBitrate,
- boolean allowMixedMimeTypeAdaptiveness,
- boolean allowMixedSampleRateAdaptiveness,
- boolean allowAudioMixedChannelCountAdaptiveness) {
- Format primaryFormat = group.getFormat(primaryTrackIndex);
- int[] adaptiveIndices = new int[group.length];
- int count = 0;
- for (int i = 0; i < group.length; i++) {
- if (i == primaryTrackIndex
- || isSupportedAdaptiveAudioTrack(
- group.getFormat(i),
- formatSupport[i],
- primaryFormat,
- maxAudioBitrate,
- allowMixedMimeTypeAdaptiveness,
- allowMixedSampleRateAdaptiveness,
- allowAudioMixedChannelCountAdaptiveness)) {
- adaptiveIndices[count++] = i;
- }
- }
- return Arrays.copyOf(adaptiveIndices, count);
- }
-
- private static boolean isSupportedAdaptiveAudioTrack(
- Format format,
- @Capabilities int formatSupport,
- Format primaryFormat,
- int maxAudioBitrate,
- boolean allowMixedMimeTypeAdaptiveness,
- boolean allowMixedSampleRateAdaptiveness,
- boolean allowAudioMixedChannelCountAdaptiveness) {
- return isSupported(formatSupport, /* allowExceedsCapabilities= */ false)
- && format.bitrate != Format.NO_VALUE
- && format.bitrate <= maxAudioBitrate
- && (allowAudioMixedChannelCountAdaptiveness
- || (format.channelCount != Format.NO_VALUE
- && format.channelCount == primaryFormat.channelCount))
- && (allowMixedMimeTypeAdaptiveness
- || (format.sampleMimeType != null
- && TextUtils.equals(format.sampleMimeType, primaryFormat.sampleMimeType)))
- && (allowMixedSampleRateAdaptiveness
- || (format.sampleRate != Format.NO_VALUE
- && format.sampleRate == primaryFormat.sampleRate));
+ boolean hasVideoRendererWithMappedTracksFinal = hasVideoRendererWithMappedTracks;
+ return selectTracksForType(
+ C.TRACK_TYPE_AUDIO,
+ mappedTrackInfo,
+ rendererFormatSupports,
+ (rendererIndex, group, support) ->
+ AudioTrackInfo.createForTrackGroup(
+ rendererIndex, group, params, support, hasVideoRendererWithMappedTracksFinal),
+ AudioTrackInfo::compareSelections);
}
// Text track selection implementation.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
- * {@link ExoTrackSelection} for a text renderer.
+ * {@link ExoTrackSelection.Definition} for a text track selection.
*
- * @param groups The {@link TrackGroupArray} mapped to the renderer.
- * @param formatSupport The {@link Capabilities} for each mapped track, indexed by track group and
- * track (in that order).
+ * @param mappedTrackInfo Mapped track information.
+ * @param rendererFormatSupports The {@link Capabilities} for each mapped track, indexed by
+ * renderer, track group and track (in that order).
* @param params The selector's current constraint parameters.
* @param selectedAudioLanguage The language of the selected audio track. May be null if the
- * selected text track declares no language or no text track was selected.
- * @return The {@link ExoTrackSelection.Definition} and corresponding {@link TextTrackScore}, or
- * null if no selection was made.
+ * selected audio track declares no language or no audio track was selected.
+ * @return A pair of the selected {@link ExoTrackSelection.Definition} and the corresponding
+ * renderer index, or null if no selection was made.
* @throws ExoPlaybackException If an error occurs while selecting the tracks.
*/
+ @SuppressLint("WrongConstant") // Lint doesn't understand arrays of IntDefs.
@Nullable
- protected Pair selectTextTrack(
- TrackGroupArray groups,
- @Capabilities int[][] formatSupport,
+ protected Pair selectTextTrack(
+ MappedTrackInfo mappedTrackInfo,
+ @Capabilities int[][][] rendererFormatSupports,
Parameters params,
@Nullable String selectedAudioLanguage)
throws ExoPlaybackException {
- @Nullable TrackGroup selectedGroup = null;
- int selectedTrackIndex = C.INDEX_UNSET;
- @Nullable TextTrackScore selectedTrackScore = null;
- for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
- TrackGroup trackGroup = groups.get(groupIndex);
- @Capabilities int[] trackFormatSupport = formatSupport[groupIndex];
- for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
- if (isSupported(
- trackFormatSupport[trackIndex], params.exceedRendererCapabilitiesIfNecessary)) {
- Format format = trackGroup.getFormat(trackIndex);
- TextTrackScore trackScore =
- new TextTrackScore(
- format, params, trackFormatSupport[trackIndex], selectedAudioLanguage);
- if (trackScore.isWithinConstraints
- && (selectedTrackScore == null || trackScore.compareTo(selectedTrackScore) > 0)) {
- selectedGroup = trackGroup;
- selectedTrackIndex = trackIndex;
- selectedTrackScore = trackScore;
- }
- }
- }
- }
- return selectedGroup == null
- ? null
- : Pair.create(
- new ExoTrackSelection.Definition(selectedGroup, selectedTrackIndex),
- Assertions.checkNotNull(selectedTrackScore));
+ return selectTracksForType(
+ C.TRACK_TYPE_TEXT,
+ mappedTrackInfo,
+ rendererFormatSupports,
+ (rendererIndex, group, support) ->
+ TextTrackInfo.createForTrackGroup(
+ rendererIndex, group, params, support, selectedAudioLanguage),
+ TextTrackInfo::compareSelections);
}
- // General track selection methods.
+ // Generic track selection methods.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
@@ -2247,6 +1928,64 @@ public class DefaultTrackSelector extends MappingTrackSelector {
: new ExoTrackSelection.Definition(selectedGroup, selectedTrackIndex);
}
+ @Nullable
+ private > Pair selectTracksForType(
+ @C.TrackType int trackType,
+ MappedTrackInfo mappedTrackInfo,
+ @Capabilities int[][][] formatSupport,
+ TrackInfo.Factory trackInfoFactory,
+ Comparator> selectionComparator) {
+ ArrayList> possibleSelections = new ArrayList<>();
+ int rendererCount = mappedTrackInfo.getRendererCount();
+ for (int rendererIndex = 0; rendererIndex < rendererCount; rendererIndex++) {
+ if (trackType == mappedTrackInfo.getRendererType(rendererIndex)) {
+ TrackGroupArray groups = mappedTrackInfo.getTrackGroups(rendererIndex);
+ for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
+ TrackGroup trackGroup = groups.get(groupIndex);
+ @Capabilities int[] groupSupport = formatSupport[rendererIndex][groupIndex];
+ List trackInfos = trackInfoFactory.create(rendererIndex, trackGroup, groupSupport);
+ boolean[] usedTrackInSelection = new boolean[trackGroup.length];
+ for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
+ T trackInfo = trackInfos.get(trackIndex);
+ @SelectionEligibility int eligibility = trackInfo.getSelectionEligibility();
+ if (usedTrackInSelection[trackIndex] || eligibility == SELECTION_ELIGIBILITY_NO) {
+ continue;
+ }
+ List selection;
+ if (eligibility == SELECTION_ELIGIBILITY_FIXED) {
+ selection = ImmutableList.of(trackInfo);
+ } else {
+ selection = new ArrayList<>();
+ selection.add(trackInfo);
+ for (int i = trackIndex + 1; i < trackGroup.length; i++) {
+ T otherTrackInfo = trackInfos.get(i);
+ if (otherTrackInfo.getSelectionEligibility() == SELECTION_ELIGIBILITY_ADAPTIVE) {
+ if (trackInfo.isCompatibleForAdaptationWith(otherTrackInfo)) {
+ selection.add(otherTrackInfo);
+ usedTrackInSelection[i] = true;
+ }
+ }
+ }
+ }
+ possibleSelections.add(selection);
+ }
+ }
+ }
+ }
+ if (possibleSelections.isEmpty()) {
+ return null;
+ }
+ List bestSelection = max(possibleSelections, selectionComparator);
+ int[] trackIndices = new int[bestSelection.size()];
+ for (int i = 0; i < bestSelection.size(); i++) {
+ trackIndices[i] = bestSelection.get(i).trackIndex;
+ }
+ T firstTrackInfo = bestSelection.get(0);
+ return Pair.create(
+ new ExoTrackSelection.Definition(firstTrackInfo.trackGroup, trackIndices),
+ firstTrackInfo.rendererIndex);
+ }
+
// Utility methods.
/**
@@ -2402,25 +2141,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return 0;
}
- private static List getViewportFilteredTrackIndices(
+ private static int getMaxVideoPixelsToRetainForViewport(
TrackGroup group, int viewportWidth, int viewportHeight, boolean orientationMayChange) {
- // Initially include all indices.
- ArrayList selectedTrackIndices = new ArrayList<>(group.length);
- for (int i = 0; i < group.length; i++) {
- selectedTrackIndices.add(i);
- }
-
if (viewportWidth == Integer.MAX_VALUE || viewportHeight == Integer.MAX_VALUE) {
- // Viewport dimensions not set. Return the full set of indices.
- return selectedTrackIndices;
+ return Integer.MAX_VALUE;
}
-
int maxVideoPixelsToRetain = Integer.MAX_VALUE;
for (int i = 0; i < group.length; i++) {
Format format = group.getFormat(i);
// Keep track of the number of pixels of the selected format whose resolution is the
// smallest to exceed the maximum size at which it can be displayed within the viewport.
- // We'll discard formats of higher resolution.
if (format.width > 0 && format.height > 0) {
Point maxVideoSizeInViewport =
getMaxVideoSizeInViewport(
@@ -2433,21 +2163,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
}
}
-
- // Filter out formats that exceed maxVideoPixelsToRetain. These formats have an unnecessarily
- // high resolution given the size at which the video will be displayed within the viewport. Also
- // filter out formats with unknown dimensions, since we have some whose dimensions are known.
- if (maxVideoPixelsToRetain != Integer.MAX_VALUE) {
- for (int i = selectedTrackIndices.size() - 1; i >= 0; i--) {
- Format format = group.getFormat(selectedTrackIndices.get(i));
- int pixelCount = format.getPixelCount();
- if (pixelCount == Format.NO_VALUE || pixelCount > maxVideoPixelsToRetain) {
- selectedTrackIndices.remove(i);
- }
- }
- }
-
- return selectedTrackIndices;
+ return maxVideoPixelsToRetain;
}
/**
@@ -2484,15 +2200,92 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return Integer.bitCount(trackRoleFlags & preferredRoleFlags);
}
- /** Represents how well a video track matches the selection {@link Parameters}. */
- protected static final class VideoTrackScore implements Comparable {
+ /**
+ * Returns preference score for primary, hardware-accelerated video codecs, with higher score
+ * being preferred.
+ */
+ private static int getVideoCodecPreferenceScore(@Nullable String mimeType) {
+ if (mimeType == null) {
+ return 0;
+ }
+ switch (mimeType) {
+ case MimeTypes.VIDEO_AV1:
+ return 4;
+ case MimeTypes.VIDEO_H265:
+ return 3;
+ case MimeTypes.VIDEO_VP9:
+ return 2;
+ case MimeTypes.VIDEO_H264:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+
+ /** Base class for track selection information of a {@link Format}. */
+ private abstract static class TrackInfo> {
+ /** Factory for {@link TrackInfo} implementations for a given {@link TrackGroup}. */
+ public interface Factory> {
+ List create(int rendererIndex, TrackGroup trackGroup, @Capabilities int[] formatSupports);
+ }
+
+ public final int rendererIndex;
+ public final TrackGroup trackGroup;
+ public final int trackIndex;
+ public final Format format;
+
+ public TrackInfo(int rendererIndex, TrackGroup trackGroup, int trackIndex) {
+ this.rendererIndex = rendererIndex;
+ this.trackGroup = trackGroup;
+ this.trackIndex = trackIndex;
+ this.format = trackGroup.getFormat(trackIndex);
+ }
+
+ /** Returns to what extent the track is {@link SelectionEligibility eligible for selection}. */
+ @SelectionEligibility
+ public abstract int getSelectionEligibility();
/**
- * Whether the provided format is within the parameter maximum constraints. If {@code false},
- * the format should not be selected.
+ * Returns whether this track is compatible for an adaptive selection with the specified other
+ * track.
*/
- public final boolean isWithinMaxConstraints;
+ public abstract boolean isCompatibleForAdaptationWith(T otherTrack);
+ }
+ private static final class VideoTrackInfo extends TrackInfo {
+
+ public static ImmutableList createForTrackGroup(
+ int rendererIndex,
+ TrackGroup trackGroup,
+ Parameters params,
+ @Capabilities int[] formatSupport,
+ @AdaptiveSupport int mixedMimeTypeAdaptionSupport) {
+ int maxPixelsToRetainForViewport =
+ getMaxVideoPixelsToRetainForViewport(
+ trackGroup,
+ params.viewportWidth,
+ params.viewportHeight,
+ params.viewportOrientationMayChange);
+ ImmutableList.Builder listBuilder = ImmutableList.builder();
+ for (int i = 0; i < trackGroup.length; i++) {
+ int pixelCount = trackGroup.getFormat(i).getPixelCount();
+ boolean isSuitableForViewport =
+ maxPixelsToRetainForViewport == Integer.MAX_VALUE
+ || (pixelCount != Format.NO_VALUE && pixelCount <= maxPixelsToRetainForViewport);
+ listBuilder.add(
+ new VideoTrackInfo(
+ rendererIndex,
+ trackGroup,
+ /* trackIndex= */ i,
+ params,
+ formatSupport[i],
+ mixedMimeTypeAdaptionSupport,
+ isSuitableForViewport));
+ }
+ return listBuilder.build();
+ }
+
+ private final boolean isWithinMaxConstraints;
private final Parameters parameters;
private final boolean isWithinMinConstraints;
private final boolean isWithinRendererCapabilities;
@@ -2501,13 +2294,31 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final int preferredMimeTypeMatchIndex;
private final int preferredRoleFlagsScore;
private final boolean hasMainOrNoRoleFlag;
+ private final boolean allowMixedMimeTypes;
+ @SelectionEligibility private final int selectionEligibility;
+ private final boolean usesPrimaryDecoder;
+ private final boolean usesHardwareAcceleration;
+ private final int codecPreferenceScore;
- public VideoTrackScore(
- Format format,
+ public VideoTrackInfo(
+ int rendererIndex,
+ TrackGroup trackGroup,
+ int trackIndex,
Parameters parameters,
@Capabilities int formatSupport,
+ @AdaptiveSupport int mixedMimeTypeAdaptationSupport,
boolean isSuitableForViewport) {
+ super(rendererIndex, trackGroup, trackIndex);
this.parameters = parameters;
+ @SuppressLint("WrongConstant")
+ int requiredAdaptiveSupport =
+ parameters.allowVideoNonSeamlessAdaptiveness
+ ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS
+ | RendererCapabilities.ADAPTIVE_SEAMLESS)
+ : RendererCapabilities.ADAPTIVE_SEAMLESS;
+ allowMixedMimeTypes =
+ parameters.allowVideoMixedMimeTypeAdaptiveness
+ && (mixedMimeTypeAdaptationSupport & requiredAdaptiveSupport) != 0;
isWithinMaxConstraints =
isSuitableForViewport
&& (format.width == Format.NO_VALUE || format.width <= parameters.maxVideoWidth)
@@ -2540,10 +2351,81 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
}
preferredMimeTypeMatchIndex = bestMimeTypeMatchIndex;
+ usesPrimaryDecoder =
+ RendererCapabilities.getDecoderSupport(formatSupport)
+ == RendererCapabilities.DECODER_SUPPORT_PRIMARY;
+ usesHardwareAcceleration =
+ RendererCapabilities.getHardwareAccelerationSupport(formatSupport)
+ == RendererCapabilities.HARDWARE_ACCELERATION_SUPPORTED;
+ codecPreferenceScore = getVideoCodecPreferenceScore(format.sampleMimeType);
+ selectionEligibility = evaluateSelectionEligibility(formatSupport, requiredAdaptiveSupport);
}
@Override
- public int compareTo(VideoTrackScore other) {
+ @SelectionEligibility
+ public int getSelectionEligibility() {
+ return selectionEligibility;
+ }
+
+ @Override
+ public boolean isCompatibleForAdaptationWith(VideoTrackInfo otherTrack) {
+ return (allowMixedMimeTypes
+ || Util.areEqual(format.sampleMimeType, otherTrack.format.sampleMimeType))
+ && (parameters.allowVideoMixedDecoderSupportAdaptiveness
+ || (this.usesPrimaryDecoder == otherTrack.usesPrimaryDecoder
+ && this.usesHardwareAcceleration == otherTrack.usesHardwareAcceleration));
+ }
+
+ @SelectionEligibility
+ private int evaluateSelectionEligibility(
+ @Capabilities int rendererSupport, @AdaptiveSupport int requiredAdaptiveSupport) {
+ if ((format.roleFlags & C.ROLE_FLAG_TRICK_PLAY) != 0) {
+ // Ignore trick-play tracks for now.
+ return SELECTION_ELIGIBILITY_NO;
+ }
+ if (!isSupported(rendererSupport, parameters.exceedRendererCapabilitiesIfNecessary)) {
+ return SELECTION_ELIGIBILITY_NO;
+ }
+ if (!isWithinMaxConstraints && !parameters.exceedVideoConstraintsIfNecessary) {
+ return SELECTION_ELIGIBILITY_NO;
+ }
+ return isSupported(rendererSupport, /* allowExceedsCapabilities= */ false)
+ && isWithinMinConstraints
+ && isWithinMaxConstraints
+ && format.bitrate != Format.NO_VALUE
+ && !parameters.forceHighestSupportedBitrate
+ && !parameters.forceLowestBitrate
+ && ((rendererSupport & requiredAdaptiveSupport) != 0)
+ ? SELECTION_ELIGIBILITY_ADAPTIVE
+ : SELECTION_ELIGIBILITY_FIXED;
+ }
+
+ private static int compareNonQualityPreferences(VideoTrackInfo info1, VideoTrackInfo info2) {
+ ComparisonChain chain =
+ ComparisonChain.start()
+ .compareFalseFirst(
+ info1.isWithinRendererCapabilities, info2.isWithinRendererCapabilities)
+ // 1. Compare match with specific content preferences set by the parameters.
+ .compare(info1.preferredRoleFlagsScore, info2.preferredRoleFlagsScore)
+ // 2. Compare match with implicit content preferences set by the media.
+ .compareFalseFirst(info1.hasMainOrNoRoleFlag, info2.hasMainOrNoRoleFlag)
+ // 3. Compare match with technical preferences set by the parameters.
+ .compareFalseFirst(info1.isWithinMaxConstraints, info2.isWithinMaxConstraints)
+ .compareFalseFirst(info1.isWithinMinConstraints, info2.isWithinMinConstraints)
+ .compare(
+ info1.preferredMimeTypeMatchIndex,
+ info2.preferredMimeTypeMatchIndex,
+ Ordering.natural().reverse())
+ // 4. Compare match with renderer capability preferences.
+ .compareFalseFirst(info1.usesPrimaryDecoder, info2.usesPrimaryDecoder)
+ .compareFalseFirst(info1.usesHardwareAcceleration, info2.usesHardwareAcceleration);
+ if (info1.usesPrimaryDecoder && info1.usesHardwareAcceleration) {
+ chain = chain.compare(info1.codecPreferenceScore, info2.codecPreferenceScore);
+ }
+ return chain.result();
+ }
+
+ private static int compareQualityPreferences(VideoTrackInfo info1, VideoTrackInfo info2) {
// The preferred ordering by video quality depends on the constraints:
// - Not within renderer capabilities: Prefer lower quality because it's more likely to play.
// - Within min and max constraints: Prefer higher quality.
@@ -2553,42 +2435,62 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// satisfying the violated max constraints.
// - Outside min and max constraints: Arbitrarily prefer lower quality.
Ordering qualityOrdering =
- isWithinMaxConstraints && isWithinRendererCapabilities
+ info1.isWithinMaxConstraints && info1.isWithinRendererCapabilities
? FORMAT_VALUE_ORDERING
: FORMAT_VALUE_ORDERING.reverse();
return ComparisonChain.start()
- .compareFalseFirst(this.isWithinRendererCapabilities, other.isWithinRendererCapabilities)
- // 1. Compare match with specific content preferences set by the parameters.
- .compare(this.preferredRoleFlagsScore, other.preferredRoleFlagsScore)
- // 2. Compare match with implicit content preferences set by the media.
- .compareFalseFirst(this.hasMainOrNoRoleFlag, other.hasMainOrNoRoleFlag)
- // 3. Compare match with technical preferences set by the parameters.
- .compareFalseFirst(this.isWithinMaxConstraints, other.isWithinMaxConstraints)
- .compareFalseFirst(this.isWithinMinConstraints, other.isWithinMinConstraints)
.compare(
- this.preferredMimeTypeMatchIndex,
- other.preferredMimeTypeMatchIndex,
- Ordering.natural().reverse())
- // 4. Compare technical quality.
+ info1.bitrate,
+ info2.bitrate,
+ info1.parameters.forceLowestBitrate ? FORMAT_VALUE_ORDERING.reverse() : NO_ORDER)
+ .compare(info1.pixelCount, info2.pixelCount, qualityOrdering)
+ .compare(info1.bitrate, info2.bitrate, qualityOrdering)
+ .result();
+ }
+
+ public static int compareSelections(List infos1, List infos2) {
+ return ComparisonChain.start()
+ // Compare non-quality preferences of the best individual track with each other.
.compare(
- this.bitrate,
- other.bitrate,
- parameters.forceLowestBitrate ? FORMAT_VALUE_ORDERING.reverse() : NO_ORDER)
- .compare(this.pixelCount, other.pixelCount, qualityOrdering)
- .compare(this.bitrate, other.bitrate, qualityOrdering)
+ max(infos1, VideoTrackInfo::compareNonQualityPreferences),
+ max(infos2, VideoTrackInfo::compareNonQualityPreferences),
+ VideoTrackInfo::compareNonQualityPreferences)
+ // Prefer selections with more formats (all non-quality preferences being equal).
+ .compare(infos1.size(), infos2.size())
+ // Prefer selections with the best individual track quality.
+ .compare(
+ max(infos1, VideoTrackInfo::compareQualityPreferences),
+ max(infos2, VideoTrackInfo::compareQualityPreferences),
+ VideoTrackInfo::compareQualityPreferences)
.result();
}
}
- /** Represents how well an audio track matches the selection {@link Parameters}. */
- protected static final class AudioTrackScore implements Comparable {
+ private static final class AudioTrackInfo extends TrackInfo
+ implements Comparable {
- /**
- * Whether the provided format is within the parameter constraints. If {@code false}, the format
- * should not be selected.
- */
- public final boolean isWithinConstraints;
+ public static ImmutableList createForTrackGroup(
+ int rendererIndex,
+ TrackGroup trackGroup,
+ Parameters params,
+ @Capabilities int[] formatSupport,
+ boolean hasMappedVideoTracks) {
+ ImmutableList.Builder listBuilder = ImmutableList.builder();
+ for (int i = 0; i < trackGroup.length; i++) {
+ listBuilder.add(
+ new AudioTrackInfo(
+ rendererIndex,
+ trackGroup,
+ /* trackIndex= */ i,
+ params,
+ formatSupport[i],
+ hasMappedVideoTracks));
+ }
+ return listBuilder.build();
+ }
+ @SelectionEligibility private final int selectionEligibility;
+ private final boolean isWithinConstraints;
@Nullable private final String language;
private final Parameters parameters;
private final boolean isWithinRendererCapabilities;
@@ -2603,8 +2505,17 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final int sampleRate;
private final int bitrate;
private final int preferredMimeTypeMatchIndex;
+ private final boolean usesPrimaryDecoder;
+ private final boolean usesHardwareAcceleration;
- public AudioTrackScore(Format format, Parameters parameters, @Capabilities int formatSupport) {
+ public AudioTrackInfo(
+ int rendererIndex,
+ TrackGroup trackGroup,
+ int trackIndex,
+ Parameters parameters,
+ @Capabilities int formatSupport,
+ boolean hasMappedVideoTracks) {
+ super(rendererIndex, trackGroup, trackIndex);
this.parameters = parameters;
this.language = normalizeUndeterminedLanguageToNull(format.language);
isWithinRendererCapabilities =
@@ -2660,17 +2571,39 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
}
preferredMimeTypeMatchIndex = bestMimeTypeMatchIndex;
+ usesPrimaryDecoder =
+ RendererCapabilities.getDecoderSupport(formatSupport)
+ == RendererCapabilities.DECODER_SUPPORT_PRIMARY;
+ usesHardwareAcceleration =
+ RendererCapabilities.getHardwareAccelerationSupport(formatSupport)
+ == RendererCapabilities.HARDWARE_ACCELERATION_SUPPORTED;
+ selectionEligibility = evaluateSelectionEligibility(formatSupport, hasMappedVideoTracks);
}
- /**
- * Compares this score with another.
- *
- * @param other The other score to compare to.
- * @return A positive integer if this score is better than the other. Zero if they are equal. A
- * negative integer if this score is worse than the other.
- */
@Override
- public int compareTo(AudioTrackScore other) {
+ @SelectionEligibility
+ public int getSelectionEligibility() {
+ return selectionEligibility;
+ }
+
+ @Override
+ public boolean isCompatibleForAdaptationWith(AudioTrackInfo otherTrack) {
+ return (parameters.allowAudioMixedChannelCountAdaptiveness
+ || (format.channelCount != Format.NO_VALUE
+ && format.channelCount == otherTrack.format.channelCount))
+ && (parameters.allowAudioMixedMimeTypeAdaptiveness
+ || (format.sampleMimeType != null
+ && TextUtils.equals(format.sampleMimeType, otherTrack.format.sampleMimeType)))
+ && (parameters.allowAudioMixedSampleRateAdaptiveness
+ || (format.sampleRate != Format.NO_VALUE
+ && format.sampleRate == otherTrack.format.sampleRate))
+ && (parameters.allowAudioMixedDecoderSupportAdaptiveness
+ || (this.usesPrimaryDecoder == otherTrack.usesPrimaryDecoder
+ && this.usesHardwareAcceleration == otherTrack.usesHardwareAcceleration));
+ }
+
+ @Override
+ public int compareTo(AudioTrackInfo other) {
// If the formats are within constraints and renderer capabilities then prefer higher values
// of channel count, sample rate and bit rate in that order. Otherwise, prefer lower values.
Ordering qualityOrdering =
@@ -2704,7 +2637,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.bitrate,
other.bitrate,
parameters.forceLowestBitrate ? FORMAT_VALUE_ORDERING.reverse() : NO_ORDER)
- // 4. Compare technical quality.
+ // 4. Compare match with renderer capability preferences.
+ .compareFalseFirst(this.usesPrimaryDecoder, other.usesPrimaryDecoder)
+ .compareFalseFirst(this.usesHardwareAcceleration, other.usesHardwareAcceleration)
+ // 5. Compare technical quality.
.compare(this.channelCount, other.channelCount, qualityOrdering)
.compare(this.sampleRate, other.sampleRate, qualityOrdering)
.compare(
@@ -2714,17 +2650,56 @@ public class DefaultTrackSelector extends MappingTrackSelector {
Util.areEqual(this.language, other.language) ? qualityOrdering : NO_ORDER)
.result();
}
+
+ @SelectionEligibility
+ private int evaluateSelectionEligibility(
+ @Capabilities int rendererSupport, boolean hasMappedVideoTracks) {
+ if (!isSupported(rendererSupport, parameters.exceedRendererCapabilitiesIfNecessary)) {
+ return SELECTION_ELIGIBILITY_NO;
+ }
+ if (!isWithinConstraints && !parameters.exceedAudioConstraintsIfNecessary) {
+ return SELECTION_ELIGIBILITY_NO;
+ }
+ return isSupported(rendererSupport, /* allowExceedsCapabilities= */ false)
+ && isWithinConstraints
+ && format.bitrate != Format.NO_VALUE
+ && !parameters.forceHighestSupportedBitrate
+ && !parameters.forceLowestBitrate
+ && (parameters.allowMultipleAdaptiveSelections || !hasMappedVideoTracks)
+ ? SELECTION_ELIGIBILITY_ADAPTIVE
+ : SELECTION_ELIGIBILITY_FIXED;
+ }
+
+ public static int compareSelections(List infos1, List infos2) {
+ // Compare best tracks of each selection with each other.
+ return max(infos1).compareTo(max(infos2));
+ }
}
- /** Represents how well a text track matches the selection {@link Parameters}. */
- protected static final class TextTrackScore implements Comparable {
+ private static final class TextTrackInfo extends TrackInfo
+ implements Comparable {
- /**
- * Whether the provided format is within the parameter constraints. If {@code false}, the format
- * should not be selected.
- */
- public final boolean isWithinConstraints;
+ public static ImmutableList createForTrackGroup(
+ int rendererIndex,
+ TrackGroup trackGroup,
+ Parameters params,
+ @Capabilities int[] formatSupport,
+ @Nullable String selectedAudioLanguage) {
+ ImmutableList.Builder listBuilder = ImmutableList.builder();
+ for (int i = 0; i < trackGroup.length; i++) {
+ listBuilder.add(
+ new TextTrackInfo(
+ rendererIndex,
+ trackGroup,
+ /* trackIndex= */ i,
+ params,
+ formatSupport[i],
+ selectedAudioLanguage));
+ }
+ return listBuilder.build();
+ }
+ @SelectionEligibility private final int selectionEligibility;
private final boolean isWithinRendererCapabilities;
private final boolean isDefault;
private final boolean isForced;
@@ -2734,11 +2709,14 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private final int selectedAudioLanguageScore;
private final boolean hasCaptionRoleFlags;
- public TextTrackScore(
- Format format,
+ public TextTrackInfo(
+ int rendererIndex,
+ TrackGroup trackGroup,
+ int trackIndex,
Parameters parameters,
@Capabilities int trackFormatSupport,
@Nullable String selectedAudioLanguage) {
+ super(rendererIndex, trackGroup, trackIndex);
isWithinRendererCapabilities =
isSupported(trackFormatSupport, /* allowExceedsCapabilities= */ false);
int maskedSelectionFlags =
@@ -2773,22 +2751,31 @@ public class DefaultTrackSelector extends MappingTrackSelector {
normalizeUndeterminedLanguageToNull(selectedAudioLanguage) == null;
selectedAudioLanguageScore =
getFormatLanguageScore(format, selectedAudioLanguage, selectedAudioLanguageUndetermined);
- isWithinConstraints =
+ boolean isWithinConstraints =
preferredLanguageScore > 0
|| (parameters.preferredTextLanguages.isEmpty() && preferredRoleFlagsScore > 0)
|| isDefault
|| (isForced && selectedAudioLanguageScore > 0);
+ selectionEligibility =
+ isSupported(trackFormatSupport, parameters.exceedRendererCapabilitiesIfNecessary)
+ && isWithinConstraints
+ ? SELECTION_ELIGIBILITY_FIXED
+ : SELECTION_ELIGIBILITY_NO;
}
- /**
- * Compares this score with another.
- *
- * @param other The other score to compare to.
- * @return A positive integer if this score is better than the other. Zero if they are equal. A
- * negative integer if this score is worse than the other.
- */
@Override
- public int compareTo(TextTrackScore other) {
+ @SelectionEligibility
+ public int getSelectionEligibility() {
+ return selectionEligibility;
+ }
+
+ @Override
+ public boolean isCompatibleForAdaptationWith(TextTrackInfo otherTrack) {
+ return false;
+ }
+
+ @Override
+ public int compareTo(TextTrackInfo other) {
ComparisonChain chain =
ComparisonChain.start()
.compareFalseFirst(
@@ -2815,13 +2802,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
return chain.result();
}
+
+ public static int compareSelections(List infos1, List infos2) {
+ return infos1.get(0).compareTo(infos2.get(0));
+ }
}
- /**
- * Represents how well any other track (non video, audio or text) matches the selection {@link
- * Parameters}.
- */
- protected static final class OtherTrackScore implements Comparable {
+ private static final class OtherTrackScore implements Comparable {
private final boolean isDefault;
private final boolean isWithinRendererCapabilities;
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
index 7f53747ea3..aded173b2a 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
@@ -490,7 +490,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
releaseCodec();
}
eventDispatcher.enabled(decoderCounters);
- frameReleaseHelper.onEnabled();
mayRenderFirstFrameAfterEnableIfNotStarted = mayRenderStartOfStream;
renderedFirstFrameAfterEnable = false;
}
@@ -558,7 +557,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
clearReportedVideoSize();
clearRenderedFirstFrame();
haveReportedFirstFrameRenderedForCurrentSurface = false;
- frameReleaseHelper.onDisabled();
tunnelingOnFrameRenderedListener = null;
try {
super.onDisabled();
@@ -770,7 +768,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@Override
protected void onCodecInitialized(
- String name, long initializedTimestampMs, long initializationDurationMs) {
+ String name,
+ MediaCodecAdapter.Configuration configuration,
+ long initializedTimestampMs,
+ long initializationDurationMs) {
eventDispatcher.decoderInitialized(name, initializedTimestampMs, initializationDurationMs);
codecNeedsSetOutputSurfaceWorkaround = codecNeedsSetOutputSurfaceWorkaround(name);
codecHandlesHdr10PlusOutOfBandMetadata =
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java
index 33a445f52f..1875eea81a 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseHelper.java
@@ -149,18 +149,14 @@ public final class VideoFrameReleaseHelper {
updateSurfacePlaybackFrameRate(/* forceUpdate= */ true);
}
- /** Called when the renderer is enabled. */
- public void onEnabled() {
- if (displayHelper != null) {
- checkNotNull(vsyncSampler).addObserver();
- displayHelper.register(this::updateDefaultDisplayRefreshRateParams);
- }
- }
-
/** Called when the renderer is started. */
public void onStarted() {
started = true;
resetAdjustment();
+ if (displayHelper != null) {
+ checkNotNull(vsyncSampler).addObserver();
+ displayHelper.register(this::updateDefaultDisplayRefreshRateParams);
+ }
updateSurfacePlaybackFrameRate(/* forceUpdate= */ false);
}
@@ -227,15 +223,11 @@ public final class VideoFrameReleaseHelper {
/** Called when the renderer is stopped. */
public void onStopped() {
started = false;
- clearSurfaceFrameRate();
- }
-
- /** Called when the renderer is disabled. */
- public void onDisabled() {
if (displayHelper != null) {
displayHelper.unregister();
checkNotNull(vsyncSampler).removeObserver();
}
+ clearSurfaceFrameRate();
}
// Frame release time adjustment.
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
index 886d3c8ed9..923311db17 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java
@@ -9324,6 +9324,85 @@ public final class ExoPlayerTest {
.onPlaybackParametersChanged(new PlaybackParameters(/* speed= */ 2, /* pitch= */ 2));
}
+ @Test
+ public void setPlaybackSpeed_withAdPlayback_onlyAppliesToContent() throws Exception {
+ // Create renderer with media clock to listen to playback parameter changes.
+ ArrayList playbackParameters = new ArrayList<>();
+ FakeMediaClockRenderer audioRenderer =
+ new FakeMediaClockRenderer(C.TRACK_TYPE_AUDIO) {
+ private long positionUs;
+
+ @Override
+ protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
+ this.positionUs = offsetUs;
+ }
+
+ @Override
+ public long getPositionUs() {
+ // Continuously increase position to let playback progress.
+ positionUs += 10_000;
+ return positionUs;
+ }
+
+ @Override
+ public void setPlaybackParameters(PlaybackParameters parameters) {
+ playbackParameters.add(parameters);
+ }
+
+ @Override
+ public PlaybackParameters getPlaybackParameters() {
+ return playbackParameters.isEmpty()
+ ? PlaybackParameters.DEFAULT
+ : Iterables.getLast(playbackParameters);
+ }
+ };
+ ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(audioRenderer).build();
+ AdPlaybackState adPlaybackState =
+ FakeTimeline.createAdPlaybackState(
+ /* adsPerAdGroup= */ 1,
+ /* adGroupTimesUs...= */ 0,
+ 7 * C.MICROS_PER_SECOND,
+ C.TIME_END_OF_SOURCE);
+ TimelineWindowDefinition adTimelineDefinition =
+ new TimelineWindowDefinition(
+ /* periodCount= */ 1,
+ /* id= */ 0,
+ /* isSeekable= */ true,
+ /* isDynamic= */ false,
+ /* isLive= */ false,
+ /* isPlaceholder= */ false,
+ /* durationUs= */ 10 * C.MICROS_PER_SECOND,
+ /* defaultPositionUs= */ 0,
+ /* windowOffsetInFirstPeriodUs= */ 0,
+ adPlaybackState);
+ player.setMediaSource(
+ new FakeMediaSource(
+ new FakeTimeline(adTimelineDefinition), ExoPlayerTestRunner.AUDIO_FORMAT));
+ Player.Listener mockListener = mock(Player.Listener.class);
+ player.addListener(mockListener);
+
+ player.setPlaybackSpeed(5f);
+ player.prepare();
+ player.play();
+ runUntilPlaybackState(player, Player.STATE_ENDED);
+ player.release();
+
+ // Assert that the renderer received the playback speed updates at each ad/content boundary.
+ assertThat(playbackParameters)
+ .containsExactly(
+ /* preroll ad */ new PlaybackParameters(1f),
+ /* content after preroll */ new PlaybackParameters(5f),
+ /* midroll ad */ new PlaybackParameters(1f),
+ /* content after midroll */ new PlaybackParameters(5f),
+ /* postroll ad */ new PlaybackParameters(1f),
+ /* content after postroll */ new PlaybackParameters(5f))
+ .inOrder();
+
+ // Assert that user-set speed was reported, but none of the ad overrides.
+ verify(mockListener).onPlaybackParametersChanged(any());
+ verify(mockListener).onPlaybackParametersChanged(new PlaybackParameters(5.0f));
+ }
+
@Test
public void targetLiveOffsetInMedia_withSetPlaybackParameters_usesPlaybackParameterSpeed()
throws Exception {
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
index 00e99f8b3a..5263f957a9 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaPeriodQueueTest.java
@@ -22,7 +22,9 @@ import static org.robolectric.Shadows.shadowOf;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import com.google.android.exoplayer2.analytics.PlayerId;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.MediaSource.MediaSourceCaller;
@@ -37,6 +39,7 @@ import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
import com.google.android.exoplayer2.upstream.Allocator;
+import com.google.android.exoplayer2.util.Clock;
import com.google.common.collect.ImmutableList;
import org.junit.Before;
import org.junit.Test;
@@ -74,12 +77,16 @@ public final class MediaPeriodQueueTest {
@Before
public void setUp() {
+ AnalyticsCollector analyticsCollector = new AnalyticsCollector(Clock.DEFAULT);
+ analyticsCollector.setPlayer(
+ new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build(),
+ Looper.getMainLooper());
mediaPeriodQueue =
- new MediaPeriodQueue(/* analyticsCollector= */ null, new Handler(Looper.getMainLooper()));
+ new MediaPeriodQueue(analyticsCollector, new Handler(Looper.getMainLooper()));
mediaSourceList =
new MediaSourceList(
mock(MediaSourceList.MediaSourceListInfoRefreshListener.class),
- /* analyticsCollector= */ null,
+ analyticsCollector,
new Handler(Looper.getMainLooper()),
PlayerId.UNSET);
rendererCapabilities = new RendererCapabilities[0];
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java
index 209fb83547..53ba1dac82 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaSourceListTest.java
@@ -25,12 +25,16 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.os.Looper;
+import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.android.exoplayer2.analytics.AnalyticsCollector;
import com.google.android.exoplayer2.analytics.PlayerId;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ShuffleOrder;
import com.google.android.exoplayer2.testutil.FakeMediaSource;
import com.google.android.exoplayer2.testutil.FakeShuffleOrder;
+import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.Collections;
@@ -51,10 +55,14 @@ public class MediaSourceListTest {
@Before
public void setUp() {
+ AnalyticsCollector analyticsCollector = new AnalyticsCollector(Clock.DEFAULT);
+ analyticsCollector.setPlayer(
+ new ExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build(),
+ Looper.getMainLooper());
mediaSourceList =
new MediaSourceList(
mock(MediaSourceList.MediaSourceListInfoRefreshListener.class),
- /* analyticsCollector= */ null,
+ analyticsCollector,
Util.createHandlerForCurrentOrMainLooper(),
PlayerId.UNSET);
}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
index 930a835cec..44aba86db3 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/DefaultPlaybackSessionManagerTest.java
@@ -743,6 +743,126 @@ public final class DefaultPlaybackSessionManagerTest {
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
}
+ @Test
+ public void timelineUpdate_toNewMediaWithWindowIndexOnly_finishesOtherSessions() {
+ Timeline firstTimeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 1000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 3000));
+ EventTime eventTimeFirstTimelineWithPeriodId =
+ createEventTime(
+ firstTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ firstTimeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
+ EventTime eventTimeFirstTimelineWindowOnly1 =
+ createEventTime(firstTimeline, /* windowIndex= */ 1, /* mediaPeriodId= */ null);
+ EventTime eventTimeFirstTimelineWindowOnly2 =
+ createEventTime(firstTimeline, /* windowIndex= */ 2, /* mediaPeriodId= */ null);
+ Timeline secondTimeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 4000));
+ EventTime eventTimeSecondTimeline =
+ createEventTime(secondTimeline, /* windowIndex= */ 0, /* mediaPeriodId= */ null);
+ sessionManager.updateSessionsWithTimelineChange(eventTimeFirstTimelineWithPeriodId);
+ sessionManager.updateSessions(eventTimeFirstTimelineWindowOnly1);
+ sessionManager.updateSessions(eventTimeFirstTimelineWindowOnly2);
+
+ sessionManager.updateSessionsWithTimelineChange(eventTimeSecondTimeline);
+
+ InOrder inOrder = inOrder(mockListener);
+ ArgumentCaptor firstId = ArgumentCaptor.forClass(String.class);
+ inOrder
+ .verify(mockListener)
+ .onSessionCreated(eq(eventTimeFirstTimelineWithPeriodId), firstId.capture());
+ inOrder
+ .verify(mockListener)
+ .onSessionActive(eventTimeFirstTimelineWithPeriodId, firstId.getValue());
+ ArgumentCaptor secondId = ArgumentCaptor.forClass(String.class);
+ inOrder
+ .verify(mockListener)
+ .onSessionCreated(eq(eventTimeFirstTimelineWindowOnly1), secondId.capture());
+ ArgumentCaptor thirdId = ArgumentCaptor.forClass(String.class);
+ inOrder
+ .verify(mockListener)
+ .onSessionCreated(eq(eventTimeFirstTimelineWindowOnly2), thirdId.capture());
+ // The sessions may finish at the same time, so the order of these two callbacks is undefined.
+ ArgumentCaptor finishedSessions = ArgumentCaptor.forClass(String.class);
+ inOrder
+ .verify(mockListener, times(2))
+ .onSessionFinished(
+ eq(eventTimeSecondTimeline),
+ finishedSessions.capture(),
+ /* automaticTransitionToNextPlayback= */ eq(false));
+ assertThat(finishedSessions.getAllValues())
+ .containsExactly(firstId.getValue(), thirdId.getValue());
+ inOrder.verify(mockListener).onSessionActive(eventTimeSecondTimeline, secondId.getValue());
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void timelineUpdate_toNewMediaWithMediaPeriodId_finishesOtherSessions() {
+ Timeline firstTimeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 1000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 3000));
+ EventTime eventTimeFirstTimeline1 =
+ createEventTime(
+ firstTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ firstTimeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
+ EventTime eventTimeFirstTimeline2 =
+ createEventTime(
+ firstTimeline,
+ /* windowIndex= */ 1,
+ new MediaPeriodId(
+ firstTimeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
+ EventTime eventTimeFirstTimeline3 =
+ createEventTime(
+ firstTimeline,
+ /* windowIndex= */ 2,
+ new MediaPeriodId(
+ firstTimeline.getUidOfPeriod(/* periodIndex= */ 2), /* windowSequenceNumber= */ 2));
+ Timeline secondTimeline =
+ new FakeTimeline(
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 2000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 1000),
+ new TimelineWindowDefinition(/* periodCount= */ 1, /* id= */ 3000));
+ EventTime eventTimeSecondTimeline =
+ createEventTime(
+ secondTimeline,
+ /* windowIndex= */ 0,
+ new MediaPeriodId(
+ secondTimeline.getUidOfPeriod(/* periodIndex= */ 0),
+ /* windowSequenceNumber= */ 1));
+ sessionManager.updateSessionsWithTimelineChange(eventTimeFirstTimeline1);
+ sessionManager.updateSessions(eventTimeFirstTimeline2);
+ sessionManager.updateSessions(eventTimeFirstTimeline3);
+
+ sessionManager.updateSessionsWithTimelineChange(eventTimeSecondTimeline);
+
+ InOrder inOrder = inOrder(mockListener);
+ ArgumentCaptor firstId = ArgumentCaptor.forClass(String.class);
+ inOrder.verify(mockListener).onSessionCreated(eq(eventTimeFirstTimeline1), firstId.capture());
+ inOrder.verify(mockListener).onSessionActive(eventTimeFirstTimeline1, firstId.getValue());
+ ArgumentCaptor secondId = ArgumentCaptor.forClass(String.class);
+ inOrder.verify(mockListener).onSessionCreated(eq(eventTimeFirstTimeline2), secondId.capture());
+ ArgumentCaptor thirdId = ArgumentCaptor.forClass(String.class);
+ inOrder.verify(mockListener).onSessionCreated(eq(eventTimeFirstTimeline3), thirdId.capture());
+ inOrder
+ .verify(mockListener)
+ .onSessionFinished(
+ eventTimeSecondTimeline,
+ firstId.getValue(),
+ /* automaticTransitionToNextPlayback= */ false);
+ inOrder.verify(mockListener).onSessionActive(eventTimeSecondTimeline, secondId.getValue());
+ inOrder.verifyNoMoreInteractions();
+ }
+
@Test
public void positionDiscontinuity_withinWindow_doesNotFinishSession() {
Timeline timeline =
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioTrackBufferSizeProviderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioTrackBufferSizeProviderTest.java
new file mode 100644
index 0000000000..eea49bf5b8
--- /dev/null
+++ b/library/core/src/test/java/com/google/android/exoplayer2/audio/DefaultAudioTrackBufferSizeProviderTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2022 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 com.google.android.exoplayer2.audio;
+
+import static com.google.android.exoplayer2.audio.DefaultAudioSink.OUTPUT_MODE_PASSTHROUGH;
+import static com.google.android.exoplayer2.audio.DefaultAudioSink.OUTPUT_MODE_PCM;
+import static com.google.android.exoplayer2.audio.DefaultAudioTrackBufferSizeProvider.getMaximumEncodedRateBytesPerSecond;
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.util.Util;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.junit.runners.Parameterized;
+
+/** Tests for {@link DefaultAudioTrackBufferSizeProvider}. */
+@RunWith(JUnit4.class)
+public class DefaultAudioTrackBufferSizeProviderTest {
+
+ private static final DefaultAudioTrackBufferSizeProvider DEFAULT =
+ new DefaultAudioTrackBufferSizeProvider.Builder().build();
+
+ /** Tests for {@link DefaultAudioTrackBufferSizeProvider} for PCM audio. */
+ @RunWith(Parameterized.class)
+ public static class PcmTest {
+
+ @Parameterized.Parameter(0)
+ @C.PcmEncoding
+ public int encoding;
+
+ @Parameterized.Parameter(1)
+ public int channelCount;
+
+ @Parameterized.Parameter(2)
+ public int sampleRate;
+
+ @Parameterized.Parameters(name = "{index}: encoding={0}, channelCount={1}, sampleRate={2}")
+ public static List data() {
+ return Sets.cartesianProduct(
+ ImmutableList.of(
+ /* encoding */ ImmutableSet.of(
+ C.ENCODING_PCM_8BIT,
+ C.ENCODING_PCM_16BIT,
+ C.ENCODING_PCM_16BIT_BIG_ENDIAN,
+ C.ENCODING_PCM_24BIT,
+ C.ENCODING_PCM_32BIT,
+ C.ENCODING_PCM_FLOAT),
+ /* channelCount */ ImmutableSet.of(1, 2, 3, 4, 6, 8),
+ /* sampleRate*/ ImmutableSet.of(
+ 8000, 11025, 16000, 22050, 44100, 48000, 88200, 96000)))
+ .stream()
+ .map(s -> s.toArray(new Integer[0]))
+ .collect(Collectors.toList());
+ }
+
+ private int getPcmFrameSize() {
+ return Util.getPcmFrameSize(encoding, channelCount);
+ }
+
+ private int durationUsToBytes(int durationUs) {
+ return (int) (((long) durationUs * getPcmFrameSize() * sampleRate) / C.MICROS_PER_SECOND);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_veryBigMinBufferSize_isMinBufferSize() {
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ 123456789,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize).isEqualTo(123456789);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_noMinBufferSize_isMinBufferDuration() {
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ 0,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize).isEqualTo(durationUsToBytes(DEFAULT.minPcmBufferDurationUs));
+ assertThat(bufferSize % getPcmFrameSize()).isEqualTo(0);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_tooSmallMinBufferSize_isMinBufferDuration() {
+ int minBufferSizeInBytes =
+ durationUsToBytes(DEFAULT.minPcmBufferDurationUs / DEFAULT.pcmBufferMultiplicationFactor)
+ - 1;
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ minBufferSizeInBytes,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize).isEqualTo(durationUsToBytes(DEFAULT.minPcmBufferDurationUs));
+ }
+
+ @Test
+ public void getBufferSizeInBytes_lowMinBufferSize_multipliesAudioTrackMinBuffer() {
+ int minBufferSizeInBytes =
+ durationUsToBytes(DEFAULT.minPcmBufferDurationUs / DEFAULT.pcmBufferMultiplicationFactor)
+ + 1;
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ minBufferSizeInBytes,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize)
+ .isEqualTo(minBufferSizeInBytes * DEFAULT.pcmBufferMultiplicationFactor);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_highMinBufferSize_multipliesAudioTrackMinBuffer() {
+ int minBufferSizeInBytes =
+ durationUsToBytes(DEFAULT.maxPcmBufferDurationUs / DEFAULT.pcmBufferMultiplicationFactor)
+ - 1;
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ minBufferSizeInBytes,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize)
+ .isEqualTo(minBufferSizeInBytes * DEFAULT.pcmBufferMultiplicationFactor);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_tooHighMinBufferSize_isMaxBufferDuration() {
+ int minBufferSizeInBytes =
+ durationUsToBytes(DEFAULT.maxPcmBufferDurationUs / DEFAULT.pcmBufferMultiplicationFactor)
+ + 1;
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ minBufferSizeInBytes,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize).isEqualTo(durationUsToBytes(DEFAULT.maxPcmBufferDurationUs));
+ assertThat(bufferSize % getPcmFrameSize()).isEqualTo(0);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_lowPlaybackSpeed_isScaledByPlaybackSpeed() {
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ 0,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 1 / 5F);
+
+ assertThat(bufferSize).isEqualTo(durationUsToBytes(DEFAULT.minPcmBufferDurationUs / 5));
+ }
+
+ @Test
+ public void getBufferSizeInBytes_highPlaybackSpeed_isScaledByPlaybackSpeed() {
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ 0,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PCM,
+ /* pcmFrameSize= */ getPcmFrameSize(),
+ /* sampleRate= */ sampleRate,
+ /* maxAudioTrackPlaybackSpeed= */ 8F);
+
+ assertThat(bufferSize).isEqualTo(durationUsToBytes(DEFAULT.minPcmBufferDurationUs * 8));
+ }
+ }
+ /**
+ * Tests for {@link DefaultAudioTrackBufferSizeProvider} for encoded audio except {@link
+ * C#ENCODING_AC3}.
+ */
+ @RunWith(Parameterized.class)
+ public static class EncodedTest {
+
+ @Parameterized.Parameter(0)
+ @C.Encoding
+ public int encoding;
+
+ @Parameterized.Parameters(name = "{index}: encoding={0}")
+ public static ImmutableList data() {
+ return ImmutableList.of(
+ C.ENCODING_MP3,
+ C.ENCODING_AAC_LC,
+ C.ENCODING_AAC_HE_V1,
+ C.ENCODING_AC4,
+ C.ENCODING_DTS,
+ C.ENCODING_DOLBY_TRUEHD);
+ }
+
+ @Test
+ public void getBufferSizeInBytes_veryBigMinBufferSize_isMinBufferSize() {
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ 123456789,
+ /* encoding= */ encoding,
+ /* outputMode= */ OUTPUT_MODE_PASSTHROUGH,
+ /* pcmFrameSize= */ 1,
+ /* sampleRate= */ 0,
+ /* maxAudioTrackPlaybackSpeed= */ 0);
+
+ assertThat(bufferSize).isEqualTo(123456789);
+ }
+ }
+
+ @Test
+ public void
+ getBufferSizeInBytes_passthroughAC3_isPassthroughBufferSizeTimesMultiplicationFactor() {
+ int bufferSize =
+ DEFAULT.getBufferSizeInBytes(
+ /* minBufferSizeInBytes= */ 0,
+ /* encoding= */ C.ENCODING_AC3,
+ /* outputMode= */ OUTPUT_MODE_PASSTHROUGH,
+ /* pcmFrameSize= */ 1,
+ /* sampleRate= */ 0,
+ /* maxAudioTrackPlaybackSpeed= */ 1);
+
+ assertThat(bufferSize)
+ .isEqualTo(
+ durationUsToAc3MaxBytes(DEFAULT.passthroughBufferDurationUs)
+ * DEFAULT.ac3BufferMultiplicationFactor);
+ }
+
+ private static int durationUsToAc3MaxBytes(long durationUs) {
+ return (int)
+ (durationUs * getMaximumEncodedRateBytesPerSecond(C.ENCODING_AC3) / C.MICROS_PER_SECOND);
+ }
+}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/MkvPlaybackTest.java b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/MkvPlaybackTest.java
index c719cdfa00..4a8b550a15 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/e2etest/MkvPlaybackTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/e2etest/MkvPlaybackTest.java
@@ -48,7 +48,9 @@ public final class MkvPlaybackTest {
"sample_with_ssa_subtitles.mkv",
"sample_with_null_terminated_ssa_subtitles.mkv",
"sample_with_srt.mkv",
- "sample_with_null_terminated_srt.mkv");
+ "sample_with_null_terminated_srt.mkv",
+ "sample_with_vtt_subtitles.mkv",
+ "sample_with_null_terminated_vtt_subtitles.mkv");
}
@ParameterizedRobolectricTestRunner.Parameter public String inputFile;
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSourceTest.java
index 66d85e360f..cd9b066f69 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSourceTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionMediaSourceTest.java
@@ -182,20 +182,20 @@ public final class ServerSideAdInsertionMediaSourceTest {
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 0,
- /* toPositionUs= */ 200_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 200_000);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 400_000,
- /* toPositionUs= */ 700_000,
- /* contentResumeOffsetUs= */ 1_000_000);
+ /* contentResumeOffsetUs= */ 1_000_000,
+ /* adDurationsUs...= */ 300_000);
AdPlaybackState firstAdPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 900_000,
- /* toPositionUs= */ 1_000_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 100_000);
AtomicReference mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
@@ -252,8 +252,8 @@ public final class ServerSideAdInsertionMediaSourceTest {
addAdGroupToAdPlaybackState(
new AdPlaybackState(/* adsId= */ new Object()),
/* fromPositionUs= */ 900_000,
- /* toPositionUs= */ 1_000_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 100_000);
AtomicReference mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
new ServerSideAdInsertionMediaSource(
@@ -280,8 +280,8 @@ public final class ServerSideAdInsertionMediaSourceTest {
addAdGroupToAdPlaybackState(
firstAdPlaybackState,
/* fromPositionUs= */ 0,
- /* toPositionUs= */ 500_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 500_000);
mediaSourceRef
.get()
.setAdPlaybackStates(ImmutableMap.of(periodUid.get(), secondAdPlaybackState));
@@ -323,8 +323,8 @@ public final class ServerSideAdInsertionMediaSourceTest {
addAdGroupToAdPlaybackState(
new AdPlaybackState(/* adsId= */ new Object()),
/* fromPositionUs= */ 0,
- /* toPositionUs= */ 500_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 500_000);
AtomicReference mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
new ServerSideAdInsertionMediaSource(
@@ -391,20 +391,20 @@ public final class ServerSideAdInsertionMediaSourceTest {
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 0,
- /* toPositionUs= */ 100_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 100_000);
adPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 600_000,
- /* toPositionUs= */ 700_000,
- /* contentResumeOffsetUs= */ 1_000_000);
+ /* contentResumeOffsetUs= */ 1_000_000,
+ /* adDurationsUs...= */ 100_000);
AdPlaybackState firstAdPlaybackState =
addAdGroupToAdPlaybackState(
adPlaybackState,
/* fromPositionUs= */ 900_000,
- /* toPositionUs= */ 1_000_000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 100_000);
AtomicReference mediaSourceRef = new AtomicReference<>();
mediaSourceRef.set(
@@ -427,7 +427,7 @@ public final class ServerSideAdInsertionMediaSourceTest {
player.setMediaSource(mediaSourceRef.get());
player.prepare();
// Play to the first content part, then seek past the midroll.
- playUntilPosition(player, /* windowIndex= */ 0, /* positionMs= */ 100);
+ playUntilPosition(player, /* mediaItemIndex= */ 0, /* positionMs= */ 100);
player.seekTo(/* positionMs= */ 1_600);
runUntilPendingCommandsAreFullyHandled(player);
long positionAfterSeekMs = player.getCurrentPosition();
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtilTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtilTest.java
index b9bfaae7b9..c3a3c38d74 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtilTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ads/ServerSideAdInsertionUtilTest.java
@@ -22,6 +22,7 @@ import static com.google.android.exoplayer2.source.ads.ServerSideAdInsertionUtil
import static com.google.android.exoplayer2.source.ads.ServerSideAdInsertionUtil.getStreamPositionUsForAd;
import static com.google.android.exoplayer2.source.ads.ServerSideAdInsertionUtil.getStreamPositionUsForContent;
import static com.google.common.truth.Truth.assertThat;
+import static java.util.Arrays.stream;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
@@ -46,8 +47,8 @@ public final class ServerSideAdInsertionUtilTest {
addAdGroupToAdPlaybackState(
state,
/* fromPositionUs= */ 4300,
- /* toPositionUs= */ 4500,
- /* contentResumeOffsetUs= */ 400);
+ /* contentResumeOffsetUs= */ 400,
+ /* adDurationsUs...= */ 200);
assertThat(state)
.isEqualTo(
@@ -64,8 +65,8 @@ public final class ServerSideAdInsertionUtilTest {
addAdGroupToAdPlaybackState(
state,
/* fromPositionUs= */ 2100,
- /* toPositionUs= */ 2400,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 300);
assertThat(state)
.isEqualTo(
@@ -86,8 +87,8 @@ public final class ServerSideAdInsertionUtilTest {
addAdGroupToAdPlaybackState(
state,
/* fromPositionUs= */ 0,
- /* toPositionUs= */ 100,
- /* contentResumeOffsetUs= */ 50);
+ /* contentResumeOffsetUs= */ 50,
+ /* adDurationsUs...= */ 100);
assertThat(state)
.isEqualTo(
@@ -112,8 +113,8 @@ public final class ServerSideAdInsertionUtilTest {
addAdGroupToAdPlaybackState(
state,
/* fromPositionUs= */ 5000,
- /* toPositionUs= */ 6000,
- /* contentResumeOffsetUs= */ 0);
+ /* contentResumeOffsetUs= */ 0,
+ /* adDurationsUs...= */ 1000);
assertThat(state)
.isEqualTo(
@@ -143,6 +144,33 @@ public final class ServerSideAdInsertionUtilTest {
.withAdDurationsUs(/* adGroupIndex= */ 5, /* adDurationsUs...= */ 1000));
}
+ @Test
+ public void addAdGroupToAdPlaybackState_emptyLeadingAds_markedAsSkipped() {
+ AdPlaybackState state = new AdPlaybackState(ADS_ID);
+
+ state =
+ addAdGroupToAdPlaybackState(
+ state,
+ /* fromPositionUs= */ 0,
+ /* contentResumeOffsetUs= */ 50_000,
+ /* adDurationsUs...= */ 0,
+ 0,
+ 10_000,
+ 40_000,
+ 0);
+
+ AdPlaybackState.AdGroup adGroup = state.getAdGroup(/* adGroupIndex= */ 0);
+ assertThat(adGroup.durationsUs[0]).isEqualTo(0);
+ assertThat(adGroup.states[0]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED);
+ assertThat(adGroup.durationsUs[1]).isEqualTo(0);
+ assertThat(adGroup.states[1]).isEqualTo(AdPlaybackState.AD_STATE_SKIPPED);
+ assertThat(adGroup.durationsUs[2]).isEqualTo(10_000);
+ assertThat(adGroup.states[2]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
+ assertThat(adGroup.durationsUs[4]).isEqualTo(0);
+ assertThat(adGroup.states[4]).isEqualTo(AdPlaybackState.AD_STATE_UNAVAILABLE);
+ assertThat(stream(adGroup.durationsUs).sum()).isEqualTo(50_000);
+ }
+
@Test
public void getStreamPositionUsForAd_returnsCorrectPositions() {
// stream: 0-- ad1 --200-- content --2100-- ad2 --2300-- content --4300-- ad3 --4500-- content
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java
index 40a8e3d93c..8eefe2d16a 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java
@@ -20,6 +20,10 @@ import static com.google.android.exoplayer2.C.FORMAT_HANDLED;
import static com.google.android.exoplayer2.C.FORMAT_UNSUPPORTED_SUBTYPE;
import static com.google.android.exoplayer2.C.FORMAT_UNSUPPORTED_TYPE;
import static com.google.android.exoplayer2.RendererCapabilities.ADAPTIVE_NOT_SEAMLESS;
+import static com.google.android.exoplayer2.RendererCapabilities.DECODER_SUPPORT_FALLBACK;
+import static com.google.android.exoplayer2.RendererCapabilities.DECODER_SUPPORT_PRIMARY;
+import static com.google.android.exoplayer2.RendererCapabilities.HARDWARE_ACCELERATION_NOT_SUPPORTED;
+import static com.google.android.exoplayer2.RendererCapabilities.HARDWARE_ACCELERATION_SUPPORTED;
import static com.google.android.exoplayer2.RendererCapabilities.TUNNELING_NOT_SUPPORTED;
import static com.google.android.exoplayer2.RendererConfiguration.DEFAULT;
import static com.google.common.truth.Truth.assertThat;
@@ -37,6 +41,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities;
+import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
@@ -1623,6 +1628,122 @@ public final class DefaultTrackSelectorTest {
assertNoSelection(result.selections[0]);
}
+ @Test
+ public void selectTracksWithMultipleAudioTracksWithMixedDecoderSupportLevels() throws Exception {
+ Format.Builder formatBuilder = AUDIO_FORMAT.buildUpon();
+ Format format0 = formatBuilder.setId("0").setAverageBitrate(200).build();
+ Format format1 = formatBuilder.setId("1").setAverageBitrate(400).build();
+ Format format2 = formatBuilder.setId("2").setAverageBitrate(600).build();
+ Format format3 = formatBuilder.setId("3").setAverageBitrate(800).build();
+ TrackGroupArray trackGroups = singleTrackGroup(format0, format1, format2, format3);
+ @Capabilities int unsupported = RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE);
+ @Capabilities
+ int primaryHardware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_SUPPORTED,
+ DECODER_SUPPORT_PRIMARY);
+ @Capabilities
+ int primarySoftware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_NOT_SUPPORTED,
+ DECODER_SUPPORT_PRIMARY);
+ @Capabilities
+ int fallbackHardware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_SUPPORTED,
+ DECODER_SUPPORT_FALLBACK);
+ @Capabilities
+ int fallbackSoftware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_NOT_SUPPORTED,
+ DECODER_SUPPORT_FALLBACK);
+
+ // Select all tracks supported by primary, hardware decoder by default.
+ ImmutableMap rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0",
+ primaryHardware,
+ "1",
+ primaryHardware,
+ "2",
+ primarySoftware,
+ "3",
+ fallbackHardware);
+ RendererCapabilities rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, rendererCapabilitiesMap);
+ TrackSelectorResult result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 1, 0);
+
+ // Select all tracks supported by primary, software decoder by default if no primary, hardware
+ // decoder is available.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0",
+ fallbackHardware,
+ "1",
+ fallbackHardware,
+ "2",
+ primarySoftware,
+ "3",
+ fallbackSoftware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, rendererCapabilitiesMap);
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertFixedSelection(result.selections[0], trackGroups.get(0), 2);
+
+ // Select all tracks supported by fallback, hardware decoder if no primary decoder is
+ // available.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0", fallbackHardware, "1", unsupported, "2", fallbackSoftware, "3", fallbackHardware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, rendererCapabilitiesMap);
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 3, 0);
+
+ // Select all tracks supported by fallback, software decoder if no other decoder is available.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0", fallbackSoftware, "1", fallbackSoftware, "2", unsupported, "3", fallbackSoftware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, rendererCapabilitiesMap);
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 3, 1, 0);
+
+ // Select all tracks if mixed decoder support is allowed.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0", primaryHardware, "1", unsupported, "2", primarySoftware, "3", fallbackHardware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_AUDIO, rendererCapabilitiesMap);
+ trackSelector.setParameters(
+ defaultParameters.buildUpon().setAllowAudioMixedDecoderSupportAdaptiveness(true));
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 3, 2, 0);
+ }
+
@Test
public void selectTracksWithMultipleAudioTracksOverrideReturnsAdaptiveTrackSelection()
throws Exception {
@@ -1773,6 +1894,122 @@ public final class DefaultTrackSelectorTest {
assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 0, 1);
}
+ @Test
+ public void selectTracksWithMultipleVideoTracksWithMixedDecoderSupportLevels() throws Exception {
+ Format.Builder formatBuilder = VIDEO_FORMAT.buildUpon();
+ Format format0 = formatBuilder.setId("0").setAverageBitrate(200).build();
+ Format format1 = formatBuilder.setId("1").setAverageBitrate(400).build();
+ Format format2 = formatBuilder.setId("2").setAverageBitrate(600).build();
+ Format format3 = formatBuilder.setId("3").setAverageBitrate(800).build();
+ TrackGroupArray trackGroups = singleTrackGroup(format0, format1, format2, format3);
+ @Capabilities int unsupported = RendererCapabilities.create(FORMAT_UNSUPPORTED_TYPE);
+ @Capabilities
+ int primaryHardware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_SUPPORTED,
+ DECODER_SUPPORT_PRIMARY);
+ @Capabilities
+ int primarySoftware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_NOT_SUPPORTED,
+ DECODER_SUPPORT_PRIMARY);
+ @Capabilities
+ int fallbackHardware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_SUPPORTED,
+ DECODER_SUPPORT_FALLBACK);
+ @Capabilities
+ int fallbackSoftware =
+ RendererCapabilities.create(
+ FORMAT_HANDLED,
+ ADAPTIVE_NOT_SEAMLESS,
+ TUNNELING_NOT_SUPPORTED,
+ HARDWARE_ACCELERATION_NOT_SUPPORTED,
+ DECODER_SUPPORT_FALLBACK);
+
+ // Select all tracks supported by primary, hardware decoder by default.
+ ImmutableMap rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0",
+ primaryHardware,
+ "1",
+ primaryHardware,
+ "2",
+ primarySoftware,
+ "3",
+ fallbackHardware);
+ RendererCapabilities rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_VIDEO, rendererCapabilitiesMap);
+ TrackSelectorResult result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 1, 0);
+
+ // Select all tracks supported by primary, software decoder by default if no primary, hardware
+ // decoder is available.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0",
+ fallbackHardware,
+ "1",
+ fallbackHardware,
+ "2",
+ primarySoftware,
+ "3",
+ fallbackSoftware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_VIDEO, rendererCapabilitiesMap);
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertFixedSelection(result.selections[0], trackGroups.get(0), 2);
+
+ // Select all tracks supported by fallback, hardware decoder if no primary decoder is
+ // available.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0", fallbackHardware, "1", unsupported, "2", fallbackSoftware, "3", fallbackHardware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_VIDEO, rendererCapabilitiesMap);
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 3, 0);
+
+ // Select all tracks supported by fallback, software decoder if no other decoder is available.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0", fallbackSoftware, "1", fallbackSoftware, "2", unsupported, "3", fallbackSoftware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_VIDEO, rendererCapabilitiesMap);
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 3, 1, 0);
+
+ // Select all tracks if mixed decoder support is allowed.
+ rendererCapabilitiesMap =
+ ImmutableMap.of(
+ "0", primaryHardware, "1", unsupported, "2", primarySoftware, "3", fallbackHardware);
+ rendererCapabilities =
+ new FakeMappedRendererCapabilities(C.TRACK_TYPE_VIDEO, rendererCapabilitiesMap);
+ trackSelector.setParameters(
+ defaultParameters.buildUpon().setAllowVideoMixedDecoderSupportAdaptiveness(true));
+ result =
+ trackSelector.selectTracks(
+ new RendererCapabilities[] {rendererCapabilities}, trackGroups, periodId, TIMELINE);
+ assertAdaptiveSelection(result.selections[0], trackGroups.get(0), 3, 2, 0);
+ }
+
@Test
public void selectTracksWithMultipleVideoTracksOverrideReturnsAdaptiveTrackSelection()
throws Exception {
@@ -1859,11 +2096,17 @@ public final class DefaultTrackSelectorTest {
throws Exception {
Format formatAv1 = new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_AV1).build();
Format formatVp9 = new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_VP9).build();
- Format formatH264 = new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).build();
- TrackGroupArray trackGroups = wrapFormats(formatAv1, formatVp9, formatH264);
+ Format formatH264Low =
+ new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).setAverageBitrate(400).build();
+ Format formatH264High =
+ new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_H264).setAverageBitrate(800).build();
+ // Use an adaptive group to check that MIME type has a higher priority than number of tracks.
+ TrackGroup adaptiveGroup = new TrackGroup(formatH264Low, formatH264High);
+ TrackGroupArray trackGroups =
+ new TrackGroupArray(new TrackGroup(formatAv1), new TrackGroup(formatVp9), adaptiveGroup);
trackSelector.setParameters(
- trackSelector.buildUponParameters().setPreferredVideoMimeType(MimeTypes.VIDEO_VP9));
+ defaultParameters.buildUpon().setPreferredVideoMimeType(MimeTypes.VIDEO_VP9));
TrackSelectorResult result =
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
@@ -1871,8 +2114,8 @@ public final class DefaultTrackSelectorTest {
assertFixedSelection(result.selections[0], trackGroups, formatVp9);
trackSelector.setParameters(
- trackSelector
- .buildUponParameters()
+ defaultParameters
+ .buildUpon()
.setPreferredVideoMimeTypes(MimeTypes.VIDEO_VP9, MimeTypes.VIDEO_AV1));
result =
trackSelector.selectTracks(
@@ -1881,23 +2124,22 @@ public final class DefaultTrackSelectorTest {
assertFixedSelection(result.selections[0], trackGroups, formatVp9);
trackSelector.setParameters(
- trackSelector
- .buildUponParameters()
+ defaultParameters
+ .buildUpon()
.setPreferredVideoMimeTypes(MimeTypes.VIDEO_DIVX, MimeTypes.VIDEO_H264));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
- assertFixedSelection(result.selections[0], trackGroups, formatH264);
+ assertAdaptiveSelection(result.selections[0], adaptiveGroup, /* expectedTracks...= */ 1, 0);
- // Select first in the list if no preference is specified.
- trackSelector.setParameters(
- trackSelector.buildUponParameters().setPreferredVideoMimeType(null));
+ // Select default (=most tracks) if no preference is specified.
+ trackSelector.setParameters(defaultParameters.buildUpon().setPreferredVideoMimeType(null));
result =
trackSelector.selectTracks(
new RendererCapabilities[] {VIDEO_CAPABILITIES}, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(1);
- assertFixedSelection(result.selections[0], trackGroups, formatAv1);
+ assertAdaptiveSelection(result.selections[0], adaptiveGroup, /* expectedTracks...= */ 1, 0);
}
/**
@@ -1907,13 +2149,18 @@ public final class DefaultTrackSelectorTest {
@Test
public void selectTracks_withPreferredVideoRoleFlags_selectPreferredTrack() throws Exception {
Format.Builder formatBuilder = VIDEO_FORMAT.buildUpon();
- Format noRoleFlags = formatBuilder.build();
+ Format noRoleFlagsLow = formatBuilder.setAverageBitrate(4000).build();
+ Format noRoleFlagsHigh = formatBuilder.setAverageBitrate(8000).build();
Format lessRoleFlags = formatBuilder.setRoleFlags(C.ROLE_FLAG_CAPTION).build();
Format moreRoleFlags =
formatBuilder
.setRoleFlags(C.ROLE_FLAG_CAPTION | C.ROLE_FLAG_COMMENTARY | C.ROLE_FLAG_DUB)
.build();
- TrackGroupArray trackGroups = wrapFormats(noRoleFlags, moreRoleFlags, lessRoleFlags);
+ // Use an adaptive group to check that role flags have higher priority than number of tracks.
+ TrackGroup adaptiveNoRoleFlagsGroup = new TrackGroup(noRoleFlagsLow, noRoleFlagsHigh);
+ TrackGroupArray trackGroups =
+ new TrackGroupArray(
+ adaptiveNoRoleFlagsGroup, new TrackGroup(moreRoleFlags), new TrackGroup(lessRoleFlags));
trackSelector.setParameters(
defaultParameters
@@ -2109,6 +2356,7 @@ public final class DefaultTrackSelectorTest {
.setExceedVideoConstraintsIfNecessary(false)
.setAllowVideoMixedMimeTypeAdaptiveness(true)
.setAllowVideoNonSeamlessAdaptiveness(false)
+ .setAllowVideoMixedDecoderSupportAdaptiveness(true)
.setViewportSize(
/* viewportWidth= */ 8,
/* viewportHeight= */ 9,
@@ -2123,6 +2371,7 @@ public final class DefaultTrackSelectorTest {
.setAllowAudioMixedMimeTypeAdaptiveness(true)
.setAllowAudioMixedSampleRateAdaptiveness(false)
.setAllowAudioMixedChannelCountAdaptiveness(true)
+ .setAllowAudioMixedDecoderSupportAdaptiveness(false)
.setPreferredAudioMimeTypes(MimeTypes.AUDIO_AC3, MimeTypes.AUDIO_E_AC3)
// Text
.setPreferredTextLanguages("de", "en")
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.java
index e2110a7c10..1cf34b8f42 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionList.java
@@ -66,7 +66,9 @@ public final class BaseUrlExclusionList {
public void exclude(BaseUrl baseUrlToExclude, long exclusionDurationMs) {
long excludeUntilMs = SystemClock.elapsedRealtime() + exclusionDurationMs;
addExclusion(baseUrlToExclude.serviceLocation, excludeUntilMs, excludedServiceLocations);
- addExclusion(baseUrlToExclude.priority, excludeUntilMs, excludedPriorities);
+ if (baseUrlToExclude.priority != BaseUrl.PRIORITY_UNSET) {
+ addExclusion(baseUrlToExclude.priority, excludeUntilMs, excludedPriorities);
+ }
}
/**
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
index aaca62086a..0bdc49d76d 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java
@@ -217,7 +217,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
periodDurationUs,
representation,
selectedBaseUrl != null ? selectedBaseUrl : representation.baseUrls.get(0),
- BundledChunkExtractor.FACTORY.createProgressiveMediaExtractor(
+ chunkExtractorFactory.createProgressiveMediaExtractor(
trackType,
representation.format,
enableEventMessageTrack,
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/BaseUrl.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/BaseUrl.java
index 1792afd905..5cf79e7fc4 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/BaseUrl.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/BaseUrl.java
@@ -21,10 +21,12 @@ import com.google.common.base.Objects;
/** A base URL, as defined by ISO 23009-1, 2nd edition, 5.6. and ETSI TS 103 285 V1.2.1, 10.8.2.1 */
public final class BaseUrl {
- /** The default priority. */
- public static final int DEFAULT_PRIORITY = 1;
/** The default weight. */
public static final int DEFAULT_WEIGHT = 1;
+ /** The default priority. */
+ public static final int DEFAULT_DVB_PRIORITY = 1;
+ /** Constant representing an unset priority in a manifest that does not declare a DVB profile. */
+ public static final int PRIORITY_UNSET = Integer.MIN_VALUE;
/** The URL. */
public final String url;
@@ -36,11 +38,11 @@ public final class BaseUrl {
public final int weight;
/**
- * Creates an instance with {@link #DEFAULT_PRIORITY default priority}, {@link #DEFAULT_WEIGHT
+ * Creates an instance with {@link #PRIORITY_UNSET an unset priority}, {@link #DEFAULT_WEIGHT
* default weight} and using the URL as the service location.
*/
public BaseUrl(String url) {
- this(url, /* serviceLocation= */ url, DEFAULT_PRIORITY, DEFAULT_WEIGHT);
+ this(url, /* serviceLocation= */ url, PRIORITY_UNSET, DEFAULT_WEIGHT);
}
/** Creates an instance. */
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
index e0d7e2c43a..867018d33c 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java
@@ -15,6 +15,10 @@
*/
package com.google.android.exoplayer2.source.dash.manifest;
+import static com.google.android.exoplayer2.source.dash.manifest.BaseUrl.DEFAULT_DVB_PRIORITY;
+import static com.google.android.exoplayer2.source.dash.manifest.BaseUrl.DEFAULT_WEIGHT;
+import static com.google.android.exoplayer2.source.dash.manifest.BaseUrl.PRIORITY_UNSET;
+
import android.net.Uri;
import android.text.TextUtils;
import android.util.Base64;
@@ -103,14 +107,16 @@ public class DashManifestParser extends DefaultHandler
"inputStream does not contain a valid media presentation description",
/* cause= */ null);
}
- return parseMediaPresentationDescription(xpp, new BaseUrl(uri.toString()));
+ return parseMediaPresentationDescription(xpp, uri);
} catch (XmlPullParserException e) {
throw ParserException.createForMalformedManifest(/* message= */ null, /* cause= */ e);
}
}
- protected DashManifest parseMediaPresentationDescription(
- XmlPullParser xpp, BaseUrl documentBaseUrl) throws XmlPullParserException, IOException {
+ protected DashManifest parseMediaPresentationDescription(XmlPullParser xpp, Uri documentBaseUri)
+ throws XmlPullParserException, IOException {
+ boolean dvbProfileDeclared =
+ isDvbProfileDeclared(parseProfiles(xpp, "profiles", new String[0]));
long availabilityStartTime = parseDateTime(xpp, "availabilityStartTime", C.TIME_UNSET);
long durationMs = parseDuration(xpp, "mediaPresentationDuration", C.TIME_UNSET);
long minBufferTimeMs = parseDuration(xpp, "minBufferTime", C.TIME_UNSET);
@@ -128,6 +134,12 @@ public class DashManifestParser extends DefaultHandler
Uri location = null;
ServiceDescriptionElement serviceDescription = null;
long baseUrlAvailabilityTimeOffsetUs = dynamic ? 0 : C.TIME_UNSET;
+ BaseUrl documentBaseUrl =
+ new BaseUrl(
+ documentBaseUri.toString(),
+ /* serviceLocation= */ documentBaseUri.toString(),
+ dvbProfileDeclared ? DEFAULT_DVB_PRIORITY : PRIORITY_UNSET,
+ DEFAULT_WEIGHT);
ArrayList parentBaseUrls = Lists.newArrayList(documentBaseUrl);
List periods = new ArrayList<>();
@@ -143,7 +155,7 @@ public class DashManifestParser extends DefaultHandler
parseAvailabilityTimeOffsetUs(xpp, baseUrlAvailabilityTimeOffsetUs);
seenFirstBaseUrl = true;
}
- baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls));
+ baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls, dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "ProgramInformation")) {
programInformation = parseProgramInformation(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "UTCTiming")) {
@@ -160,7 +172,8 @@ public class DashManifestParser extends DefaultHandler
nextPeriodStartMs,
baseUrlAvailabilityTimeOffsetUs,
availabilityStartTime,
- timeShiftBufferDepthMs);
+ timeShiftBufferDepthMs,
+ dvbProfileDeclared);
Period period = periodWithDurationMs.first;
if (period.startMs == C.TIME_UNSET) {
if (dynamic) {
@@ -280,7 +293,8 @@ public class DashManifestParser extends DefaultHandler
long defaultStartMs,
long baseUrlAvailabilityTimeOffsetUs,
long availabilityStartTimeMs,
- long timeShiftBufferDepthMs)
+ long timeShiftBufferDepthMs,
+ boolean dvbProfileDeclared)
throws XmlPullParserException, IOException {
@Nullable String id = xpp.getAttributeValue(null, "id");
long startMs = parseDuration(xpp, "start", defaultStartMs);
@@ -302,7 +316,7 @@ public class DashManifestParser extends DefaultHandler
parseAvailabilityTimeOffsetUs(xpp, baseUrlAvailabilityTimeOffsetUs);
seenFirstBaseUrl = true;
}
- baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls));
+ baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls, dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "AdaptationSet")) {
adaptationSets.add(
parseAdaptationSet(
@@ -313,7 +327,8 @@ public class DashManifestParser extends DefaultHandler
baseUrlAvailabilityTimeOffsetUs,
segmentBaseAvailabilityTimeOffsetUs,
periodStartUnixTimeMs,
- timeShiftBufferDepthMs));
+ timeShiftBufferDepthMs,
+ dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "EventStream")) {
eventStreams.add(parseEventStream(xpp));
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
@@ -373,7 +388,8 @@ public class DashManifestParser extends DefaultHandler
long baseUrlAvailabilityTimeOffsetUs,
long segmentBaseAvailabilityTimeOffsetUs,
long periodStartUnixTimeMs,
- long timeShiftBufferDepthMs)
+ long timeShiftBufferDepthMs,
+ boolean dvbProfileDeclared)
throws XmlPullParserException, IOException {
int id = parseInt(xpp, "id", AdaptationSet.ID_UNSET);
@C.TrackType int contentType = parseContentType(xpp);
@@ -406,7 +422,7 @@ public class DashManifestParser extends DefaultHandler
parseAvailabilityTimeOffsetUs(xpp, baseUrlAvailabilityTimeOffsetUs);
seenFirstBaseUrl = true;
}
- baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls));
+ baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls, dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
Pair contentProtection = parseContentProtection(xpp);
if (contentProtection.first != null) {
@@ -450,7 +466,8 @@ public class DashManifestParser extends DefaultHandler
periodDurationMs,
baseUrlAvailabilityTimeOffsetUs,
segmentBaseAvailabilityTimeOffsetUs,
- timeShiftBufferDepthMs);
+ timeShiftBufferDepthMs,
+ dvbProfileDeclared);
contentType =
checkContentTypeConsistency(
contentType, MimeTypes.getTrackType(representationInfo.format.sampleMimeType));
@@ -650,7 +667,8 @@ public class DashManifestParser extends DefaultHandler
long periodDurationMs,
long baseUrlAvailabilityTimeOffsetUs,
long segmentBaseAvailabilityTimeOffsetUs,
- long timeShiftBufferDepthMs)
+ long timeShiftBufferDepthMs,
+ boolean dvbProfileDeclared)
throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
@@ -679,7 +697,7 @@ public class DashManifestParser extends DefaultHandler
parseAvailabilityTimeOffsetUs(xpp, baseUrlAvailabilityTimeOffsetUs);
seenFirstBaseUrl = true;
}
- baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls));
+ baseUrls.addAll(parseBaseUrl(xpp, parentBaseUrls, dvbProfileDeclared));
} else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
audioChannels = parseAudioChannelConfiguration(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
@@ -1371,35 +1389,42 @@ public class DashManifestParser extends DefaultHandler
*
* @param xpp The parser from which to read.
* @param parentBaseUrls The parent base URLs for resolving the parsed URLs.
+ * @param dvbProfileDeclared Whether the dvb profile is declared.
* @throws XmlPullParserException If an error occurs parsing the element.
* @throws IOException If an error occurs reading the element.
* @return The list of parsed and resolved URLs.
*/
- protected List parseBaseUrl(XmlPullParser xpp, List parentBaseUrls)
+ protected List parseBaseUrl(
+ XmlPullParser xpp, List parentBaseUrls, boolean dvbProfileDeclared)
throws XmlPullParserException, IOException {
@Nullable String priorityValue = xpp.getAttributeValue(null, "dvb:priority");
int priority =
- priorityValue != null ? Integer.parseInt(priorityValue) : BaseUrl.DEFAULT_PRIORITY;
+ priorityValue != null
+ ? Integer.parseInt(priorityValue)
+ : (dvbProfileDeclared ? DEFAULT_DVB_PRIORITY : PRIORITY_UNSET);
@Nullable String weightValue = xpp.getAttributeValue(null, "dvb:weight");
- int weight = weightValue != null ? Integer.parseInt(weightValue) : BaseUrl.DEFAULT_WEIGHT;
+ int weight = weightValue != null ? Integer.parseInt(weightValue) : DEFAULT_WEIGHT;
@Nullable String serviceLocation = xpp.getAttributeValue(null, "serviceLocation");
String baseUrl = parseText(xpp, "BaseURL");
- if (serviceLocation == null) {
- serviceLocation = baseUrl;
- }
if (UriUtil.isAbsolute(baseUrl)) {
+ if (serviceLocation == null) {
+ serviceLocation = baseUrl;
+ }
return Lists.newArrayList(new BaseUrl(baseUrl, serviceLocation, priority, weight));
}
List baseUrls = new ArrayList<>();
for (int i = 0; i < parentBaseUrls.size(); i++) {
BaseUrl parentBaseUrl = parentBaseUrls.get(i);
- priority = parentBaseUrl.priority;
- weight = parentBaseUrl.weight;
- serviceLocation = parentBaseUrl.serviceLocation;
- baseUrls.add(
- new BaseUrl(
- UriUtil.resolve(parentBaseUrl.url, baseUrl), serviceLocation, priority, weight));
+ String resolvedBaseUri = UriUtil.resolve(parentBaseUrl.url, baseUrl);
+ String resolvedServiceLocation = serviceLocation == null ? resolvedBaseUri : serviceLocation;
+ if (dvbProfileDeclared) {
+ // Inherit parent properties only if dvb profile is declared.
+ priority = parentBaseUrl.priority;
+ weight = parentBaseUrl.weight;
+ resolvedServiceLocation = parentBaseUrl.serviceLocation;
+ }
+ baseUrls.add(new BaseUrl(resolvedBaseUri, resolvedServiceLocation, priority, weight));
}
return baseUrls;
}
@@ -1581,6 +1606,14 @@ public class DashManifestParser extends DefaultHandler
}
}
+ protected String[] parseProfiles(XmlPullParser xpp, String attributeName, String[] defaultValue) {
+ @Nullable String attributeValue = xpp.getAttributeValue(/* namespace= */ null, attributeName);
+ if (attributeValue == null) {
+ return defaultValue;
+ }
+ return attributeValue.split(",");
+ }
+
// Utility methods.
/**
@@ -1907,6 +1940,15 @@ public class DashManifestParser extends DefaultHandler
return availabilityTimeOffsetUs;
}
+ private boolean isDvbProfileDeclared(String[] profiles) {
+ for (String profile : profiles) {
+ if (profile.startsWith("urn:dvb:dash:profile:dvb-dash:")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/** A parsed Representation element. */
protected static final class RepresentationInfo {
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java
index 1e02e9cd62..62787cee4c 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/Representation.java
@@ -213,7 +213,7 @@ public abstract class Representation {
new RangedUri(null, initializationStart, initializationEnd - initializationStart + 1);
SingleSegmentBase segmentBase =
new SingleSegmentBase(rangedUri, 1, 0, indexStart, indexEnd - indexStart + 1);
- List baseUrls = ImmutableList.of(new BaseUrl(uri));
+ ImmutableList baseUrls = ImmutableList.of(new BaseUrl(uri));
return new SingleSegmentRepresentation(
revisionId,
format,
diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionListTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionListTest.java
index cb75903c81..22391608be 100644
--- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionListTest.java
+++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/BaseUrlExclusionListTest.java
@@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.source.dash;
+import static com.google.android.exoplayer2.source.dash.manifest.BaseUrl.DEFAULT_DVB_PRIORITY;
+import static com.google.android.exoplayer2.source.dash.manifest.BaseUrl.DEFAULT_WEIGHT;
import static com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy.DEFAULT_LOCATION_EXCLUSION_MS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -173,6 +175,32 @@ public class BaseUrlExclusionListTest {
assertThat(baseUrlExclusionList.getPriorityCountAfterExclusion(baseUrls)).isEqualTo(2);
}
+ @Test
+ public void selectBaseUrl_priorityUnset_isNotExcluded() {
+ BaseUrlExclusionList baseUrlExclusionList = new BaseUrlExclusionList();
+ ImmutableList baseUrls =
+ ImmutableList.of(
+ new BaseUrl(
+ /* url= */ "a-1",
+ /* serviceLocation= */ "a",
+ BaseUrl.PRIORITY_UNSET,
+ /* weight= */ 1),
+ new BaseUrl(
+ /* url= */ "a-2",
+ /* serviceLocation= */ "a",
+ BaseUrl.PRIORITY_UNSET,
+ /* weight= */ 1),
+ new BaseUrl(
+ /* url= */ "b",
+ /* serviceLocation= */ "b",
+ BaseUrl.PRIORITY_UNSET,
+ /* weight= */ 1));
+
+ baseUrlExclusionList.exclude(baseUrls.get(0), 10_000);
+
+ assertThat(baseUrlExclusionList.selectBaseUrl(baseUrls).serviceLocation).isEqualTo("b");
+ }
+
@Test
public void selectBaseUrl_emptyBaseUrlList_selectionIsNull() {
BaseUrlExclusionList baseUrlExclusionList = new BaseUrlExclusionList();
@@ -183,7 +211,8 @@ public class BaseUrlExclusionListTest {
@Test
public void reset_dropsAllExclusions() {
BaseUrlExclusionList baseUrlExclusionList = new BaseUrlExclusionList();
- List baseUrls = ImmutableList.of(new BaseUrl("a"));
+ ImmutableList baseUrls =
+ ImmutableList.of(new BaseUrl("a", "a", DEFAULT_DVB_PRIORITY, DEFAULT_WEIGHT));
baseUrlExclusionList.exclude(baseUrls.get(0), 5000);
baseUrlExclusionList.reset();
diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
index 6516f9d71a..3a2ce9a309 100644
--- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
+++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java
@@ -61,6 +61,10 @@ public class DashManifestParserTest {
"media/mpd/sample_mpd_availabilityTimeOffset_baseUrl";
private static final String SAMPLE_MPD_MULTIPLE_BASE_URLS =
"media/mpd/sample_mpd_multiple_baseUrls";
+ private static final String SAMPLE_MPD_RELATIVE_BASE_URLS_DVB_PROFILE_NOT_DECLARED =
+ "media/mpd/sample_mpd_relative_baseUrls_dvb_profile_not_declared";
+ private static final String SAMPLE_MPD_RELATIVE_BASE_URLS_DVB_PROFILE_DECLARED =
+ "media/mpd/sample_mpd_relative_baseUrls_dvb_profile_declared";
private static final String SAMPLE_MPD_AVAILABILITY_TIME_OFFSET_SEGMENT_TEMPLATE =
"media/mpd/sample_mpd_availabilityTimeOffset_segmentTemplate";
private static final String SAMPLE_MPD_AVAILABILITY_TIME_OFFSET_SEGMENT_LIST =
@@ -748,6 +752,41 @@ public class DashManifestParserTest {
assertThat(textBaseUrls.get(0).serviceLocation).isEqualTo("e");
}
+ @Test
+ public void baseUrl_relativeBaseUrlsNoDvbNamespace_hasDifferentPrioritiesAndServiceLocation()
+ throws IOException {
+ DashManifestParser parser = new DashManifestParser();
+ DashManifest manifest =
+ parser.parse(
+ Uri.parse("https://example.com/test.mpd"),
+ TestUtil.getInputStream(
+ ApplicationProvider.getApplicationContext(),
+ SAMPLE_MPD_RELATIVE_BASE_URLS_DVB_PROFILE_NOT_DECLARED));
+
+ ImmutableList baseUrls =
+ manifest.getPeriod(0).adaptationSets.get(0).representations.get(0).baseUrls;
+ assertThat(baseUrls.get(0).priority).isEqualTo(BaseUrl.PRIORITY_UNSET);
+ assertThat(baseUrls.get(1).priority).isEqualTo(BaseUrl.PRIORITY_UNSET);
+ assertThat(baseUrls.get(0).serviceLocation).isNotEqualTo(baseUrls.get(1).serviceLocation);
+ }
+
+ @Test
+ public void baseUrl_relativeBaseUrlsWithDvbNamespace_inheritsPrioritiesAndServiceLocation()
+ throws IOException {
+ DashManifestParser parser = new DashManifestParser();
+ DashManifest manifest =
+ parser.parse(
+ Uri.parse("https://example.com/test.mpd"),
+ TestUtil.getInputStream(
+ ApplicationProvider.getApplicationContext(),
+ SAMPLE_MPD_RELATIVE_BASE_URLS_DVB_PROFILE_DECLARED));
+
+ ImmutableList baseUrls =
+ manifest.getPeriod(0).adaptationSets.get(0).representations.get(0).baseUrls;
+ assertThat(baseUrls.get(0).priority).isEqualTo(baseUrls.get(1).priority);
+ assertThat(baseUrls.get(0).serviceLocation).isEqualTo(baseUrls.get(1).serviceLocation);
+ }
+
@Test
public void serviceDescriptionElement_allValuesSet() throws IOException {
DashManifestParser parser = new DashManifestParser();
diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java
index 6bdc84438b..28f40c8506 100644
--- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java
+++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java
@@ -109,8 +109,7 @@ public class DownloadManagerDashTest {
testThread.release();
}
- // Disabled due to flakiness.
- @Ignore
+ @Ignore("Disabled due to flakiness")
@Test
public void saveAndLoadActionFile() throws Throwable {
// Configure fakeDataSet to block until interrupted when TEST_MPD is read.
diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java
index e8a71798be..b50d25414d 100644
--- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java
+++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java
@@ -157,7 +157,7 @@ public class DownloadServiceDashTest {
testThread.release();
}
- @Ignore // b/78877092
+ @Ignore("Internal ref: b/78877092")
@Test
public void multipleDownloadRequest() throws Throwable {
downloadKeys(fakeStreamKey1);
@@ -168,7 +168,7 @@ public class DownloadServiceDashTest {
assertCachedData(cache, fakeDataSet);
}
- @Ignore // b/78877092
+ @Ignore("Internal ref: b/78877092")
@Test
public void removeAction() throws Throwable {
downloadKeys(fakeStreamKey1, fakeStreamKey2);
@@ -182,7 +182,7 @@ public class DownloadServiceDashTest {
assertCacheEmpty(cache);
}
- @Ignore // b/78877092
+ @Ignore("Internal ref: b/78877092")
@Test
public void removeBeforeDownloadComplete() throws Throwable {
pauseDownloadCondition = new ConditionVariable();
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java
index fdb36a2771..5d528dbb6f 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacMetadataReader.java
@@ -24,10 +24,9 @@ import com.google.android.exoplayer2.metadata.flac.PictureFrame;
import com.google.android.exoplayer2.metadata.id3.Id3Decoder;
import com.google.android.exoplayer2.util.ParsableBitArray;
import com.google.android.exoplayer2.util.ParsableByteArray;
-import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
/**
@@ -168,9 +167,12 @@ public final class FlacMetadataReader {
metadataHolder.flacStreamMetadata =
flacStreamMetadata.copyWithVorbisComments(vorbisComments);
} else if (type == FlacConstants.METADATA_TYPE_PICTURE) {
- PictureFrame pictureFrame = readPictureMetadataBlock(input, length);
+ ParsableByteArray pictureBlock = new ParsableByteArray(length);
+ input.readFully(pictureBlock.getData(), 0, length);
+ pictureBlock.skipBytes(FlacConstants.METADATA_BLOCK_HEADER_SIZE);
+ PictureFrame pictureFrame = PictureFrame.fromPictureBlock(pictureBlock);
metadataHolder.flacStreamMetadata =
- flacStreamMetadata.copyWithPictureFrames(Collections.singletonList(pictureFrame));
+ flacStreamMetadata.copyWithPictureFrames(ImmutableList.of(pictureFrame));
} else {
input.skipFully(length);
}
@@ -268,28 +270,5 @@ public final class FlacMetadataReader {
return Arrays.asList(commentHeader.comments);
}
- private static PictureFrame readPictureMetadataBlock(ExtractorInput input, int length)
- throws IOException {
- ParsableByteArray scratch = new ParsableByteArray(length);
- input.readFully(scratch.getData(), 0, length);
- scratch.skipBytes(FlacConstants.METADATA_BLOCK_HEADER_SIZE);
-
- int pictureType = scratch.readInt();
- int mimeTypeLength = scratch.readInt();
- String mimeType = scratch.readString(mimeTypeLength, Charsets.US_ASCII);
- int descriptionLength = scratch.readInt();
- String description = scratch.readString(descriptionLength);
- int width = scratch.readInt();
- int height = scratch.readInt();
- int depth = scratch.readInt();
- int colors = scratch.readInt();
- int pictureDataLength = scratch.readInt();
- byte[] pictureData = new byte[pictureDataLength];
- scratch.readBytes(pictureData, 0, pictureDataLength);
-
- return new PictureFrame(
- pictureType, mimeType, description, width, height, depth, colors, pictureData);
- }
-
private FlacMetadataReader() {}
}
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacStreamMetadata.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacStreamMetadata.java
index a4a2b64cb9..48e521b413 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacStreamMetadata.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/FlacStreamMetadata.java
@@ -15,13 +15,13 @@
*/
package com.google.android.exoplayer2.extractor;
+import static com.google.android.exoplayer2.extractor.VorbisUtil.parseVorbisComments;
+
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.flac.PictureFrame;
-import com.google.android.exoplayer2.metadata.flac.VorbisComment;
-import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableBitArray;
import com.google.android.exoplayer2.util.Util;
@@ -60,8 +60,6 @@ public final class FlacStreamMetadata {
/** Indicates that a value is not in the corresponding lookup table. */
public static final int NOT_IN_LOOKUP_TABLE = -1;
- /** Separator between the field name of a Vorbis comment and the corresponding value. */
- private static final String SEPARATOR = "=";
/** Minimum number of samples per block. */
public final int minBlockSizeSamples;
@@ -149,7 +147,7 @@ public final class FlacStreamMetadata {
bitsPerSample,
totalSamples,
/* seekTable= */ null,
- buildMetadata(vorbisComments, pictureFrames));
+ concatenateVorbisMetadata(vorbisComments, pictureFrames));
}
private FlacStreamMetadata(
@@ -274,8 +272,7 @@ public final class FlacStreamMetadata {
public FlacStreamMetadata copyWithVorbisComments(List vorbisComments) {
@Nullable
Metadata appendedMetadata =
- getMetadataCopyWithAppendedEntriesFrom(
- buildMetadata(vorbisComments, Collections.emptyList()));
+ getMetadataCopyWithAppendedEntriesFrom(parseVorbisComments(vorbisComments));
return new FlacStreamMetadata(
minBlockSizeSamples,
maxBlockSizeSamples,
@@ -292,9 +289,7 @@ public final class FlacStreamMetadata {
/** Returns a copy of {@code this} with the given picture frames added to the metadata. */
public FlacStreamMetadata copyWithPictureFrames(List pictureFrames) {
@Nullable
- Metadata appendedMetadata =
- getMetadataCopyWithAppendedEntriesFrom(
- buildMetadata(Collections.emptyList(), pictureFrames));
+ Metadata appendedMetadata = getMetadataCopyWithAppendedEntriesFrom(new Metadata(pictureFrames));
return new FlacStreamMetadata(
minBlockSizeSamples,
maxBlockSizeSamples,
@@ -308,6 +303,20 @@ public final class FlacStreamMetadata {
appendedMetadata);
}
+ /**
+ * Returns a new {@link Metadata} instance created from {@code vorbisComments} and {@code
+ * pictureFrames}.
+ */
+ @Nullable
+ private static Metadata concatenateVorbisMetadata(
+ List vorbisComments, List pictureFrames) {
+ @Nullable Metadata parsedVorbisComments = parseVorbisComments(vorbisComments);
+ if (parsedVorbisComments == null && pictureFrames.isEmpty()) {
+ return null;
+ }
+ return new Metadata(pictureFrames).copyWithAppendedEntriesFrom(parsedVorbisComments);
+ }
+
private static int getSampleRateLookupKey(int sampleRate) {
switch (sampleRate) {
case 88200:
@@ -353,27 +362,4 @@ public final class FlacStreamMetadata {
return NOT_IN_LOOKUP_TABLE;
}
}
-
- @Nullable
- private static Metadata buildMetadata(
- List vorbisComments, List pictureFrames) {
- if (vorbisComments.isEmpty() && pictureFrames.isEmpty()) {
- return null;
- }
-
- ArrayList metadataEntries = new ArrayList<>();
- for (int i = 0; i < vorbisComments.size(); i++) {
- String vorbisComment = vorbisComments.get(i);
- String[] keyAndValue = Util.splitAtFirst(vorbisComment, SEPARATOR);
- if (keyAndValue.length != 2) {
- Log.w(TAG, "Failed to parse Vorbis comment: " + vorbisComment);
- } else {
- VorbisComment entry = new VorbisComment(keyAndValue[0], keyAndValue[1]);
- metadataEntries.add(entry);
- }
- }
- metadataEntries.addAll(pictureFrames);
-
- return metadataEntries.isEmpty() ? null : new Metadata(metadataEntries);
- }
}
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java
index 5fbd0e4ae4..ed02771fe5 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/VorbisUtil.java
@@ -15,11 +15,20 @@
*/
package com.google.android.exoplayer2.extractor;
+import android.util.Base64;
+import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
+import com.google.android.exoplayer2.metadata.Metadata;
+import com.google.android.exoplayer2.metadata.Metadata.Entry;
+import com.google.android.exoplayer2.metadata.flac.PictureFrame;
+import com.google.android.exoplayer2.metadata.vorbis.VorbisComment;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.ParsableByteArray;
+import com.google.android.exoplayer2.util.Util;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/** Utility methods for parsing Vorbis streams. */
public final class VorbisUtil {
@@ -248,6 +257,45 @@ public final class VorbisUtil {
return new CommentHeader(vendor, comments, length);
}
+ /**
+ * Builds a {@link Metadata} instance from a list of Vorbis Comments.
+ *
+ * METADATA_BLOCK_PICTURE comments will be transformed into {@link PictureFrame} entries. All
+ * others will be transformed into {@link VorbisComment} entries.
+ *
+ * @param vorbisComments The raw input of comments, as a key-value pair KEY=VAL.
+ * @return The fully parsed Metadata instance. Null if no vorbis comments could be parsed.
+ */
+ @Nullable
+ public static Metadata parseVorbisComments(List vorbisComments) {
+ List metadataEntries = new ArrayList<>();
+ for (int i = 0; i < vorbisComments.size(); i++) {
+ String vorbisComment = vorbisComments.get(i);
+ String[] keyAndValue = Util.splitAtFirst(vorbisComment, "=");
+ if (keyAndValue.length != 2) {
+ Log.w(TAG, "Failed to parse Vorbis comment: " + vorbisComment);
+ continue;
+ }
+
+ if (keyAndValue[0].equals("METADATA_BLOCK_PICTURE")) {
+ // This tag is a special cover art tag, outlined by
+ // https://wiki.xiph.org/index.php/VorbisComment#Cover_art.
+ // Decode it from Base64 and transform it into a PictureFrame.
+ try {
+ byte[] decoded = Base64.decode(keyAndValue[1], Base64.DEFAULT);
+ metadataEntries.add(PictureFrame.fromPictureBlock(new ParsableByteArray(decoded)));
+ } catch (RuntimeException e) {
+ Log.w(TAG, "Failed to parse vorbis picture", e);
+ }
+ } else {
+ VorbisComment entry = new VorbisComment(keyAndValue[0], keyAndValue[1]);
+ metadataEntries.add(entry);
+ }
+ }
+
+ return metadataEntries.isEmpty() ? null : new Metadata(metadataEntries);
+ }
+
/**
* Verifies whether the next bytes in {@code header} are a Vorbis header of the given {@code
* headerType}.
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java
index e8876ca52c..3659f2270e 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java
@@ -138,6 +138,7 @@ public class MatroskaExtractor implements Extractor {
private static final String CODEC_ID_PCM_FLOAT = "A_PCM/FLOAT/IEEE";
private static final String CODEC_ID_SUBRIP = "S_TEXT/UTF8";
private static final String CODEC_ID_ASS = "S_TEXT/ASS";
+ private static final String CODEC_ID_VTT = "S_TEXT/WEBVTT";
private static final String CODEC_ID_VOBSUB = "S_VOBSUB";
private static final String CODEC_ID_PGS = "S_HDMV/PGS";
private static final String CODEC_ID_DVBSUB = "S_DVBSUB";
@@ -323,6 +324,32 @@ public class MatroskaExtractor implements Extractor {
/** The format of an SSA timecode. */
private static final String SSA_TIMECODE_FORMAT = "%01d:%02d:%02d:%02d";
+ /**
+ * A template for the prefix that must be added to each VTT sample.
+ *
+ * The display time of each subtitle is passed as {@code timeUs} to {@link
+ * TrackOutput#sampleMetadata}. The start and end timecodes in this template are relative to
+ * {@code timeUs}. Hence the start timecode is always zero. The 12 byte end timecode starting at
+ * {@link #VTT_PREFIX_END_TIMECODE_OFFSET} is set to a placeholder value, and must be replaced
+ * with the duration of the subtitle.
+ *
+ *
Equivalent to the UTF-8 string: "WEBVTT\n\n00:00:00.000 --> 00:00:00.000\n".
+ */
+ private static final byte[] VTT_PREFIX =
+ new byte[] {
+ 87, 69, 66, 86, 84, 84, 10, 10, 48, 48, 58, 48, 48, 58, 48, 48, 46, 48, 48, 48, 32, 45, 45,
+ 62, 32, 48, 48, 58, 48, 48, 58, 48, 48, 46, 48, 48, 48, 10
+ };
+ /** The byte offset of the end timecode in {@link #VTT_PREFIX}. */
+ private static final int VTT_PREFIX_END_TIMECODE_OFFSET = 25;
+ /**
+ * The value by which to divide a time in microseconds to convert it to the unit of the last value
+ * in a VTT timecode (milliseconds).
+ */
+ private static final long VTT_TIMECODE_LAST_VALUE_SCALING_FACTOR = 1000;
+ /** The format of a VTT timecode. */
+ private static final String VTT_TIMECODE_FORMAT = "%02d:%02d:%02d.%03d";
+
/** The length in bytes of a WAVEFORMATEX structure. */
private static final int WAVE_FORMAT_SIZE = 18;
/** Format tag indicating a WAVEFORMATEXTENSIBLE structure. */
@@ -1342,7 +1369,9 @@ public class MatroskaExtractor implements Extractor {
track.trueHdSampleRechunker.sampleMetadata(
track.output, timeUs, flags, size, offset, track.cryptoData);
} else {
- if (CODEC_ID_SUBRIP.equals(track.codecId) || CODEC_ID_ASS.equals(track.codecId)) {
+ if (CODEC_ID_SUBRIP.equals(track.codecId)
+ || CODEC_ID_ASS.equals(track.codecId)
+ || CODEC_ID_VTT.equals(track.codecId)) {
if (blockSampleCount > 1) {
Log.w(TAG, "Skipping subtitle sample in laced block.");
} else if (blockDurationUs == C.TIME_UNSET) {
@@ -1415,6 +1444,9 @@ public class MatroskaExtractor implements Extractor {
} else if (CODEC_ID_ASS.equals(track.codecId)) {
writeSubtitleSampleData(input, SSA_PREFIX, size);
return finishWriteSampleData();
+ } else if (CODEC_ID_VTT.equals(track.codecId)) {
+ writeSubtitleSampleData(input, VTT_PREFIX, size);
+ return finishWriteSampleData();
}
TrackOutput output = track.output;
@@ -1641,7 +1673,8 @@ public class MatroskaExtractor implements Extractor {
*
See documentation on {@link #SSA_DIALOGUE_FORMAT} and {@link #SUBRIP_PREFIX} for why we use
* the duration as the end timecode.
*
- * @param codecId The subtitle codec; must be {@link #CODEC_ID_SUBRIP} or {@link #CODEC_ID_ASS}.
+ * @param codecId The subtitle codec; must be {@link #CODEC_ID_SUBRIP}, {@link #CODEC_ID_ASS} or
+ * {@link #CODEC_ID_VTT}.
* @param durationUs The duration of the sample, in microseconds.
* @param subtitleData The subtitle sample in which to overwrite the end timecode (output
* parameter).
@@ -1662,6 +1695,12 @@ public class MatroskaExtractor implements Extractor {
durationUs, SSA_TIMECODE_FORMAT, SSA_TIMECODE_LAST_VALUE_SCALING_FACTOR);
endTimecodeOffset = SSA_PREFIX_END_TIMECODE_OFFSET;
break;
+ case CODEC_ID_VTT:
+ endTimecode =
+ formatSubtitleTimecode(
+ durationUs, VTT_TIMECODE_FORMAT, VTT_TIMECODE_LAST_VALUE_SCALING_FACTOR);
+ endTimecodeOffset = VTT_PREFIX_END_TIMECODE_OFFSET;
+ break;
default:
throw new IllegalArgumentException();
}
@@ -1830,6 +1869,7 @@ public class MatroskaExtractor implements Extractor {
case CODEC_ID_PCM_FLOAT:
case CODEC_ID_SUBRIP:
case CODEC_ID_ASS:
+ case CODEC_ID_VTT:
case CODEC_ID_VOBSUB:
case CODEC_ID_PGS:
case CODEC_ID_DVBSUB:
@@ -2157,6 +2197,9 @@ public class MatroskaExtractor implements Extractor {
mimeType = MimeTypes.TEXT_SSA;
initializationData = ImmutableList.of(SSA_DIALOGUE_FORMAT, getCodecPrivate(codecId));
break;
+ case CODEC_ID_VTT:
+ mimeType = MimeTypes.TEXT_VTT;
+ break;
case CODEC_ID_VOBSUB:
mimeType = MimeTypes.APPLICATION_VOBSUB;
initializationData = ImmutableList.of(getCodecPrivate(codecId));
@@ -2245,6 +2288,7 @@ public class MatroskaExtractor implements Extractor {
.setColorInfo(colorInfo);
} else if (MimeTypes.APPLICATION_SUBRIP.equals(mimeType)
|| MimeTypes.TEXT_SSA.equals(mimeType)
+ || MimeTypes.TEXT_VTT.equals(mimeType)
|| MimeTypes.APPLICATION_VOBSUB.equals(mimeType)
|| MimeTypes.APPLICATION_PGS.equals(mimeType)
|| MimeTypes.APPLICATION_DVBSUBS.equals(mimeType)) {
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java
index 32791c33d5..e092d7001b 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/OpusReader.java
@@ -15,12 +15,18 @@
*/
package com.google.android.exoplayer2.extractor.ogg;
-import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
+import static com.google.android.exoplayer2.util.Assertions.checkState;
+import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
+import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.audio.OpusUtil;
+import com.google.android.exoplayer2.extractor.VorbisUtil;
+import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableByteArray;
+import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.List;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
@@ -28,26 +34,13 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
/** {@link StreamReader} to extract Opus data out of Ogg byte stream. */
/* package */ final class OpusReader extends StreamReader {
- private static final int OPUS_CODE = 0x4f707573;
- private static final byte[] OPUS_SIGNATURE = {'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'};
-
- private boolean headerRead;
+ private static final byte[] OPUS_ID_HEADER_SIGNATURE = {'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'};
+ private static final byte[] OPUS_COMMENT_HEADER_SIGNATURE = {
+ 'O', 'p', 'u', 's', 'T', 'a', 'g', 's'
+ };
public static boolean verifyBitstreamType(ParsableByteArray data) {
- if (data.bytesLeft() < OPUS_SIGNATURE.length) {
- return false;
- }
- byte[] header = new byte[OPUS_SIGNATURE.length];
- data.readBytes(header, 0, OPUS_SIGNATURE.length);
- return Arrays.equals(header, OPUS_SIGNATURE);
- }
-
- @Override
- protected void reset(boolean headerData) {
- super.reset(headerData);
- if (headerData) {
- headerRead = false;
- }
+ return peekPacketStartsWith(data, OPUS_ID_HEADER_SIGNATURE);
}
@Override
@@ -57,11 +50,16 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
@Override
@EnsuresNonNullIf(expression = "#3.format", result = false)
- protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData) {
- if (!headerRead) {
+ protected boolean readHeaders(ParsableByteArray packet, long position, SetupData setupData)
+ throws ParserException {
+ if (peekPacketStartsWith(packet, OPUS_ID_HEADER_SIGNATURE)) {
byte[] headerBytes = Arrays.copyOf(packet.getData(), packet.limit());
int channelCount = OpusUtil.getChannelCount(headerBytes);
List initializationData = OpusUtil.buildInitializationData(headerBytes);
+
+ // The ID header must come at the start of the file:
+ // https://datatracker.ietf.org/doc/html/rfc7845#section-3
+ checkState(setupData.format == null);
setupData.format =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_OPUS)
@@ -69,13 +67,33 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
.setSampleRate(OpusUtil.SAMPLE_RATE)
.setInitializationData(initializationData)
.build();
- headerRead = true;
+ return true;
+ } else if (peekPacketStartsWith(packet, OPUS_COMMENT_HEADER_SIGNATURE)) {
+ // The comment header must come immediately after the ID header, so the format will already
+ // be populated: https://datatracker.ietf.org/doc/html/rfc7845#section-3
+ checkStateNotNull(setupData.format);
+ packet.skipBytes(OPUS_COMMENT_HEADER_SIGNATURE.length);
+ VorbisUtil.CommentHeader commentHeader =
+ VorbisUtil.readVorbisCommentHeader(
+ packet, /* hasMetadataHeader= */ false, /* hasFramingBit= */ false);
+ @Nullable
+ Metadata vorbisMetadata =
+ VorbisUtil.parseVorbisComments(ImmutableList.copyOf(commentHeader.comments));
+ if (vorbisMetadata == null) {
+ return true;
+ }
+ setupData.format =
+ setupData
+ .format
+ .buildUpon()
+ .setMetadata(vorbisMetadata.copyWithAppendedEntriesFrom(setupData.format.metadata))
+ .build();
return true;
} else {
- checkNotNull(setupData.format); // Has been set when the header was read.
- boolean headerPacket = packet.readInt() == OPUS_CODE;
- packet.setPosition(0);
- return headerPacket;
+ // The ID header must come at the start of the file, so the format must already be populated:
+ // https://datatracker.ietf.org/doc/html/rfc7845#section-3
+ checkStateNotNull(setupData.format);
+ return false;
}
}
@@ -114,4 +132,22 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
}
return (long) frames * length;
}
+
+ /**
+ * Returns true if the given {@link ParsableByteArray} starts with {@code expectedPrefix}. Does
+ * not change the {@link ParsableByteArray#getPosition() position} of {@code packet}.
+ *
+ * @param packet The packet data.
+ * @return True if the packet starts with {@code expectedPrefix}, false if not.
+ */
+ private static boolean peekPacketStartsWith(ParsableByteArray packet, byte[] expectedPrefix) {
+ if (packet.bytesLeft() < expectedPrefix.length) {
+ return false;
+ }
+ int startPosition = packet.getPosition();
+ byte[] header = new byte[expectedPrefix.length];
+ packet.readBytes(header, 0, expectedPrefix.length);
+ packet.setPosition(startPosition);
+ return Arrays.equals(header, expectedPrefix);
+ }
}
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java
index 607bffe858..316543113c 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ogg/VorbisReader.java
@@ -24,8 +24,10 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.extractor.VorbisUtil;
import com.google.android.exoplayer2.extractor.VorbisUtil.Mode;
+import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableByteArray;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -111,6 +113,10 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
codecInitializationData.add(idHeader.data);
codecInitializationData.add(vorbisSetup.setupHeaderData);
+ @Nullable
+ Metadata metadata =
+ VorbisUtil.parseVorbisComments(ImmutableList.copyOf(vorbisSetup.commentHeader.comments));
+
setupData.format =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_VORBIS)
@@ -119,6 +125,7 @@ import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
.setChannelCount(idHeader.channels)
.setSampleRate(idHeader.sampleRate)
.setInitializationData(codecInitializationData)
+ .setMetadata(metadata)
.build();
return true;
}
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java
index 8d62be52c6..11fc1f24e5 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/PictureFrame.java
@@ -22,9 +22,11 @@ import android.os.Parcelable;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.metadata.Metadata;
+import com.google.android.exoplayer2.util.ParsableByteArray;
+import com.google.common.base.Charsets;
import java.util.Arrays;
-/** A picture parsed from a FLAC file. */
+/** A picture parsed from a Vorbis Comment or a FLAC picture block. */
public final class PictureFrame implements Metadata.Entry {
/** The type of the picture. */
@@ -134,6 +136,35 @@ public final class PictureFrame implements Metadata.Entry {
return 0;
}
+ /**
+ * Parses a {@code METADATA_BLOCK_PICTURE} into a {@code PictureFrame} instance.
+ *
+ * {@code pictureBlock} may be read directly from a FLAC file , or decoded from
+ * the base64 content of a Vorbis Comment .
+ *
+ * @param pictureBlock The data of the {@code METADATA_BLOCK_PICTURE}, not including any headers.
+ * @return A {@code PictureFrame} parsed from {@code pictureBlock}.
+ */
+ public static PictureFrame fromPictureBlock(ParsableByteArray pictureBlock) {
+ int pictureType = pictureBlock.readInt();
+ int mimeTypeLength = pictureBlock.readInt();
+ String mimeType = pictureBlock.readString(mimeTypeLength, Charsets.US_ASCII);
+ int descriptionLength = pictureBlock.readInt();
+ String description = pictureBlock.readString(descriptionLength);
+ int width = pictureBlock.readInt();
+ int height = pictureBlock.readInt();
+ int depth = pictureBlock.readInt();
+ int colors = pictureBlock.readInt();
+ int pictureDataLength = pictureBlock.readInt();
+ byte[] pictureData = new byte[pictureDataLength];
+ pictureBlock.readBytes(pictureData, 0, pictureDataLength);
+
+ return new PictureFrame(
+ pictureType, mimeType, description, width, height, depth, colors, pictureData);
+ }
+
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java
index 3ab60541a9..5829b0845a 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/flac/VorbisComment.java
@@ -23,8 +23,9 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.metadata.Metadata;
-/** A vorbis comment. */
-public final class VorbisComment implements Metadata.Entry {
+/** @deprecated Use {@link com.google.android.exoplayer2.metadata.vorbis.VorbisComment} instead. */
+@Deprecated
+public class VorbisComment implements Metadata.Entry {
/** The key. */
public final String key;
@@ -41,7 +42,7 @@ public final class VorbisComment implements Metadata.Entry {
this.value = value;
}
- /* package */ VorbisComment(Parcel in) {
+ protected VorbisComment(Parcel in) {
this.key = castNonNull(in.readString());
this.value = castNonNull(in.readString());
}
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java
new file mode 100644
index 0000000000..6f452f29bd
--- /dev/null
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/vorbis/VorbisComment.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 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 com.google.android.exoplayer2.metadata.vorbis;
+
+import android.os.Parcel;
+
+/** A vorbis comment, extracted from a FLAC or Ogg file. */
+@SuppressWarnings("deprecation") // Extending deprecated type for backwards compatibility.
+public final class VorbisComment extends com.google.android.exoplayer2.metadata.flac.VorbisComment {
+
+ /**
+ * @param key The key.
+ * @param value The value.
+ */
+ public VorbisComment(String key, String value) {
+ super(key, value);
+ }
+
+ /* package */ VorbisComment(Parcel in) {
+ super(in);
+ }
+
+ public static final Creator CREATOR =
+ new Creator() {
+
+ @Override
+ public VorbisComment createFromParcel(Parcel in) {
+ return new VorbisComment(in);
+ }
+
+ @Override
+ public VorbisComment[] newArray(int size) {
+ return new VorbisComment[size];
+ }
+ };
+}
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/vorbis/package-info.java b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/vorbis/package-info.java
new file mode 100644
index 0000000000..858bba01a9
--- /dev/null
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/metadata/vorbis/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+@NonNullApi
+package com.google.android.exoplayer2.metadata.vorbis;
+
+import com.google.android.exoplayer2.util.NonNullApi;
diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacMetadataReaderTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacMetadataReaderTest.java
index 7076181d62..422974a089 100644
--- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacMetadataReaderTest.java
+++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacMetadataReaderTest.java
@@ -25,7 +25,7 @@ import com.google.android.exoplayer2.extractor.FlacMetadataReader.FlacStreamMeta
import com.google.android.exoplayer2.extractor.flac.FlacConstants;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.flac.PictureFrame;
-import com.google.android.exoplayer2.metadata.flac.VorbisComment;
+import com.google.android.exoplayer2.metadata.vorbis.VorbisComment;
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.ParsableByteArray;
diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacStreamMetadataTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacStreamMetadataTest.java
index 49d49ac981..a5258f8634 100644
--- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacStreamMetadataTest.java
+++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/FlacStreamMetadataTest.java
@@ -21,7 +21,7 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.extractor.flac.FlacConstants;
import com.google.android.exoplayer2.metadata.Metadata;
-import com.google.android.exoplayer2.metadata.flac.VorbisComment;
+import com.google.android.exoplayer2.metadata.vorbis.VorbisComment;
import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.IOException;
import java.util.ArrayList;
diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java
index 64faff9a0e..531a1926ed 100644
--- a/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java
+++ b/library/extractor/src/test/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractorTest.java
@@ -67,6 +67,20 @@ public final class MatroskaExtractorTest {
simulationConfig);
}
+ @Test
+ public void mkvSample_withVttSubtitles() throws Exception {
+ ExtractorAsserts.assertBehavior(
+ MatroskaExtractor::new, "media/mkv/sample_with_vtt_subtitles.mkv", simulationConfig);
+ }
+
+ @Test
+ public void mkvSample_withNullTerminatedVttSubtitles() throws Exception {
+ ExtractorAsserts.assertBehavior(
+ MatroskaExtractor::new,
+ "media/mkv/sample_with_null_terminated_vtt_subtitles.mkv",
+ simulationConfig);
+ }
+
@Test
public void mkvSample_withVorbisAudio() throws Exception {
ExtractorAsserts.assertBehavior(
diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/metadata/flac/VorbisCommentTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java
similarity index 98%
rename from library/extractor/src/test/java/com/google/android/exoplayer2/metadata/flac/VorbisCommentTest.java
rename to library/extractor/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java
index 4c0f0592de..41bafef71c 100644
--- a/library/extractor/src/test/java/com/google/android/exoplayer2/metadata/flac/VorbisCommentTest.java
+++ b/library/extractor/src/test/java/com/google/android/exoplayer2/metadata/vorbis/VorbisCommentTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.google.android.exoplayer2.metadata.flac;
+package com.google.android.exoplayer2.metadata.vorbis;
import static com.google.common.truth.Truth.assertThat;
diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java
index 5fd4823b95..5b30d5a039 100644
--- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java
+++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspClient.java
@@ -619,11 +619,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
startTimingString == null
? RtspSessionTiming.DEFAULT
: RtspSessionTiming.parseTiming(startTimingString);
- @Nullable String rtpInfoString = response.headers.get(RtspHeaders.RTP_INFO);
- ImmutableList trackTimingList =
- rtpInfoString == null
- ? ImmutableList.of()
- : RtspTrackTiming.parseTrackTiming(rtpInfoString, uri);
+
+ ImmutableList trackTimingList;
+ try {
+ @Nullable String rtpInfoString = response.headers.get(RtspHeaders.RTP_INFO);
+ trackTimingList =
+ rtpInfoString == null
+ ? ImmutableList.of()
+ : RtspTrackTiming.parseTrackTiming(rtpInfoString, uri);
+ } catch (ParserException e) {
+ trackTimingList = ImmutableList.of();
+ }
+
onPlayResponseReceived(new RtspPlayResponse(response.status, timing, trackTimingList));
break;
diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java
index 6113cd3089..0f1c94c097 100644
--- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java
+++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaPeriod.java
@@ -67,6 +67,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** Called when the {@link RtspSessionTiming} is available. */
void onSourceInfoRefreshed(RtspSessionTiming timing);
+
+ /** Called when the RTSP server does not support seeking. */
+ default void onSeekingUnsupported() {}
}
/** The maximum times to retry if the underlying data channel failed to bind. */
@@ -90,6 +93,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private long pendingSeekPositionUs;
private long pendingSeekPositionUsForTcpRetry;
private boolean loadingFinished;
+ private boolean notifyDiscontinuity;
private boolean released;
private boolean prepared;
private boolean trackSelected;
@@ -243,6 +247,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public long readDiscontinuity() {
+ // Discontinuity only happens in RTSP when seeking an unexpectedly un-seekable RTSP server (a
+ // server that doesn't include the required RTP-Info header in its PLAY responses). This only
+ // applies to seeks made before receiving the first RTSP PLAY response. The playback can only
+ // start from time zero in this case.
+ if (notifyDiscontinuity) {
+ notifyDiscontinuity = false;
+ return 0;
+ }
return C.TIME_UNSET;
}
@@ -355,7 +367,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// SampleStream methods.
/* package */ boolean isReady(int trackGroupIndex) {
- return rtspLoaderWrappers.get(trackGroupIndex).isSampleQueueReady();
+ return !suppressRead() && rtspLoaderWrappers.get(trackGroupIndex).isSampleQueueReady();
}
@ReadDataResult
@@ -364,9 +376,23 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
FormatHolder formatHolder,
DecoderInputBuffer buffer,
@ReadFlags int readFlags) {
+ if (suppressRead()) {
+ return C.RESULT_NOTHING_READ;
+ }
return rtspLoaderWrappers.get(sampleQueueIndex).read(formatHolder, buffer, readFlags);
}
+ /* package */ int skipData(int sampleQueueIndex, long positionUs) {
+ if (suppressRead()) {
+ return C.RESULT_NOTHING_READ;
+ }
+ return rtspLoaderWrappers.get(sampleQueueIndex).skipData(positionUs);
+ }
+
+ private boolean suppressRead() {
+ return notifyDiscontinuity;
+ }
+
// Internal methods.
@Nullable
@@ -549,7 +575,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public void onPlaybackStarted(
long startPositionUs, ImmutableList trackTimingList) {
- // Validate that the trackTimingList contains timings for the selected tracks.
+
+ // Validate that the trackTimingList contains timings for the selected tracks, and notify the
+ // listener.
ArrayList trackUrisWithTiming = new ArrayList<>(trackTimingList.size());
for (int i = 0; i < trackTimingList.size(); i++) {
trackUrisWithTiming.add(checkNotNull(trackTimingList.get(i).uri.getPath()));
@@ -557,10 +585,13 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
for (int i = 0; i < selectedLoadInfos.size(); i++) {
RtpLoadInfo loadInfo = selectedLoadInfos.get(i);
if (!trackUrisWithTiming.contains(loadInfo.getTrackUri().getPath())) {
- playbackException =
- new RtspPlaybackException(
- "Server did not provide timing for track " + loadInfo.getTrackUri());
- return;
+ listener.onSeekingUnsupported();
+ if (isSeekPending()) {
+ notifyDiscontinuity = true;
+ pendingSeekPositionUs = C.TIME_UNSET;
+ requestedSeekPositionUs = C.TIME_UNSET;
+ pendingSeekPositionUsForTcpRetry = C.TIME_UNSET;
+ }
}
}
@@ -697,7 +728,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
public int skipData(long positionUs) {
- return 0;
+ return RtspMediaPeriod.this.skipData(track, positionUs);
}
}
@@ -748,6 +779,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return sampleQueue.read(formatHolder, buffer, readFlags, /* loadingFinished= */ canceled);
}
+ public int skipData(long positionUs) {
+ int skipCount = sampleQueue.getSkipCount(positionUs, /* allowEndOfQueue= */ canceled);
+ sampleQueue.skip(skipCount);
+ return skipCount;
+ }
+
/** Cancels loading. */
public void cancelLoad() {
if (!canceled) {
diff --git a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java
index 5fd1e6cb04..05301cdd54 100644
--- a/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java
+++ b/library/rtsp/src/main/java/com/google/android/exoplayer2/source/rtsp/RtspMediaSource.java
@@ -255,12 +255,21 @@ public final class RtspMediaSource extends BaseMediaSource {
allocator,
rtpDataChannelFactory,
uri,
- /* listener= */ timing -> {
- timelineDurationUs = Util.msToUs(timing.getDurationMs());
- timelineIsSeekable = !timing.isLive();
- timelineIsLive = timing.isLive();
- timelineIsPlaceholder = false;
- notifySourceInfoRefreshed();
+ new RtspMediaPeriod.Listener() {
+ @Override
+ public void onSourceInfoRefreshed(RtspSessionTiming timing) {
+ timelineDurationUs = Util.msToUs(timing.getDurationMs());
+ timelineIsSeekable = !timing.isLive();
+ timelineIsLive = timing.isLive();
+ timelineIsPlaceholder = false;
+ notifySourceInfoRefreshed();
+ }
+
+ @Override
+ public void onSeekingUnsupported() {
+ timelineIsSeekable = false;
+ notifySourceInfoRefreshed();
+ }
},
userAgent,
socketFactory,
diff --git a/library/transformer/src/androidTest/AndroidManifest.xml b/library/transformer/src/androidTest/AndroidManifest.xml
index c1afec1685..7094f6b0cf 100644
--- a/library/transformer/src/androidTest/AndroidManifest.xml
+++ b/library/transformer/src/androidTest/AndroidManifest.xml
@@ -22,7 +22,6 @@
-
> 24) & 0xFF) - ((expectedColor >> 24) & 0xFF)));
- maximumAbsoluteDifference =
- max(
- maximumAbsoluteDifference,
- abs(((color >> 16) & 0xFF) - ((expectedColor >> 16) & 0xFF)));
- maximumAbsoluteDifference =
- max(
- maximumAbsoluteDifference,
- abs(((color >> 8) & 0xFF) - ((expectedColor >> 8) & 0xFF)));
- maximumAbsoluteDifference =
- max(maximumAbsoluteDifference, abs((color & 0xFF) - (expectedColor & 0xFF)));
+ maximumAbsoluteDifference = max(maximumAbsoluteDifference, alphaDifference);
+ maximumAbsoluteDifference = max(maximumAbsoluteDifference, redDifference);
+ maximumAbsoluteDifference = max(maximumAbsoluteDifference, blueDifference);
+ maximumAbsoluteDifference = max(maximumAbsoluteDifference, greenDifference);
+
sumMaximumAbsoluteDifferences += maximumAbsoluteDifference;
}
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioTranscodingSamplePipeline.java
similarity index 81%
rename from library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java
rename to library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioTranscodingSamplePipeline.java
index 505677d046..126c5cf59b 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioSamplePipeline.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/AudioTranscodingSamplePipeline.java
@@ -18,7 +18,6 @@ package com.google.android.exoplayer2.transformer;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Assertions.checkState;
-import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
import static java.lang.Math.min;
import android.media.MediaCodec.BufferInfo;
@@ -29,23 +28,24 @@ import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.audio.AudioProcessor.AudioFormat;
import com.google.android.exoplayer2.audio.SonicAudioProcessor;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer;
+import java.util.List;
+import org.checkerframework.dataflow.qual.Pure;
/**
* Pipeline to decode audio samples, apply transformations on the raw samples, and re-encode them.
*/
-/* package */ final class AudioSamplePipeline implements SamplePipeline {
+/* package */ final class AudioTranscodingSamplePipeline implements SamplePipeline {
- private static final String TAG = "AudioSamplePipeline";
private static final int DEFAULT_ENCODER_BITRATE = 128 * 1024;
- private final TransformationRequest transformationRequest;
-
private final Codec decoder;
private final DecoderInputBuffer decoderInputBuffer;
private final SonicAudioProcessor sonicAudioProcessor;
private final SpeedProvider speedProvider;
+ private final boolean flattenForSlowMotion;
private final Codec encoder;
private final AudioFormat encoderInputAudioFormat;
@@ -59,13 +59,14 @@ import java.nio.ByteBuffer;
private boolean drainingSonicForSpeedChange;
private float currentSpeed;
- public AudioSamplePipeline(
+ public AudioTranscodingSamplePipeline(
Format inputFormat,
TransformationRequest transformationRequest,
+ Codec.DecoderFactory decoderFactory,
Codec.EncoderFactory encoderFactory,
- Codec.DecoderFactory decoderFactory)
+ List allowedOutputMimeTypes,
+ FallbackListener fallbackListener)
throws TransformationException {
- this.transformationRequest = transformationRequest;
decoderInputBuffer =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
encoderInputBuffer =
@@ -75,6 +76,7 @@ import java.nio.ByteBuffer;
this.decoder = decoderFactory.createForAudioDecoding(inputFormat);
+ this.flattenForSlowMotion = transformationRequest.flattenForSlowMotion;
sonicAudioProcessor = new SonicAudioProcessor();
sonicOutputBuffer = AudioProcessor.EMPTY_BUFFER;
speedProvider = new SegmentSpeedProvider(inputFormat);
@@ -86,7 +88,7 @@ import java.nio.ByteBuffer;
// The decoder uses ENCODING_PCM_16BIT by default.
// https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers
C.ENCODING_PCM_16BIT);
- if (transformationRequest.flattenForSlowMotion) {
+ if (flattenForSlowMotion) {
try {
encoderInputAudioFormat = sonicAudioProcessor.configure(encoderInputAudioFormat);
} catch (AudioProcessor.UnhandledAudioFormatException impossible) {
@@ -96,19 +98,23 @@ import java.nio.ByteBuffer;
sonicAudioProcessor.setPitch(currentSpeed);
sonicAudioProcessor.flush();
}
-
- encoder =
- encoderFactory.createForAudioEncoding(
- new Format.Builder()
- .setSampleMimeType(
- transformationRequest.audioMimeType == null
- ? inputFormat.sampleMimeType
- : transformationRequest.audioMimeType)
- .setSampleRate(encoderInputAudioFormat.sampleRate)
- .setChannelCount(encoderInputAudioFormat.channelCount)
- .setAverageBitrate(DEFAULT_ENCODER_BITRATE)
- .build());
this.encoderInputAudioFormat = encoderInputAudioFormat;
+
+ Format requestedOutputFormat =
+ new Format.Builder()
+ .setSampleMimeType(
+ transformationRequest.audioMimeType == null
+ ? inputFormat.sampleMimeType
+ : transformationRequest.audioMimeType)
+ .setSampleRate(encoderInputAudioFormat.sampleRate)
+ .setChannelCount(encoderInputAudioFormat.channelCount)
+ .setAverageBitrate(DEFAULT_ENCODER_BITRATE)
+ .build();
+ encoder = encoderFactory.createForAudioEncoding(requestedOutputFormat, allowedOutputMimeTypes);
+
+ fallbackListener.onTransformationRequestFinalized(
+ createFallbackTransformationRequest(
+ transformationRequest, requestedOutputFormat, encoder.getConfigurationFormat()));
}
@Override
@@ -134,40 +140,36 @@ import java.nio.ByteBuffer;
@Override
@Nullable
public Format getOutputFormat() throws TransformationException {
- return encoder != null ? encoder.getOutputFormat() : null;
+ return encoder.getOutputFormat();
}
@Override
@Nullable
public DecoderInputBuffer getOutputBuffer() throws TransformationException {
- if (encoder != null) {
- encoderOutputBuffer.data = encoder.getOutputBuffer();
- if (encoderOutputBuffer.data != null) {
- encoderOutputBuffer.timeUs = checkNotNull(encoder.getOutputBufferInfo()).presentationTimeUs;
- encoderOutputBuffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);
- return encoderOutputBuffer;
- }
+ encoderOutputBuffer.data = encoder.getOutputBuffer();
+ if (encoderOutputBuffer.data == null) {
+ return null;
}
- return null;
+ encoderOutputBuffer.timeUs = checkNotNull(encoder.getOutputBufferInfo()).presentationTimeUs;
+ encoderOutputBuffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);
+ return encoderOutputBuffer;
}
@Override
public void releaseOutputBuffer() throws TransformationException {
- checkStateNotNull(encoder).releaseOutputBuffer();
+ encoder.releaseOutputBuffer();
}
@Override
public boolean isEnded() {
- return encoder != null && encoder.isEnded();
+ return encoder.isEnded();
}
@Override
public void release() {
sonicAudioProcessor.reset();
decoder.release();
- if (encoder != null) {
- encoder.release();
- }
+ encoder.release();
}
/**
@@ -293,7 +295,7 @@ import java.nio.ByteBuffer;
}
private boolean isSpeedChanging(BufferInfo bufferInfo) {
- if (!transformationRequest.flattenForSlowMotion) {
+ if (!flattenForSlowMotion) {
return false;
}
float newSpeed = speedProvider.getSpeed(bufferInfo.presentationTimeUs);
@@ -325,4 +327,15 @@ import java.nio.ByteBuffer;
}
nextEncoderInputBufferTimeUs += bufferDurationUs;
}
+
+ @Pure
+ private static TransformationRequest createFallbackTransformationRequest(
+ TransformationRequest transformationRequest, Format requestedFormat, Format actualFormat) {
+ // TODO(b/210591626): Also update bitrate and other params once encoder configuration and
+ // fallback are implemented.
+ if (Util.areEqual(requestedFormat.sampleMimeType, actualFormat.sampleMimeType)) {
+ return transformationRequest;
+ }
+ return transformationRequest.buildUpon().setAudioMimeType(actualFormat.sampleMimeType).build();
+ }
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Codec.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Codec.java
index b898bb20a7..834b54a404 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Codec.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Codec.java
@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import java.nio.ByteBuffer;
+import java.util.List;
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@@ -54,7 +55,7 @@ public final class Codec {
* @param format The {@link Format} (of the input data) used to determine the underlying {@link
* MediaCodec} and its configuration values.
* @return A configured and started decoder wrapper.
- * @throws TransformationException If the underlying codec cannot be created.
+ * @throws TransformationException If no suitable codec can be created.
*/
Codec createForAudioDecoding(Format format) throws TransformationException;
@@ -65,7 +66,7 @@ public final class Codec {
* MediaCodec} and its configuration values.
* @param outputSurface The {@link Surface} to which the decoder output is rendered.
* @return A configured and started decoder wrapper.
- * @throws TransformationException If the underlying codec cannot be created.
+ * @throws TransformationException If no suitable codec can be created.
*/
Codec createForVideoDecoding(Format format, Surface outputSurface)
throws TransformationException;
@@ -80,25 +81,39 @@ public final class Codec {
/**
* Returns a {@link Codec} for audio encoding.
*
+ * This method must validate that the {@link Codec} is configured to produce one of the
+ * {@code allowedMimeTypes}. The {@link Format#sampleMimeType sample MIME type} given in {@code
+ * format} is not necessarily allowed.
+ *
* @param format The {@link Format} (of the output data) used to determine the underlying {@link
* MediaCodec} and its configuration values.
+ * @param allowedMimeTypes The non-empty list of allowed output sample {@link MimeTypes MIME
+ * types}.
* @return A configured and started encoder wrapper.
- * @throws TransformationException If the underlying codec cannot be created.
+ * @throws TransformationException If no suitable codec can be created.
*/
- Codec createForAudioEncoding(Format format) throws TransformationException;
+ Codec createForAudioEncoding(Format format, List allowedMimeTypes)
+ throws TransformationException;
/**
* Returns a {@link Codec} for video encoding.
*
+ * This method must validate that the {@link Codec} is configured to produce one of the
+ * {@code allowedMimeTypes}. The {@link Format#sampleMimeType sample MIME type} given in {@code
+ * format} is not necessarily allowed.
+ *
* @param format The {@link Format} (of the output data) used to determine the underlying {@link
* MediaCodec} and its configuration values. {@link Format#sampleMimeType}, {@link
* Format#width} and {@link Format#height} must be set to those of the desired output video
* format. {@link Format#rotationDegrees} should be 0. The video should always be in
* landscape orientation.
+ * @param allowedMimeTypes The non-empty list of allowed output sample {@link MimeTypes MIME
+ * types}.
* @return A configured and started encoder wrapper.
- * @throws TransformationException If the underlying codec cannot be created.
+ * @throws TransformationException If no suitable codec can be created.
*/
- Codec createForVideoEncoding(Format format) throws TransformationException;
+ Codec createForVideoEncoding(Format format, List allowedMimeTypes)
+ throws TransformationException;
}
// MediaCodec decoders always output 16 bit PCM, unless configured to output PCM float.
@@ -142,8 +157,6 @@ public final class Codec {
* DecoderFactory} or output {@link Format} used by the {@link EncoderFactory} for selecting and
* configuring the underlying {@link MediaCodec}.
*/
- // TODO(b/214012830): Use this to check whether the Format passed to the factory and actual
- // configuration format differ to see whether fallback was applied.
public Format getConfigurationFormat() {
return configurationFormat;
}
@@ -248,7 +261,7 @@ public final class Codec {
@Nullable
public Format getOutputFormat() throws TransformationException {
// The format is updated when dequeueing a 'special' buffer index, so attempt to dequeue now.
- maybeDequeueOutputBuffer();
+ maybeDequeueOutputBuffer(/* setOutputBuffer= */ false);
return outputFormat;
}
@@ -259,7 +272,7 @@ public final class Codec {
*/
@Nullable
public ByteBuffer getOutputBuffer() throws TransformationException {
- return maybeDequeueAndSetOutputBuffer() ? outputBuffer : null;
+ return maybeDequeueOutputBuffer(/* setOutputBuffer= */ true) ? outputBuffer : null;
}
/**
@@ -269,7 +282,7 @@ public final class Codec {
*/
@Nullable
public BufferInfo getOutputBufferInfo() throws TransformationException {
- return maybeDequeueOutputBuffer() ? outputBufferInfo : null;
+ return maybeDequeueOutputBuffer(/* setOutputBuffer= */ false) ? outputBufferInfo : null;
}
/**
@@ -321,33 +334,15 @@ public final class Codec {
}
/**
- * Tries obtaining an output buffer and sets {@link #outputBuffer} to the obtained output buffer.
+ * Attempts to dequeue an output buffer if there is no output buffer pending. Does nothing
+ * otherwise.
*
- * @return {@code true} if a buffer is successfully obtained, {@code false} otherwise.
+ * @param setOutputBuffer Whether to read the bytes of the dequeued output buffer and copy them
+ * into {@link #outputBuffer}.
+ * @return Whether there is an output buffer available.
* @throws TransformationException If the underlying {@link MediaCodec} encounters a problem.
*/
- private boolean maybeDequeueAndSetOutputBuffer() throws TransformationException {
- if (!maybeDequeueOutputBuffer()) {
- return false;
- }
-
- try {
- outputBuffer = checkNotNull(mediaCodec.getOutputBuffer(outputBufferIndex));
- } catch (RuntimeException e) {
- throw createTransformationException(e);
- }
- outputBuffer.position(outputBufferInfo.offset);
- outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size);
- return true;
- }
-
- /**
- * Returns true if there is already an output buffer pending. Otherwise attempts to dequeue an
- * output buffer and returns whether there is a new output buffer.
- *
- * @throws TransformationException If the underlying {@link MediaCodec} encounters a problem.
- */
- private boolean maybeDequeueOutputBuffer() throws TransformationException {
+ private boolean maybeDequeueOutputBuffer(boolean setOutputBuffer) throws TransformationException {
if (outputBufferIndex >= 0) {
return true;
}
@@ -378,6 +373,16 @@ public final class Codec {
releaseOutputBuffer();
return false;
}
+
+ if (setOutputBuffer) {
+ try {
+ outputBuffer = checkNotNull(mediaCodec.getOutputBuffer(outputBufferIndex));
+ } catch (RuntimeException e) {
+ throw createTransformationException(e);
+ }
+ outputBuffer.position(outputBufferInfo.offset);
+ outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size);
+ }
return true;
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodecFactory.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodecFactory.java
index 081e502ccf..b4a7cf68b5 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodecFactory.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/DefaultCodecFactory.java
@@ -22,19 +22,31 @@ import static com.google.android.exoplayer2.util.Util.SDK_INT;
import android.annotation.SuppressLint;
import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaFormat;
+import android.util.Pair;
import android.view.Surface;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.util.MediaFormatUtil;
+import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.TraceUtil;
import java.io.IOException;
+import java.util.List;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** A default {@link Codec.DecoderFactory} and {@link Codec.EncoderFactory}. */
/* package */ final class DefaultCodecFactory
implements Codec.DecoderFactory, Codec.EncoderFactory {
+ // TODO(b/214973843): Add option to disable fallback.
+
+ // TODO(b/210591626): Fall back adaptively to H265 if possible.
+ private static final String DEFAULT_FALLBACK_MIME_TYPE = MimeTypes.VIDEO_H264;
+ private static final int DEFAULT_COLOR_FORMAT = CodecCapabilities.COLOR_FormatSurface;
+ private static final int DEFAULT_FRAME_RATE = 60;
+ private static final int DEFAULT_I_FRAME_INTERVAL_SECS = 1;
@Override
public Codec createForAudioDecoding(Format format) throws TransformationException {
@@ -75,7 +87,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
@Override
- public Codec createForAudioEncoding(Format format) throws TransformationException {
+ public Codec createForAudioEncoding(Format format, List allowedMimeTypes)
+ throws TransformationException {
+ checkArgument(!allowedMimeTypes.isEmpty());
+ if (!allowedMimeTypes.contains(format.sampleMimeType)) {
+ // TODO(b/210591626): Pick fallback MIME type using same strategy as for encoder
+ // capabilities limitations.
+ format = format.buildUpon().setSampleMimeType(allowedMimeTypes.get(0)).build();
+ }
MediaFormat mediaFormat =
MediaFormat.createAudioFormat(
checkNotNull(format.sampleMimeType), format.sampleRate, format.channelCount);
@@ -90,21 +109,37 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
}
@Override
- public Codec createForVideoEncoding(Format format) throws TransformationException {
+ public Codec createForVideoEncoding(Format format, List allowedMimeTypes)
+ throws TransformationException {
checkArgument(format.width != Format.NO_VALUE);
checkArgument(format.height != Format.NO_VALUE);
// According to interface Javadoc, format.rotationDegrees should be 0. The video should always
// be in landscape orientation.
- checkArgument(format.height < format.width);
+ checkArgument(format.height <= format.width);
checkArgument(format.rotationDegrees == 0);
+ checkNotNull(format.sampleMimeType);
+
+ checkArgument(!allowedMimeTypes.isEmpty());
+
+ format = getVideoEncoderSupportedFormat(format, allowedMimeTypes);
MediaFormat mediaFormat =
MediaFormat.createVideoFormat(
checkNotNull(format.sampleMimeType), format.width, format.height);
- mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, CodecCapabilities.COLOR_FormatSurface);
- mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
- mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
- mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 413_000);
+ mediaFormat.setFloat(MediaFormat.KEY_FRAME_RATE, format.frameRate);
+ mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, format.averageBitrate);
+
+ @Nullable
+ Pair codecProfileAndLevel = MediaCodecUtil.getCodecProfileAndLevel(format);
+ if (codecProfileAndLevel != null) {
+ mediaFormat.setInteger(MediaFormat.KEY_PROFILE, codecProfileAndLevel.first);
+ if (SDK_INT >= 23) {
+ mediaFormat.setInteger(MediaFormat.KEY_LEVEL, codecProfileAndLevel.second);
+ }
+ }
+
+ mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, DEFAULT_COLOR_FORMAT);
+ mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, DEFAULT_I_FRAME_INTERVAL_SECS);
return createCodec(
format,
@@ -168,6 +203,89 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
TraceUtil.endSection();
}
+ @RequiresNonNull("#1.sampleMimeType")
+ private static Format getVideoEncoderSupportedFormat(
+ Format requestedFormat, List allowedMimeTypes) throws TransformationException {
+ String mimeType = requestedFormat.sampleMimeType;
+ Format.Builder formatBuilder = requestedFormat.buildUpon();
+
+ // TODO(b/210591626) Implement encoder filtering.
+ if (!allowedMimeTypes.contains(mimeType)
+ || EncoderUtil.getSupportedEncoders(mimeType).isEmpty()) {
+ mimeType =
+ allowedMimeTypes.contains(DEFAULT_FALLBACK_MIME_TYPE)
+ ? DEFAULT_FALLBACK_MIME_TYPE
+ : allowedMimeTypes.get(0);
+ if (EncoderUtil.getSupportedEncoders(mimeType).isEmpty()) {
+ throw createTransformationException(
+ new IllegalArgumentException(
+ "No encoder is found for requested MIME type " + requestedFormat.sampleMimeType),
+ requestedFormat,
+ /* isVideo= */ true,
+ /* isDecoder= */ false,
+ /* mediaCodecName= */ null);
+ }
+ }
+
+ formatBuilder.setSampleMimeType(mimeType);
+ MediaCodecInfo encoderInfo = EncoderUtil.getSupportedEncoders(mimeType).get(0);
+
+ int width = requestedFormat.width;
+ int height = requestedFormat.height;
+ @Nullable
+ Pair encoderSupportedResolution =
+ EncoderUtil.getClosestSupportedResolution(encoderInfo, mimeType, width, height);
+ if (encoderSupportedResolution == null) {
+ throw createTransformationException(
+ new IllegalArgumentException(
+ "Cannot find fallback resolution for resolution " + width + " x " + height),
+ requestedFormat,
+ /* isVideo= */ true,
+ /* isDecoder= */ false,
+ /* mediaCodecName= */ null);
+ }
+ width = encoderSupportedResolution.first;
+ height = encoderSupportedResolution.second;
+ formatBuilder.setWidth(width).setHeight(height);
+
+ // The frameRate does not affect the resulting frame rate. It affects the encoder's rate control
+ // algorithm. Setting it too high may lead to video quality degradation.
+ float frameRate =
+ requestedFormat.frameRate != Format.NO_VALUE
+ ? requestedFormat.frameRate
+ : DEFAULT_FRAME_RATE;
+ int bitrate =
+ EncoderUtil.getClosestSupportedBitrate(
+ encoderInfo,
+ mimeType,
+ /* bitrate= */ requestedFormat.averageBitrate != Format.NO_VALUE
+ ? requestedFormat.averageBitrate
+ : getSuggestedBitrate(width, height, frameRate));
+ formatBuilder.setFrameRate(frameRate).setAverageBitrate(bitrate);
+
+ @Nullable
+ Pair profileLevel = MediaCodecUtil.getCodecProfileAndLevel(requestedFormat);
+ if (profileLevel == null
+ // Transcoding to another MIME type.
+ || !requestedFormat.sampleMimeType.equals(mimeType)
+ || !EncoderUtil.isProfileLevelSupported(
+ encoderInfo,
+ mimeType,
+ /* profile= */ profileLevel.first,
+ /* level= */ profileLevel.second)) {
+ formatBuilder.setCodecs(null);
+ }
+
+ return formatBuilder.build();
+ }
+
+ /** Computes the video bit rate using the Kush Gauge. */
+ private static int getSuggestedBitrate(int width, int height, float frameRate) {
+ // TODO(b/210591626) Implement bitrate estimation.
+ // 1080p30 -> 6.2Mbps, 720p30 -> 2.7Mbps.
+ return (int) (width * height * frameRate * 0.1);
+ }
+
private static TransformationException createTransformationException(
Exception cause,
Format format,
@@ -193,7 +311,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
mediaCodecName,
isDecoder
? TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED
- : TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED);
+ : TransformationException.ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED);
}
return TransformationException.createForUnexpected(cause);
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/EncoderUtil.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/EncoderUtil.java
new file mode 100644
index 0000000000..65e96efbc8
--- /dev/null
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/EncoderUtil.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2022 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 com.google.android.exoplayer2.transformer;
+
+import static java.lang.Math.round;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.util.Pair;
+import androidx.annotation.Nullable;
+import com.google.common.base.Ascii;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Utility methods for {@link MediaCodec} encoders. */
+public final class EncoderUtil {
+
+ private static final List encoders = new ArrayList<>();
+
+ /**
+ * Returns a list of {@link MediaCodecInfo encoders} that support the given {@code mimeType}, or
+ * an empty list if there is none.
+ */
+ public static ImmutableList getSupportedEncoders(String mimeType) {
+ maybePopulateEncoderInfos();
+
+ ImmutableList.Builder availableEncoders = new ImmutableList.Builder<>();
+ for (int i = 0; i < encoders.size(); i++) {
+ MediaCodecInfo encoderInfo = encoders.get(i);
+ String[] supportedMimeTypes = encoderInfo.getSupportedTypes();
+ for (String supportedMimeType : supportedMimeTypes) {
+ if (Ascii.equalsIgnoreCase(supportedMimeType, mimeType)) {
+ availableEncoders.add(encoderInfo);
+ }
+ }
+ }
+ return availableEncoders.build();
+ }
+
+ /**
+ * Finds the {@link MediaCodecInfo encoder}'s closest supported resolution from the given
+ * resolution.
+ *
+ * The input resolution is returned, if it is supported by the {@link MediaCodecInfo encoder}.
+ *
+ *
The resolution will be clamped to the {@link MediaCodecInfo encoder}'s range of supported
+ * resolutions, and adjusted to the {@link MediaCodecInfo encoder}'s size alignment. The
+ * adjustment process takes into account the original aspect ratio. But the fixed resolution may
+ * not preserve the original aspect ratio, depending on the encoder's required size alignment.
+ *
+ * @param encoderInfo The {@link MediaCodecInfo} of the encoder.
+ * @param mimeType The output MIME type.
+ * @param width The original width.
+ * @param height The original height.
+ * @return A {@link Pair} of width and height, or {@code null} if unable to find a fix.
+ */
+ @Nullable
+ public static Pair getClosestSupportedResolution(
+ MediaCodecInfo encoderInfo, String mimeType, int width, int height) {
+ MediaCodecInfo.VideoCapabilities videoEncoderCapabilities =
+ encoderInfo.getCapabilitiesForType(mimeType).getVideoCapabilities();
+
+ if (videoEncoderCapabilities.isSizeSupported(width, height)) {
+ return Pair.create(width, height);
+ }
+
+ // Fix frame being too wide or too tall.
+ int adjustedHeight = videoEncoderCapabilities.getSupportedHeights().clamp(height);
+ if (adjustedHeight != height) {
+ width = (int) round((double) width * adjustedHeight / height);
+ height = adjustedHeight;
+ }
+
+ int adjustedWidth = videoEncoderCapabilities.getSupportedWidths().clamp(width);
+ if (adjustedWidth != width) {
+ height = (int) round((double) height * adjustedWidth / width);
+ width = adjustedWidth;
+ }
+
+ // Fix pixel alignment.
+ width = alignResolution(width, videoEncoderCapabilities.getWidthAlignment());
+ height = alignResolution(height, videoEncoderCapabilities.getHeightAlignment());
+
+ return videoEncoderCapabilities.isSizeSupported(width, height)
+ ? Pair.create(width, height)
+ : null;
+ }
+
+ /** Returns whether the {@link MediaCodecInfo encoder} supports the given profile and level. */
+ public static boolean isProfileLevelSupported(
+ MediaCodecInfo encoderInfo, String mimeType, int profile, int level) {
+ MediaCodecInfo.CodecProfileLevel[] profileLevels =
+ encoderInfo.getCapabilitiesForType(mimeType).profileLevels;
+
+ for (MediaCodecInfo.CodecProfileLevel profileLevel : profileLevels) {
+ if (profileLevel.profile == profile && profileLevel.level == level) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds the {@link MediaCodecInfo encoder}'s closest supported bitrate from the given bitrate.
+ */
+ public static int getClosestSupportedBitrate(
+ MediaCodecInfo encoderInfo, String mimeType, int bitrate) {
+ return encoderInfo
+ .getCapabilitiesForType(mimeType)
+ .getVideoCapabilities()
+ .getBitrateRange()
+ .clamp(bitrate);
+ }
+
+ /**
+ * Align to the closest resolution that respects the encoder's supported alignment.
+ *
+ * For example, size 35 will be aligned to 32 if the alignment is 16, and size 45 will be
+ * aligned to 48.
+ */
+ private static int alignResolution(int size, int alignment) {
+ return alignment * Math.round((float) size / alignment);
+ }
+
+ private static synchronized void maybePopulateEncoderInfos() {
+ if (encoders.isEmpty()) {
+ MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
+ MediaCodecInfo[] allCodecInfos = mediaCodecList.getCodecInfos();
+
+ for (MediaCodecInfo mediaCodecInfo : allCodecInfos) {
+ if (!mediaCodecInfo.isEncoder()) {
+ continue;
+ }
+ encoders.add(mediaCodecInfo);
+ }
+ }
+ }
+
+ private EncoderUtil() {}
+}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FallbackListener.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FallbackListener.java
new file mode 100644
index 0000000000..d335f0f63f
--- /dev/null
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/FallbackListener.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2022 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 com.google.android.exoplayer2.transformer;
+
+import static com.google.android.exoplayer2.util.Assertions.checkState;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.util.ListenerSet;
+import com.google.android.exoplayer2.util.Util;
+
+/**
+ * Listener for fallback {@link TransformationRequest TransformationRequests} from the audio and
+ * video renderers.
+ */
+/* package */ final class FallbackListener {
+
+ private final MediaItem mediaItem;
+ private final TransformationRequest originalTransformationRequest;
+ private final ListenerSet transformerListeners;
+
+ private TransformationRequest fallbackTransformationRequest;
+ private int trackCount;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param mediaItem The {@link MediaItem} to transform.
+ * @param transformerListeners The {@link Transformer.Listener listeners} to forward events to.
+ * @param originalTransformationRequest The original {@link TransformationRequest}.
+ */
+ public FallbackListener(
+ MediaItem mediaItem,
+ ListenerSet transformerListeners,
+ TransformationRequest originalTransformationRequest) {
+ this.mediaItem = mediaItem;
+ this.transformerListeners = transformerListeners;
+ this.originalTransformationRequest = originalTransformationRequest;
+ this.fallbackTransformationRequest = originalTransformationRequest;
+ }
+
+ /**
+ * Registers an output track.
+ *
+ * All tracks must be registered before a transformation request is {@link
+ * #onTransformationRequestFinalized(TransformationRequest) finalized}.
+ */
+ public void registerTrack() {
+ trackCount++;
+ }
+
+ /**
+ * Updates the fallback {@link TransformationRequest}.
+ *
+ *
Should be called with the final {@link TransformationRequest} for each track after all
+ * fallback has been applied. Calls {@link Transformer.Listener#onFallbackApplied(MediaItem,
+ * TransformationRequest, TransformationRequest)} once this method has been called for each track.
+ *
+ * @param transformationRequest The final {@link TransformationRequest} for a track.
+ * @throws IllegalStateException If called for more tracks than registered using {@link
+ * #registerTrack()}.
+ */
+ public void onTransformationRequestFinalized(TransformationRequest transformationRequest) {
+ checkState(trackCount-- > 0);
+
+ TransformationRequest.Builder fallbackRequestBuilder =
+ fallbackTransformationRequest.buildUpon();
+ if (!Util.areEqual(
+ transformationRequest.audioMimeType, originalTransformationRequest.audioMimeType)) {
+ fallbackRequestBuilder.setAudioMimeType(transformationRequest.audioMimeType);
+ }
+ if (!Util.areEqual(
+ transformationRequest.videoMimeType, originalTransformationRequest.videoMimeType)) {
+ fallbackRequestBuilder.setVideoMimeType(transformationRequest.videoMimeType);
+ }
+ if (transformationRequest.outputHeight != originalTransformationRequest.outputHeight) {
+ fallbackRequestBuilder.setResolution(transformationRequest.outputHeight);
+ }
+ fallbackTransformationRequest = fallbackRequestBuilder.build();
+
+ if (trackCount == 0 && !originalTransformationRequest.equals(fallbackTransformationRequest)) {
+ transformerListeners.queueEvent(
+ /* eventFlag= */ C.INDEX_UNSET,
+ listener ->
+ listener.onFallbackApplied(
+ mediaItem, originalTransformationRequest, fallbackTransformationRequest));
+ transformerListeners.flushEvents();
+ }
+ }
+}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/PassthroughSamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/PassthroughSamplePipeline.java
index 8b540ee105..042819b0fb 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/PassthroughSamplePipeline.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/PassthroughSamplePipeline.java
@@ -28,10 +28,14 @@ import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
private boolean hasPendingBuffer;
- public PassthroughSamplePipeline(Format format) {
+ public PassthroughSamplePipeline(
+ Format format,
+ TransformationRequest transformationRequest,
+ FallbackListener fallbackListener) {
this.format = format;
buffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DIRECT);
hasPendingBuffer = false;
+ fallbackListener.onTransformationRequestFinalized(transformationRequest);
}
@Override
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java
index c74901730a..0c4fcef310 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationException.java
@@ -69,10 +69,9 @@ public final class TransformationException extends Exception {
ERROR_CODE_DECODING_FORMAT_UNSUPPORTED,
ERROR_CODE_ENCODER_INIT_FAILED,
ERROR_CODE_ENCODING_FAILED,
- ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED,
+ ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED,
ERROR_CODE_GL_INIT_FAILED,
ERROR_CODE_GL_PROCESSING_FAILED,
- ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED,
ERROR_CODE_MUXING_FAILED,
})
public @interface ErrorCode {}
@@ -146,8 +145,13 @@ public final class TransformationException extends Exception {
public static final int ERROR_CODE_ENCODER_INIT_FAILED = 4001;
/** Caused by a failure while trying to encode media samples. */
public static final int ERROR_CODE_ENCODING_FAILED = 4002;
- /** Caused by requesting to encode content in a format that is not supported by the device. */
- public static final int ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED = 4003;
+ /**
+ * Caused by the output format for a track not being supported.
+ *
+ *
Supported output formats are limited by the muxer's capabilities and the {@link
+ * Codec.DecoderFactory encoders} available.
+ */
+ public static final int ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED = 4003;
// Video editing errors (5xxx).
@@ -157,16 +161,8 @@ public final class TransformationException extends Exception {
public static final int ERROR_CODE_GL_PROCESSING_FAILED = 5002;
// Muxing errors (6xxx).
-
- /**
- * Caused by an output sample MIME type inferred from the input not being supported by the muxer.
- *
- *
Use {@link TransformationRequest.Builder#setAudioMimeType(String)} or {@link
- * TransformationRequest.Builder#setVideoMimeType(String)} to transcode to a supported MIME type.
- */
- public static final int ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED = 6001;
/** Caused by a failure while muxing media samples. */
- public static final int ERROR_CODE_MUXING_FAILED = 6002;
+ public static final int ERROR_CODE_MUXING_FAILED = 6001;
private static final ImmutableBiMap NAME_TO_ERROR_CODE =
new ImmutableBiMap.Builder()
@@ -185,12 +181,9 @@ public final class TransformationException extends Exception {
.put("ERROR_CODE_DECODING_FORMAT_UNSUPPORTED", ERROR_CODE_DECODING_FORMAT_UNSUPPORTED)
.put("ERROR_CODE_ENCODER_INIT_FAILED", ERROR_CODE_ENCODER_INIT_FAILED)
.put("ERROR_CODE_ENCODING_FAILED", ERROR_CODE_ENCODING_FAILED)
- .put("ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED", ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED)
+ .put("ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED", ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED)
.put("ERROR_CODE_GL_INIT_FAILED", ERROR_CODE_GL_INIT_FAILED)
.put("ERROR_CODE_GL_PROCESSING_FAILED", ERROR_CODE_GL_PROCESSING_FAILED)
- .put(
- "ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED",
- ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED)
.put("ERROR_CODE_MUXING_FAILED", ERROR_CODE_MUXING_FAILED)
.buildOrThrow();
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationRequest.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationRequest.java
index 22a7afabb1..d756dbffe4 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationRequest.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformationRequest.java
@@ -16,6 +16,8 @@
package com.google.android.exoplayer2.transformer;
+import static com.google.android.exoplayer2.util.Assertions.checkArgument;
+
import android.graphics.Matrix;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
@@ -23,6 +25,7 @@ import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
+import com.google.common.collect.ImmutableSet;
/** A media transformation request. */
public final class TransformationRequest {
@@ -30,6 +33,9 @@ public final class TransformationRequest {
/** A builder for {@link TransformationRequest} instances. */
public static final class Builder {
+ private static final ImmutableSet SUPPORTED_OUTPUT_HEIGHTS =
+ ImmutableSet.of(144, 240, 360, 480, 720, 1080, 1440, 2160);
+
private Matrix transformationMatrix;
private boolean flattenForSlowMotion;
private int outputHeight;
@@ -48,7 +54,7 @@ public final class TransformationRequest {
}
private Builder(TransformationRequest transformationRequest) {
- this.transformationMatrix = transformationRequest.transformationMatrix;
+ this.transformationMatrix = new Matrix(transformationRequest.transformationMatrix);
this.flattenForSlowMotion = transformationRequest.flattenForSlowMotion;
this.outputHeight = transformationRequest.outputHeight;
this.audioMimeType = transformationRequest.audioMimeType;
@@ -78,7 +84,7 @@ public final class TransformationRequest {
// TODO(b/213198690): Consider changing how transformationMatrix is applied, so that
// dimensions will be from -1 to 1 on both x and y axes, but transformations will be applied
// in a predictable manner.
- this.transformationMatrix = transformationMatrix;
+ this.transformationMatrix = new Matrix(transformationMatrix);
return this;
}
@@ -113,8 +119,9 @@ public final class TransformationRequest {
}
/**
- * Sets the output resolution using the output height. The default value is the same height as
- * the input. Output width will scale to preserve the input video's aspect ratio.
+ * Sets the output resolution using the output height. The default value {@link C#LENGTH_UNSET}
+ * corresponds to using the same height as the input. Output width will scale to preserve the
+ * input video's aspect ratio.
*
* For now, only "popular" heights like 144, 240, 360, 480, 720, 1080, 1440, or 2160 are
* supported, to ensure compatibility on different devices.
@@ -123,29 +130,24 @@ public final class TransformationRequest {
*
* @param outputHeight The output height in pixels.
* @return This builder.
+ * @throws IllegalArgumentException If the {@code outputHeight} is not supported.
*/
public Builder setResolution(int outputHeight) {
+ // TODO(b/209781577): Define outputHeight in the javadoc as height can be ambiguous for videos
+ // where rotationDegrees is set in the Format.
// TODO(b/201293185): Restructure to input a Presentation class.
// TODO(b/201293185): Check encoder codec capabilities in order to allow arbitrary
// resolutions and reasonable fallbacks.
- if (outputHeight != 144
- && outputHeight != 240
- && outputHeight != 360
- && outputHeight != 480
- && outputHeight != 720
- && outputHeight != 1080
- && outputHeight != 1440
- && outputHeight != 2160) {
- throw new IllegalArgumentException(
- "Please use a height of 144, 240, 360, 480, 720, 1080, 1440, or 2160.");
- }
+ checkArgument(
+ outputHeight == C.LENGTH_UNSET || SUPPORTED_OUTPUT_HEIGHTS.contains(outputHeight),
+ "Unsupported outputHeight: " + outputHeight);
this.outputHeight = outputHeight;
return this;
}
/**
- * Sets the video MIME type of the output. The default value is to use the same MIME type as the
- * input. Supported values are:
+ * Sets the video MIME type of the output. The default value is {@code null} which corresponds
+ * to using the same MIME type as the input. Supported MIME types are:
*
*
* {@link MimeTypes#VIDEO_H263}
@@ -156,17 +158,20 @@ public final class TransformationRequest {
*
* @param videoMimeType The MIME type of the video samples in the output.
* @return This builder.
+ * @throws IllegalArgumentException If the {@code videoMimeType} is non-null but not a video
+ * {@link MimeTypes MIME type}.
*/
- public Builder setVideoMimeType(String videoMimeType) {
- // TODO(b/209469847): Validate videoMimeType here once deprecated
- // Transformer.Builder#setOuputMimeType(String) has been removed.
+ public Builder setVideoMimeType(@Nullable String videoMimeType) {
+ checkArgument(
+ videoMimeType == null || MimeTypes.isVideo(videoMimeType),
+ "Not a video MIME type: " + videoMimeType);
this.videoMimeType = videoMimeType;
return this;
}
/**
- * Sets the audio MIME type of the output. The default value is to use the same MIME type as the
- * input. Supported values are:
+ * Sets the audio MIME type of the output. The default value is {@code null} which corresponds
+ * to using the same MIME type as the input. Supported MIME types are:
*
*
* {@link MimeTypes#AUDIO_AAC}
@@ -176,10 +181,13 @@ public final class TransformationRequest {
*
* @param audioMimeType The MIME type of the audio samples in the output.
* @return This builder.
+ * @throws IllegalArgumentException If the {@code audioMimeType} is non-null but not an audio
+ * {@link MimeTypes MIME type}.
*/
- public Builder setAudioMimeType(String audioMimeType) {
- // TODO(b/209469847): Validate audioMimeType here once deprecated
- // Transformer.Builder#setOuputMimeType(String) has been removed.
+ public Builder setAudioMimeType(@Nullable String audioMimeType) {
+ checkArgument(
+ audioMimeType == null || MimeTypes.isAudio(audioMimeType),
+ "Not an audio MIME type: " + audioMimeType);
this.audioMimeType = audioMimeType;
return this;
}
@@ -191,10 +199,37 @@ public final class TransformationRequest {
}
}
+ /**
+ * A {@link Matrix transformation matrix} to apply to video frames.
+ *
+ * @see Builder#setTransformationMatrix(Matrix)
+ */
public final Matrix transformationMatrix;
+ /**
+ * Whether the input should be flattened for media containing slow motion markers.
+ *
+ * @see Builder#setFlattenForSlowMotion(boolean)
+ */
public final boolean flattenForSlowMotion;
+ /**
+ * The requested height of the output video, or {@link C#LENGTH_UNSET} if inferred from the input.
+ *
+ * @see Builder#setResolution(int)
+ */
public final int outputHeight;
+ /**
+ * The requested output audio sample {@link MimeTypes MIME type}, or {@code null} if inferred from
+ * the input.
+ *
+ * @see Builder#setAudioMimeType(String)
+ */
@Nullable public final String audioMimeType;
+ /**
+ * The requested output video sample {@link MimeTypes MIME type}, or {@code null} if inferred from
+ * the input.
+ *
+ * @see Builder#setVideoMimeType(String)
+ */
@Nullable public final String videoMimeType;
private TransformationRequest(
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
index 52f0e96f61..e1f3348bf0 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/Transformer.java
@@ -462,6 +462,20 @@ public final class Transformer {
*/
default void onTransformationError(
MediaItem inputMediaItem, TransformationException exception) {}
+
+ /**
+ * Called when fallback to an alternative {@link TransformationRequest} is necessary to comply
+ * with muxer or device constraints.
+ *
+ * @param inputMediaItem The {@link MediaItem} for which the transformation is requested.
+ * @param originalTransformationRequest The unsupported {@link TransformationRequest} used when
+ * building {@link Transformer}.
+ * @param fallbackTransformationRequest The alternative {@link TransformationRequest}.
+ */
+ default void onFallbackApplied(
+ MediaItem inputMediaItem,
+ TransformationRequest originalTransformationRequest,
+ TransformationRequest fallbackTransformationRequest) {}
}
/** Provider for views to show diagnostic information during transformation, for debugging. */
@@ -689,6 +703,7 @@ public final class Transformer {
transformationRequest,
encoderFactory,
decoderFactory,
+ new FallbackListener(mediaItem, listeners, transformationRequest),
debugViewProvider))
.setMediaSourceFactory(mediaSourceFactory)
.setTrackSelector(trackSelector)
@@ -759,6 +774,7 @@ public final class Transformer {
*/
private void releaseResources(boolean forCancellation) throws TransformationException {
verifyApplicationThread();
+ progressState = PROGRESS_STATE_NO_TRANSFORMATION;
if (player != null) {
player.release();
player = null;
@@ -772,7 +788,6 @@ public final class Transformer {
}
muxerWrapper = null;
}
- progressState = PROGRESS_STATE_NO_TRANSFORMATION;
}
private void verifyApplicationThread() {
@@ -791,6 +806,7 @@ public final class Transformer {
private final TransformationRequest transformationRequest;
private final Codec.EncoderFactory encoderFactory;
private final Codec.DecoderFactory decoderFactory;
+ private final FallbackListener fallbackListener;
private final Transformer.DebugViewProvider debugViewProvider;
public TransformerRenderersFactory(
@@ -801,6 +817,7 @@ public final class Transformer {
TransformationRequest transformationRequest,
Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
+ FallbackListener fallbackListener,
Transformer.DebugViewProvider debugViewProvider) {
this.context = context;
this.muxerWrapper = muxerWrapper;
@@ -809,6 +826,7 @@ public final class Transformer {
this.transformationRequest = transformationRequest;
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
+ this.fallbackListener = fallbackListener;
this.debugViewProvider = debugViewProvider;
mediaClock = new TransformerMediaClock();
}
@@ -826,7 +844,12 @@ public final class Transformer {
if (!removeAudio) {
renderers[index] =
new TransformerAudioRenderer(
- muxerWrapper, mediaClock, transformationRequest, encoderFactory, decoderFactory);
+ muxerWrapper,
+ mediaClock,
+ transformationRequest,
+ encoderFactory,
+ decoderFactory,
+ fallbackListener);
index++;
}
if (!removeVideo) {
@@ -838,6 +861,7 @@ public final class Transformer {
transformationRequest,
encoderFactory,
decoderFactory,
+ fallbackListener,
debugViewProvider);
index++;
}
@@ -893,7 +917,7 @@ public final class Transformer {
@Override
public void onPlayerError(PlaybackException error) {
- Throwable cause = error.getCause();
+ @Nullable Throwable cause = error.getCause();
handleTransformationEnded(
cause instanceof TransformationException
? (TransformationException) cause
@@ -909,26 +933,24 @@ public final class Transformer {
} catch (RuntimeException e) {
resourceReleaseException = TransformationException.createForUnexpected(e);
}
-
- if (exception == null && resourceReleaseException == null) {
- // TODO(b/213341814): Add event flags for Transformer events.
- listeners.queueEvent(
- /* eventFlag= */ C.INDEX_UNSET,
- listener -> listener.onTransformationCompleted(mediaItem));
- listeners.flushEvents();
- return;
+ if (exception == null) {
+ // We only report the exception caused by releasing the resources if there is no other
+ // exception. It is more intuitive to call the error callback only once and reporting the
+ // exception caused by releasing the resources can be confusing if it is a consequence of
+ // the first exception.
+ exception = resourceReleaseException;
}
if (exception != null) {
+ TransformationException finalException = exception;
+ // TODO(b/213341814): Add event flags for Transformer events.
listeners.queueEvent(
/* eventFlag= */ C.INDEX_UNSET,
- listener -> listener.onTransformationError(mediaItem, exception));
- }
- if (resourceReleaseException != null) {
- TransformationException finalResourceReleaseException = resourceReleaseException;
+ listener -> listener.onTransformationError(mediaItem, finalException));
+ } else {
listeners.queueEvent(
/* eventFlag= */ C.INDEX_UNSET,
- listener -> listener.onTransformationError(mediaItem, finalResourceReleaseException));
+ listener -> listener.onTransformationCompleted(mediaItem));
}
listeners.flushEvents();
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java
index 5eac1382ee..f5fb4a7971 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerAudioRenderer.java
@@ -41,8 +41,9 @@ import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
TransformerMediaClock mediaClock,
TransformationRequest transformationRequest,
Codec.EncoderFactory encoderFactory,
- Codec.DecoderFactory decoderFactory) {
- super(C.TRACK_TYPE_AUDIO, muxerWrapper, mediaClock, transformationRequest);
+ Codec.DecoderFactory decoderFactory,
+ FallbackListener fallbackListener) {
+ super(C.TRACK_TYPE_AUDIO, muxerWrapper, mediaClock, transformationRequest, fallbackListener);
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
decoderInputBuffer =
@@ -67,22 +68,18 @@ import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
return false;
}
Format inputFormat = checkNotNull(formatHolder.format);
- String sampleMimeType = checkNotNull(inputFormat.sampleMimeType);
- if (transformationRequest.audioMimeType == null
- && !muxerWrapper.supportsSampleMimeType(sampleMimeType)) {
- throw TransformationException.createForMuxer(
- new IllegalArgumentException(
- "The output sample MIME inferred from the input format is not supported by the muxer."
- + " Sample MIME type: "
- + sampleMimeType),
- TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED);
- }
if (shouldPassthrough(inputFormat)) {
- samplePipeline = new PassthroughSamplePipeline(inputFormat);
+ samplePipeline =
+ new PassthroughSamplePipeline(inputFormat, transformationRequest, fallbackListener);
} else {
samplePipeline =
- new AudioSamplePipeline(
- inputFormat, transformationRequest, encoderFactory, decoderFactory);
+ new AudioTranscodingSamplePipeline(
+ inputFormat,
+ transformationRequest,
+ decoderFactory,
+ encoderFactory,
+ muxerWrapper.getSupportedSampleMimeTypes(getTrackType()),
+ fallbackListener);
}
return true;
}
@@ -92,6 +89,10 @@ import com.google.android.exoplayer2.source.SampleStream.ReadDataResult;
&& !transformationRequest.audioMimeType.equals(inputFormat.sampleMimeType)) {
return false;
}
+ if (transformationRequest.audioMimeType == null
+ && !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
+ return false;
+ }
if (transformationRequest.flattenForSlowMotion && isSlowMotion(inputFormat)) {
return false;
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java
index eecb0cae62..80244bc2a7 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerBaseRenderer.java
@@ -39,6 +39,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
protected final MuxerWrapper muxerWrapper;
protected final TransformerMediaClock mediaClock;
protected final TransformationRequest transformationRequest;
+ protected final FallbackListener fallbackListener;
protected boolean isRendererStarted;
protected boolean muxerWrapperTrackAdded;
@@ -50,11 +51,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
int trackType,
MuxerWrapper muxerWrapper,
TransformerMediaClock mediaClock,
- TransformationRequest transformationRequest) {
+ TransformationRequest transformationRequest,
+ FallbackListener fallbackListener) {
super(trackType);
this.muxerWrapper = muxerWrapper;
this.mediaClock = mediaClock;
this.transformationRequest = transformationRequest;
+ this.fallbackListener = fallbackListener;
}
/**
@@ -112,6 +115,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override
protected final void onEnabled(boolean joining, boolean mayRenderStartOfStream) {
muxerWrapper.registerTrack();
+ fallbackListener.registerTrack();
mediaClock.updateTimeForTrackType(getTrackType(), 0L);
}
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
index 82968f888f..062fecb0ab 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/TransformerVideoRenderer.java
@@ -48,8 +48,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
TransformationRequest transformationRequest,
Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
+ FallbackListener fallbackListener,
Transformer.DebugViewProvider debugViewProvider) {
- super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest);
+ super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest, fallbackListener);
this.context = context;
this.encoderFactory = encoderFactory;
this.decoderFactory = decoderFactory;
@@ -76,26 +77,19 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
return false;
}
Format inputFormat = checkNotNull(formatHolder.format);
- String sampleMimeType = checkNotNull(inputFormat.sampleMimeType);
- if (transformationRequest.videoMimeType == null
- && !muxerWrapper.supportsSampleMimeType(sampleMimeType)) {
- throw TransformationException.createForMuxer(
- new IllegalArgumentException(
- "The output sample MIME inferred from the input format is not supported by the muxer."
- + " Sample MIME type: "
- + sampleMimeType),
- TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED);
- }
if (shouldPassthrough(inputFormat)) {
- samplePipeline = new PassthroughSamplePipeline(inputFormat);
+ samplePipeline =
+ new PassthroughSamplePipeline(inputFormat, transformationRequest, fallbackListener);
} else {
samplePipeline =
- new VideoSamplePipeline(
+ new VideoTranscodingSamplePipeline(
context,
inputFormat,
transformationRequest,
- encoderFactory,
decoderFactory,
+ encoderFactory,
+ muxerWrapper.getSupportedSampleMimeTypes(getTrackType()),
+ fallbackListener,
debugViewProvider);
}
if (transformationRequest.flattenForSlowMotion) {
@@ -109,6 +103,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
&& !transformationRequest.videoMimeType.equals(inputFormat.sampleMimeType)) {
return false;
}
+ if (transformationRequest.videoMimeType == null
+ && !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
+ return false;
+ }
if (transformationRequest.outputHeight != C.LENGTH_UNSET
&& transformationRequest.outputHeight != inputFormat.height) {
return false;
diff --git a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
similarity index 72%
rename from library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java
rename to library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
index 0ad61f8dee..911f510c83 100644
--- a/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoSamplePipeline.java
+++ b/library/transformer/src/main/java/com/google/android/exoplayer2/transformer/VideoTranscodingSamplePipeline.java
@@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Util.SDK_INT;
import android.content.Context;
+import android.graphics.Matrix;
import android.media.MediaCodec;
import android.media.MediaFormat;
import androidx.annotation.Nullable;
@@ -27,14 +28,15 @@ import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
+import com.google.android.exoplayer2.util.Util;
+import java.util.List;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
+import org.checkerframework.dataflow.qual.Pure;
/**
* Pipeline to decode video samples, apply transformations on the raw samples, and re-encode them.
*/
-/* package */ final class VideoSamplePipeline implements SamplePipeline {
-
- private static final String TAG = "VideoSamplePipeline";
+/* package */ final class VideoTranscodingSamplePipeline implements SamplePipeline {
private final int outputRotationDegrees;
private final DecoderInputBuffer decoderInputBuffer;
@@ -47,12 +49,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private boolean waitingForFrameEditorInput;
- public VideoSamplePipeline(
+ public VideoTranscodingSamplePipeline(
Context context,
Format inputFormat,
TransformationRequest transformationRequest,
- Codec.EncoderFactory encoderFactory,
Codec.DecoderFactory decoderFactory,
+ Codec.EncoderFactory encoderFactory,
+ List allowedOutputMimeTypes,
+ FallbackListener fallbackListener,
Transformer.DebugViewProvider debugViewProvider)
throws TransformationException {
decoderInputBuffer =
@@ -62,7 +66,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
// Scale width and height to desired transformationRequest.outputHeight, preserving aspect
// ratio.
- // TODO(internal b/209781577): Think about which edge length should be set for portrait videos.
+ // TODO(b/209781577): Think about which edge length should be set for portrait videos.
float inputFormatAspectRatio = (float) inputFormat.width / inputFormat.height;
int outputWidth = inputFormat.width;
int outputHeight = inputFormat.height;
@@ -72,9 +76,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputHeight = transformationRequest.outputHeight;
}
- if (inputFormat.height > inputFormat.width) {
- // The encoder may not support encoding in portrait orientation, so the decoded video is
- // rotated to landscape orientation and a rotation is added back later to the output format.
+ // The encoder may not support encoding in portrait orientation, so the decoded video is
+ // rotated to landscape orientation and a rotation is added back later to the output format.
+ boolean swapEncodingDimensions = inputFormat.height > inputFormat.width;
+ if (swapEncodingDimensions) {
outputRotationDegrees = (inputFormat.rotationDegrees + 90) % 360;
int temp = outputWidth;
outputWidth = outputHeight;
@@ -87,43 +92,53 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
? inputFormatAspectRatio
: 1.0f / inputFormatAspectRatio;
+ Matrix transformationMatrix = new Matrix(transformationRequest.transformationMatrix);
// Scale frames by input aspect ratio, to account for FrameEditor's square normalized device
// coordinates (-1 to 1) and preserve frame relative dimensions during transformations
// (ex. rotations). After this scaling, transformationMatrix operations operate on a rectangle
// for x from -displayAspectRatio to displayAspectRatio, and y from -1 to 1
- transformationRequest.transformationMatrix.preScale(displayAspectRatio, 1);
- transformationRequest.transformationMatrix.postScale(1.0f / displayAspectRatio, 1);
+ transformationMatrix.preScale(displayAspectRatio, 1);
+ transformationMatrix.postScale(1.0f / displayAspectRatio, 1);
// The decoder rotates videos to their intended display orientation. The frameEditor rotates
// them back for improved encoder compatibility.
// TODO(b/201293185): After fragment shader transformations are implemented, put
// postRotate in a later vertex shader.
- transformationRequest.transformationMatrix.postRotate(outputRotationDegrees);
+ transformationMatrix.postRotate(outputRotationDegrees);
- encoder =
- encoderFactory.createForVideoEncoding(
- new Format.Builder()
- .setWidth(outputWidth)
- .setHeight(outputHeight)
- .setRotationDegrees(0)
- .setSampleMimeType(
- transformationRequest.videoMimeType != null
- ? transformationRequest.videoMimeType
- : inputFormat.sampleMimeType)
- .build());
- if (inputFormat.height != outputHeight
- || inputFormat.width != outputWidth
- || !transformationRequest.transformationMatrix.isIdentity()) {
+ Format requestedOutputFormat =
+ new Format.Builder()
+ .setWidth(outputWidth)
+ .setHeight(outputHeight)
+ .setRotationDegrees(0)
+ .setSampleMimeType(
+ transformationRequest.videoMimeType != null
+ ? transformationRequest.videoMimeType
+ : inputFormat.sampleMimeType)
+ .build();
+ encoder = encoderFactory.createForVideoEncoding(requestedOutputFormat, allowedOutputMimeTypes);
+ Format actualOutputFormat = encoder.getConfigurationFormat();
+ fallbackListener.onTransformationRequestFinalized(
+ createFallbackTransformationRequest(
+ transformationRequest,
+ !swapEncodingDimensions,
+ requestedOutputFormat,
+ actualOutputFormat));
+
+ if (inputFormat.height != actualOutputFormat.height
+ || inputFormat.width != actualOutputFormat.width
+ || !transformationMatrix.isIdentity()) {
frameEditor =
FrameEditor.create(
context,
- outputWidth,
- outputHeight,
+ actualOutputFormat.width,
+ actualOutputFormat.height,
inputFormat.pixelWidthHeightRatio,
- transformationRequest.transformationMatrix,
+ transformationMatrix,
/* outputSurface= */ checkNotNull(encoder.getInputSurface()),
debugViewProvider);
}
+
decoder =
decoderFactory.createForVideoDecoding(
inputFormat,
@@ -221,7 +236,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override
@Nullable
public Format getOutputFormat() throws TransformationException {
- Format format = encoder.getOutputFormat();
+ @Nullable Format format = encoder.getOutputFormat();
return format == null
? null
: format.buildUpon().setRotationDegrees(outputRotationDegrees).build();
@@ -258,4 +273,24 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
decoder.release();
encoder.release();
}
+
+ @Pure
+ private static TransformationRequest createFallbackTransformationRequest(
+ TransformationRequest transformationRequest,
+ boolean resolutionIsHeight,
+ Format requestedFormat,
+ Format actualFormat) {
+ // TODO(b/210591626): Also update bitrate etc. once encoder configuration and fallback are
+ // implemented.
+ if (Util.areEqual(requestedFormat.sampleMimeType, actualFormat.sampleMimeType)
+ && ((!resolutionIsHeight && requestedFormat.width == actualFormat.width)
+ || (resolutionIsHeight && requestedFormat.height == actualFormat.height))) {
+ return transformationRequest;
+ }
+ return transformationRequest
+ .buildUpon()
+ .setVideoMimeType(actualFormat.sampleMimeType)
+ .setResolution(resolutionIsHeight ? requestedFormat.height : requestedFormat.width)
+ .build();
+ }
}
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/FallbackListenerTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/FallbackListenerTest.java
new file mode 100644
index 0000000000..f7f2894b45
--- /dev/null
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/FallbackListenerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2022 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 com.google.android.exoplayer2.transformer;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.net.Uri;
+import android.os.Looper;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.util.Clock;
+import com.google.android.exoplayer2.util.ListenerSet;
+import com.google.android.exoplayer2.util.MimeTypes;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link FallbackListener}. */
+@RunWith(AndroidJUnit4.class)
+public class FallbackListenerTest {
+
+ private static final MediaItem PLACEHOLDER_MEDIA_ITEM = MediaItem.fromUri(Uri.EMPTY);
+
+ @Test
+ public void onTransformationRequestFinalized_withoutTrackRegistration_throwsException() {
+ TransformationRequest transformationRequest = new TransformationRequest.Builder().build();
+ FallbackListener fallbackListener =
+ new FallbackListener(PLACEHOLDER_MEDIA_ITEM, createListenerSet(), transformationRequest);
+
+ assertThrows(
+ IllegalStateException.class,
+ () -> fallbackListener.onTransformationRequestFinalized(transformationRequest));
+ }
+
+ @Test
+ public void onTransformationRequestFinalized_afterTrackRegistration_completesSuccessfully() {
+ TransformationRequest transformationRequest = new TransformationRequest.Builder().build();
+ FallbackListener fallbackListener =
+ new FallbackListener(PLACEHOLDER_MEDIA_ITEM, createListenerSet(), transformationRequest);
+
+ fallbackListener.registerTrack();
+ fallbackListener.onTransformationRequestFinalized(transformationRequest);
+ }
+
+ @Test
+ public void onTransformationRequestFinalized_withUnchangedRequest_doesNotCallback() {
+ TransformationRequest originalRequest =
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
+ TransformationRequest unchangedRequest = originalRequest.buildUpon().build();
+ Transformer.Listener mockListener = mock(Transformer.Listener.class);
+ FallbackListener fallbackListener =
+ new FallbackListener(
+ PLACEHOLDER_MEDIA_ITEM, createListenerSet(mockListener), originalRequest);
+
+ fallbackListener.registerTrack();
+ fallbackListener.onTransformationRequestFinalized(unchangedRequest);
+
+ verify(mockListener, never()).onFallbackApplied(any(), any(), any());
+ }
+
+ @Test
+ public void onTransformationRequestFinalized_withDifferentRequest_callsCallback() {
+ TransformationRequest originalRequest =
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
+ TransformationRequest audioFallbackRequest =
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AMR_WB).build();
+ Transformer.Listener mockListener = mock(Transformer.Listener.class);
+ FallbackListener fallbackListener =
+ new FallbackListener(
+ PLACEHOLDER_MEDIA_ITEM, createListenerSet(mockListener), originalRequest);
+
+ fallbackListener.registerTrack();
+ fallbackListener.onTransformationRequestFinalized(audioFallbackRequest);
+
+ verify(mockListener, times(1))
+ .onFallbackApplied(PLACEHOLDER_MEDIA_ITEM, originalRequest, audioFallbackRequest);
+ }
+
+ @Test
+ public void
+ onTransformationRequestFinalized_forMultipleTracks_callsCallbackOnceWithMergedRequest() {
+ TransformationRequest originalRequest =
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
+ TransformationRequest audioFallbackRequest =
+ originalRequest.buildUpon().setAudioMimeType(MimeTypes.AUDIO_AMR_WB).build();
+ TransformationRequest videoFallbackRequest =
+ originalRequest.buildUpon().setVideoMimeType(MimeTypes.VIDEO_H264).build();
+ TransformationRequest mergedFallbackRequest =
+ new TransformationRequest.Builder()
+ .setAudioMimeType(MimeTypes.AUDIO_AMR_WB)
+ .setVideoMimeType(MimeTypes.VIDEO_H264)
+ .build();
+ Transformer.Listener mockListener = mock(Transformer.Listener.class);
+ FallbackListener fallbackListener =
+ new FallbackListener(
+ PLACEHOLDER_MEDIA_ITEM, createListenerSet(mockListener), originalRequest);
+
+ fallbackListener.registerTrack();
+ fallbackListener.registerTrack();
+ fallbackListener.onTransformationRequestFinalized(audioFallbackRequest);
+ fallbackListener.onTransformationRequestFinalized(videoFallbackRequest);
+
+ verify(mockListener, times(1))
+ .onFallbackApplied(PLACEHOLDER_MEDIA_ITEM, originalRequest, mergedFallbackRequest);
+ }
+
+ private static ListenerSet createListenerSet(
+ Transformer.Listener transformerListener) {
+ ListenerSet listenerSet = createListenerSet();
+ listenerSet.add(transformerListener);
+ return listenerSet;
+ }
+
+ private static ListenerSet createListenerSet() {
+ return new ListenerSet<>(Looper.myLooper(), Clock.DEFAULT, (listener, flags) -> {});
+ }
+}
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformationRequestBuilderTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformationRequestBuilderTest.java
new file mode 100644
index 0000000000..b55125c98a
--- /dev/null
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformationRequestBuilderTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 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 com.google.android.exoplayer2.transformer;
+
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.android.exoplayer2.util.MimeTypes;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Unit test for {@link TransformationRequest.Builder}. */
+@RunWith(AndroidJUnit4.class)
+public class TransformationRequestBuilderTest {
+
+ @Test
+ public void setAudioMimeType_withVideoMimeType_throws() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new TransformationRequest.Builder().setAudioMimeType(MimeTypes.VIDEO_H264));
+ }
+
+ @Test
+ public void setVideoMimeType_withAudioMimeType_throws() {
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> new TransformationRequest.Builder().setVideoMimeType(MimeTypes.AUDIO_AAC));
+ }
+}
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerBuilderTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerBuilderTest.java
index bff87ff35e..e96f136fdd 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerBuilderTest.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerBuilderTest.java
@@ -52,8 +52,6 @@ public class TransformerBuilderTest {
() -> new Transformer.Builder(context).setRemoveAudio(true).setRemoveVideo(true).build());
}
- // TODO(b/209469847): Move this test to TransformationRequestBuilderTest once deprecated
- // Transformer.Builder#setOuputMimeType(String) has been removed.
@Test
public void build_withUnsupportedAudioMimeType_throws() {
Context context = ApplicationProvider.getApplicationContext();
@@ -68,8 +66,6 @@ public class TransformerBuilderTest {
.build());
}
- // TODO(b/209469847): Move this test to TransformationRequestBuilderTest once deprecated
- // Transformer.Builder#setOuputMimeType(String) has been removed.
@Test
public void build_withUnsupportedVideoMimeType_throws() {
Context context = ApplicationProvider.getApplicationContext();
diff --git a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
index 376a0e08b4..b652594c54 100644
--- a/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
+++ b/library/transformer/src/test/java/com/google/android/exoplayer2/transformer/TransformerTest.java
@@ -23,6 +23,7 @@ import static com.google.android.exoplayer2.transformer.Transformer.PROGRESS_STA
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -65,6 +66,7 @@ import org.robolectric.shadows.ShadowMediaCodec;
/** Unit test for {@link Transformer}. */
@RunWith(AndroidJUnit4.class)
public final class TransformerTest {
+ // TODO(b/214973843): Disable fallback for all tests that aren't specifically testing fallback.
private static final String URI_PREFIX = "asset:///media/";
private static final String FILE_VIDEO_ONLY = "mp4/sample_18byte_nclx_colr.mp4";
@@ -74,7 +76,6 @@ public final class TransformerTest {
private static final String FILE_AUDIO_UNSUPPORTED_BY_DECODER = "amr/sample_wb.amr";
private static final String FILE_AUDIO_UNSUPPORTED_BY_ENCODER = "amr/sample_nb.amr";
private static final String FILE_AUDIO_UNSUPPORTED_BY_MUXER = "mp4/sample_ac3.mp4";
- private static final String FILE_VIDEO_UNSUPPORTED = "vp9/bear-vp9.webm";
private static final String FILE_UNKNOWN_DURATION = "mp4/sample_fragmented.mp4";
public static final String DUMP_FILE_OUTPUT_DIRECTORY = "transformerdumps";
public static final String DUMP_FILE_EXTENSION = "dump";
@@ -102,11 +103,7 @@ public final class TransformerTest {
@Test
public void startTransformation_videoOnlyPassthrough_completesSuccessfully() throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
transformer.startTransformation(mediaItem, outputPath);
@@ -117,11 +114,7 @@ public final class TransformerTest {
@Test
public void startTransformation_audioOnlyPassthrough_completesSuccessfully() throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER);
@@ -135,9 +128,7 @@ public final class TransformerTest {
@Test
public void startTransformation_audioOnlyTranscoding_completesSuccessfully() throws Exception {
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.setTransformationRequest(
new TransformationRequest.Builder()
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
@@ -154,11 +145,7 @@ public final class TransformerTest {
@Test
public void startTransformation_audioAndVideo_completesSuccessfully() throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
transformer.startTransformation(mediaItem, outputPath);
@@ -170,9 +157,7 @@ public final class TransformerTest {
@Test
public void startTransformation_withSubtitles_completesSuccessfully() throws Exception {
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.setTransformationRequest(
new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build())
.build();
@@ -187,11 +172,7 @@ public final class TransformerTest {
@Test
public void startTransformation_successiveTransformations_completesSuccessfully()
throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
// Transform first media item.
@@ -208,7 +189,7 @@ public final class TransformerTest {
@Test
public void startTransformation_concurrentTransformations_throwsError() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
transformer.startTransformation(mediaItem, outputPath);
@@ -219,12 +200,7 @@ public final class TransformerTest {
@Test
public void startTransformation_removeAudio_completesSuccessfully() throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setRemoveAudio(true)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().setRemoveAudio(true).build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
transformer.startTransformation(mediaItem, outputPath);
@@ -236,12 +212,7 @@ public final class TransformerTest {
@Test
public void startTransformation_removeVideo_completesSuccessfully() throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setRemoveVideo(true)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().setRemoveVideo(true).build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
transformer.startTransformation(mediaItem, outputPath);
@@ -257,9 +228,7 @@ public final class TransformerTest {
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.addListener(mockListener1)
.addListener(mockListener2)
.addListener(mockListener3)
@@ -280,14 +249,14 @@ public final class TransformerTest {
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.addListener(mockListener1)
.addListener(mockListener2)
.addListener(mockListener3)
+ .setTransformationRequest( // Request transcoding so that decoder is used.
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build())
.build();
- MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
+ MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_DECODER);
transformer.startTransformation(mediaItem, outputPath);
TransformationException exception = TransformerTestRunner.runUntilError(transformer);
@@ -297,6 +266,34 @@ public final class TransformerTest {
verify(mockListener3, times(1)).onTransformationError(mediaItem, exception);
}
+ @Test
+ public void startTransformation_withMultipleListeners_callsEachOnFallback() throws Exception {
+ Transformer.Listener mockListener1 = mock(Transformer.Listener.class);
+ Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
+ Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
+ TransformationRequest originalTransformationRequest =
+ new TransformationRequest.Builder().build();
+ TransformationRequest fallbackTransformationRequest =
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
+ Transformer transformer =
+ createTransformerBuilder()
+ .addListener(mockListener1)
+ .addListener(mockListener2)
+ .addListener(mockListener3)
+ .build();
+ MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
+
+ transformer.startTransformation(mediaItem, outputPath);
+ TransformerTestRunner.runUntilCompleted(transformer);
+
+ verify(mockListener1, times(1))
+ .onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
+ verify(mockListener2, times(1))
+ .onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
+ verify(mockListener3, times(1))
+ .onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
+ }
+
@Test
public void startTransformation_afterBuildUponWithListenerRemoved_onlyCallsRemainingListeners()
throws Exception {
@@ -304,9 +301,7 @@ public final class TransformerTest {
Transformer.Listener mockListener2 = mock(Transformer.Listener.class);
Transformer.Listener mockListener3 = mock(Transformer.Listener.class);
Transformer transformer1 =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.addListener(mockListener1)
.addListener(mockListener2)
.addListener(mockListener3)
@@ -318,16 +313,14 @@ public final class TransformerTest {
TransformerTestRunner.runUntilCompleted(transformer2);
verify(mockListener1, times(1)).onTransformationCompleted(mediaItem);
- verify(mockListener2, times(0)).onTransformationCompleted(mediaItem);
+ verify(mockListener2, never()).onTransformationCompleted(mediaItem);
verify(mockListener3, times(1)).onTransformationCompleted(mediaItem);
}
@Test
public void startTransformation_flattenForSlowMotion_completesSuccessfully() throws Exception {
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.setTransformationRequest(
new TransformationRequest.Builder().setFlattenForSlowMotion(true).build())
.build();
@@ -343,9 +336,7 @@ public final class TransformerTest {
public void startTransformation_withAudioEncoderFormatUnsupported_completesWithError()
throws Exception {
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.setTransformationRequest(
new TransformationRequest.Builder()
.setAudioMimeType(
@@ -359,16 +350,14 @@ public final class TransformerTest {
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
assertThat(exception.errorCode)
- .isEqualTo(TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED);
+ .isEqualTo(TransformationException.ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED);
}
@Test
public void startTransformation_withAudioDecoderFormatUnsupported_completesWithError()
throws Exception {
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.setTransformationRequest(
new TransformationRequest.Builder()
.setAudioMimeType(MimeTypes.AUDIO_AAC) // supported by encoder and muxer
@@ -388,9 +377,7 @@ public final class TransformerTest {
public void startTransformation_withVideoEncoderFormatUnsupported_completesWithError()
throws Exception {
Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
+ createTransformerBuilder()
.setTransformationRequest(
new TransformationRequest.Builder()
.setVideoMimeType(MimeTypes.VIDEO_H263) // unsupported encoder MIME type
@@ -403,12 +390,12 @@ public final class TransformerTest {
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
assertThat(exception.errorCode)
- .isEqualTo(TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED);
+ .isEqualTo(TransformationException.ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED);
}
@Test
public void startTransformation_withIoError_completesWithError() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri("asset:///non-existing-path.mp4");
transformer.startTransformation(mediaItem, outputPath);
@@ -419,50 +406,32 @@ public final class TransformerTest {
}
@Test
- public void startTransformation_withAudioMuxerFormatUnsupported_completesWithError()
+ public void startTransformation_withAudioMuxerFormatFallback_completesSuccessfully()
throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer.Listener mockListener = mock(Transformer.Listener.class);
+ TransformationRequest originalTransformationRequest =
+ new TransformationRequest.Builder().build();
+ TransformationRequest fallbackTransformationRequest =
+ new TransformationRequest.Builder().setAudioMimeType(MimeTypes.AUDIO_AAC).build();
+ Transformer transformer = createTransformerBuilder().addListener(mockListener).build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_MUXER);
transformer.startTransformation(mediaItem, outputPath);
- TransformationException exception = TransformerTestRunner.runUntilError(transformer);
+ TransformerTestRunner.runUntilCompleted(transformer);
- assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
- assertThat(exception).hasCauseThat().hasMessageThat().contains("audio");
- assertThat(exception.errorCode)
- .isEqualTo(TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED);
+ DumpFileAsserts.assertOutput(
+ context, testMuxer, getDumpFileName(FILE_AUDIO_UNSUPPORTED_BY_MUXER + ".fallback"));
+ verify(mockListener, times(1))
+ .onFallbackApplied(mediaItem, originalTransformationRequest, fallbackTransformationRequest);
}
- @Test
- public void startTransformation_withVideoMuxerFormatUnsupported_completesWithError()
- throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
- MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_UNSUPPORTED);
-
- transformer.startTransformation(mediaItem, outputPath);
- TransformationException exception = TransformerTestRunner.runUntilError(transformer);
-
- assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
- assertThat(exception).hasCauseThat().hasMessageThat().contains("video");
- assertThat(exception.errorCode)
- .isEqualTo(TransformationException.ERROR_CODE_MUXER_SAMPLE_MIME_TYPE_UNSUPPORTED);
- }
+ // TODO(b/214012830): Add a test to check that the correct exception is thrown when the muxer
+ // doesn't support the output sample MIME type inferred from the input once it is possible to
+ // disable fallback.
@Test
public void startTransformation_afterCancellation_completesSuccessfully() throws Exception {
- Transformer transformer =
- new Transformer.Builder(context)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
transformer.startTransformation(mediaItem, outputPath);
@@ -481,12 +450,7 @@ public final class TransformerTest {
HandlerThread anotherThread = new HandlerThread("AnotherThread");
anotherThread.start();
Looper looper = anotherThread.getLooper();
- Transformer transformer =
- new Transformer.Builder(context)
- .setLooper(looper)
- .setClock(clock)
- .setMuxerFactory(new TestMuxerFactory())
- .build();
+ Transformer transformer = createTransformerBuilder().setLooper(looper).build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
AtomicReference exception = new AtomicReference<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -511,7 +475,7 @@ public final class TransformerTest {
@Test
public void startTransformation_fromWrongThread_throwsError() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_AUDIO_VIDEO);
HandlerThread anotherThread = new HandlerThread("AnotherThread");
AtomicReference illegalStateException = new AtomicReference<>();
@@ -538,7 +502,7 @@ public final class TransformerTest {
@Test
public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
AtomicInteger previousProgressState =
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
@@ -584,7 +548,7 @@ public final class TransformerTest {
@Test
public void getProgress_knownDuration_givesIncreasingPercentages() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
List progresses = new ArrayList<>();
Handler progressHandler =
@@ -619,7 +583,7 @@ public final class TransformerTest {
@Test
public void getProgress_noCurrentTransformation_returnsNoTransformation() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
@Transformer.ProgressState int stateBeforeTransform = transformer.getProgress(progressHolder);
@@ -633,7 +597,7 @@ public final class TransformerTest {
@Test
public void getProgress_unknownDuration_returnsConsistentStates() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_UNKNOWN_DURATION);
AtomicInteger previousProgressState =
new AtomicInteger(PROGRESS_STATE_WAITING_FOR_AVAILABILITY);
@@ -676,7 +640,7 @@ public final class TransformerTest {
@Test
public void getProgress_fromWrongThread_throwsError() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
HandlerThread anotherThread = new HandlerThread("AnotherThread");
AtomicReference illegalStateException = new AtomicReference<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -700,7 +664,7 @@ public final class TransformerTest {
@Test
public void cancel_afterCompletion_doesNotThrow() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
MediaItem mediaItem = MediaItem.fromUri(URI_PREFIX + FILE_VIDEO_ONLY);
transformer.startTransformation(mediaItem, outputPath);
@@ -710,7 +674,7 @@ public final class TransformerTest {
@Test
public void cancel_fromWrongThread_throwsError() throws Exception {
- Transformer transformer = new Transformer.Builder(context).setClock(clock).build();
+ Transformer transformer = createTransformerBuilder().build();
HandlerThread anotherThread = new HandlerThread("AnotherThread");
AtomicReference illegalStateException = new AtomicReference<>();
CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -732,6 +696,10 @@ public final class TransformerTest {
assertThat(illegalStateException.get()).isNotNull();
}
+ private Transformer.Builder createTransformerBuilder() {
+ return new Transformer.Builder(context).setClock(clock).setMuxerFactory(new TestMuxerFactory());
+ }
+
private static void createEncodersAndDecoders() {
ShadowMediaCodec.CodecConfig codecConfig =
new ShadowMediaCodec.CodecConfig(
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
index 462da93a6c..abb554855b 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
@@ -1478,6 +1478,7 @@ public class PlayerNotificationManager {
return actions;
}
+ @SuppressWarnings("UnspecifiedImmutableFlag") // Warning is spurious.
private static PendingIntent createBroadcastIntent(
String action, Context context, int instanceId) {
Intent intent = new Intent(action).setPackage(context.getPackageName());
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
index b20adf781f..b63deaf5b3 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
@@ -360,6 +360,9 @@ public class StyledPlayerControlView extends FrameLayout {
public static final int MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR = 100;
/** The maximum interval between time bar position updates. */
private static final int MAX_UPDATE_INTERVAL_MS = 1_000;
+ // LINT.IfChange(playback_speeds)
+ private static final float[] PLAYBACK_SPEEDS =
+ new float[] {0.25f, 0.5f, 0.75f, 1f, 1.25f, 1.5f, 2f};
private static final int SETTINGS_PLAYBACK_SPEED_POSITION = 0;
private static final int SETTINGS_AUDIO_TRACK_SELECTION_POSITION = 1;
@@ -686,8 +689,7 @@ public class StyledPlayerControlView extends FrameLayout {
audioTrackSelectionAdapter = new AudioTrackSelectionAdapter();
playbackSpeedAdapter =
new PlaybackSpeedAdapter(
- resources.getStringArray(R.array.exo_playback_speeds),
- resources.getIntArray(R.array.exo_speed_multiplied_by_100));
+ resources.getStringArray(R.array.exo_controls_playback_speeds), PLAYBACK_SPEEDS);
fullScreenExitDrawable = resources.getDrawable(R.drawable.exo_styled_controls_fullscreen_exit);
fullScreenEnterDrawable =
@@ -1877,20 +1879,19 @@ public class StyledPlayerControlView extends FrameLayout {
private final class PlaybackSpeedAdapter extends RecyclerView.Adapter {
private final String[] playbackSpeedTexts;
- private final int[] playbackSpeedsMultBy100;
+ private final float[] playbackSpeeds;
private int selectedIndex;
- public PlaybackSpeedAdapter(String[] playbackSpeedTexts, int[] playbackSpeedsMultBy100) {
+ public PlaybackSpeedAdapter(String[] playbackSpeedTexts, float[] playbackSpeeds) {
this.playbackSpeedTexts = playbackSpeedTexts;
- this.playbackSpeedsMultBy100 = playbackSpeedsMultBy100;
+ this.playbackSpeeds = playbackSpeeds;
}
public void updateSelectedIndex(float playbackSpeed) {
- int currentSpeedMultBy100 = Math.round(playbackSpeed * 100);
int closestMatchIndex = 0;
- int closestMatchDifference = Integer.MAX_VALUE;
- for (int i = 0; i < playbackSpeedsMultBy100.length; i++) {
- int difference = Math.abs(currentSpeedMultBy100 - playbackSpeedsMultBy100[i]);
+ float closestMatchDifference = Float.MAX_VALUE;
+ for (int i = 0; i < playbackSpeeds.length; i++) {
+ float difference = Math.abs(playbackSpeed - playbackSpeeds[i]);
if (difference < closestMatchDifference) {
closestMatchIndex = i;
closestMatchDifference = difference;
@@ -1921,8 +1922,7 @@ public class StyledPlayerControlView extends FrameLayout {
holder.itemView.setOnClickListener(
v -> {
if (position != selectedIndex) {
- float speed = playbackSpeedsMultBy100[position] / 100.0f;
- setPlaybackSpeed(speed);
+ setPlaybackSpeed(playbackSpeeds[position]);
}
settingsWindow.dismiss();
});
diff --git a/library/ui/src/main/res/values-af/strings.xml b/library/ui/src/main/res/values-af/strings.xml
index 17b324a53e..4511839582 100644
--- a/library/ui/src/main/res/values-af/strings.xml
+++ b/library/ui/src/main/res/values-af/strings.xml
@@ -46,7 +46,15 @@
Deaktiveer onderskrifte
Aktiveer onderskrifte
Spoed
- Normaal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normaal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Oudio
Teks
diff --git a/library/ui/src/main/res/values-am/strings.xml b/library/ui/src/main/res/values-am/strings.xml
index ee748779f6..a35bf1a6f5 100644
--- a/library/ui/src/main/res/values-am/strings.xml
+++ b/library/ui/src/main/res/values-am/strings.xml
@@ -46,7 +46,15 @@
የግርጌ ጽሑፎችን አሰናክል
የግርጌ ጽሑፎችን አንቃ
ፍጥነት
- መደበኛ
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - መደበኛ
+ - 1.25x
+ - 1.5x
+ - 2x
+
ቪዲዮ
ኦዲዮ
ጽሑፍ
diff --git a/library/ui/src/main/res/values-ar/strings.xml b/library/ui/src/main/res/values-ar/strings.xml
index 0674a817fd..c7e48f7879 100644
--- a/library/ui/src/main/res/values-ar/strings.xml
+++ b/library/ui/src/main/res/values-ar/strings.xml
@@ -54,7 +54,15 @@
إيقاف الترجمة
تفعيل الترجمة
السرعة
- عادية
+
+ - أسرع بـ 0.25 مرة
+ - أسرع بـ 0.5 مرات
+ - أسرع بـ 0.75 مرة
+ - عادية
+ - أسرع بـ 1.25 مرة
+ - أسرع بـ 1.5 مرة
+ - أسرع بمرتين
+
فيديو
صوت
نص
diff --git a/library/ui/src/main/res/values-az/strings.xml b/library/ui/src/main/res/values-az/strings.xml
index a5c778230f..5f8cce18e3 100644
--- a/library/ui/src/main/res/values-az/strings.xml
+++ b/library/ui/src/main/res/values-az/strings.xml
@@ -46,7 +46,15 @@
Subtitrləri deaktiv edin
Subtitrləri aktiv edin
Sürət
- Normal
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Normal
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Mətn
diff --git a/library/ui/src/main/res/values-b+sr+Latn/strings.xml b/library/ui/src/main/res/values-b+sr+Latn/strings.xml
index 84862309a4..8173fb6361 100644
--- a/library/ui/src/main/res/values-b+sr+Latn/strings.xml
+++ b/library/ui/src/main/res/values-b+sr+Latn/strings.xml
@@ -48,7 +48,15 @@
Onemogući titlove
Omogući titlove
Brzina
- Uobičajena
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normalno
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Tekst
diff --git a/library/ui/src/main/res/values-be/strings.xml b/library/ui/src/main/res/values-be/strings.xml
index 61e530aec3..82518faecf 100644
--- a/library/ui/src/main/res/values-be/strings.xml
+++ b/library/ui/src/main/res/values-be/strings.xml
@@ -50,7 +50,15 @@
Выключыць субцітры
Уключыць субцітры
Хуткасць
- Звычайная
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Звычайная
+ - 1,25x
+ - 1,5x
+ - 2х
+
Відэа
Аўдыя
Тэкст
diff --git a/library/ui/src/main/res/values-bg/strings.xml b/library/ui/src/main/res/values-bg/strings.xml
index 79eb9aa9f9..056c5b9e83 100644
--- a/library/ui/src/main/res/values-bg/strings.xml
+++ b/library/ui/src/main/res/values-bg/strings.xml
@@ -46,7 +46,15 @@
Деактивиране на субтитрите
Активиране на субтитрите
Скорост
- Нормално
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Нормално
+ - 1,25x
+ - 1,5x
+ - 2x
+
Видеозапис
Аудиозапис
Текст
diff --git a/library/ui/src/main/res/values-bn/strings.xml b/library/ui/src/main/res/values-bn/strings.xml
index f5bb60110b..bf438cc335 100644
--- a/library/ui/src/main/res/values-bn/strings.xml
+++ b/library/ui/src/main/res/values-bn/strings.xml
@@ -46,7 +46,15 @@
সাবটাইটেল বন্ধ করুন
সাবটাইটেল চালু করুন
স্পিড
- সাধারণ
+
+ - ০.২৫x
+ - ০.৫x
+ - ০.৭৫x
+ - স্বাভাবিক
+ - ১.২৫x
+ - ১.৫x
+ - ২x
+
ভিডিও
অডিও
টেক্সট
diff --git a/library/ui/src/main/res/values-bs/strings.xml b/library/ui/src/main/res/values-bs/strings.xml
index eba7f1aa87..8ce4cf7648 100644
--- a/library/ui/src/main/res/values-bs/strings.xml
+++ b/library/ui/src/main/res/values-bs/strings.xml
@@ -48,7 +48,15 @@
Onemogućavanje titlova
Omogućavanje titlova
Brzina
- Normalno
+
+ - 0,25 x
+ - 0,5 x
+ - 0,75 x
+ - Normalno
+ - 1,25 x
+ - 1,5 x
+ - 2 x
+
Videozapis
Zvuk
Tekst
diff --git a/library/ui/src/main/res/values-ca/strings.xml b/library/ui/src/main/res/values-ca/strings.xml
index 5e045349a3..46aef87dd1 100644
--- a/library/ui/src/main/res/values-ca/strings.xml
+++ b/library/ui/src/main/res/values-ca/strings.xml
@@ -46,7 +46,15 @@
Desactiva els subtítols
Activa els subtítols
Velocitat
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Vídeo
Àudio
Text
diff --git a/library/ui/src/main/res/values-cs/strings.xml b/library/ui/src/main/res/values-cs/strings.xml
index a8e57eeb13..6144f3cad3 100644
--- a/library/ui/src/main/res/values-cs/strings.xml
+++ b/library/ui/src/main/res/values-cs/strings.xml
@@ -50,7 +50,15 @@
Vypnout titulky
Zapnout titulky
Rychlost
- Normální
+
+ - 0,25×
+ - 0,5×
+ - 0,75×
+ - Normální
+ - 1,25×
+ - 1,5×
+ - 2×
+
Videa
Zvuk
Text
diff --git a/library/ui/src/main/res/values-da/strings.xml b/library/ui/src/main/res/values-da/strings.xml
index f0e7214b97..e7a07fef48 100644
--- a/library/ui/src/main/res/values-da/strings.xml
+++ b/library/ui/src/main/res/values-da/strings.xml
@@ -46,7 +46,15 @@
Deaktiver undertekster
Aktivér undertekster
Hastighed
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Lyd
Undertekst
diff --git a/library/ui/src/main/res/values-de/strings.xml b/library/ui/src/main/res/values-de/strings.xml
index 42b74bbab9..05087df6a2 100644
--- a/library/ui/src/main/res/values-de/strings.xml
+++ b/library/ui/src/main/res/values-de/strings.xml
@@ -46,7 +46,15 @@
Untertitel deaktivieren
Untertitel aktivieren
Geschwindigkeit
- Normal
+
+ - 0,25-fach
+ - 0,5-fach
+ - 0,75-fach
+ - Standard
+ - 1,25-fach
+ - 1,5-fach
+ - 2-fach
+
Video
Audio
Text
diff --git a/library/ui/src/main/res/values-el/strings.xml b/library/ui/src/main/res/values-el/strings.xml
index 43037e7ce4..d7d00f184e 100644
--- a/library/ui/src/main/res/values-el/strings.xml
+++ b/library/ui/src/main/res/values-el/strings.xml
@@ -46,7 +46,15 @@
Απενεργοποίηση υπότιτλων
Ενεργοποίηση υπότιτλων
Ταχύτητα
- Κανονική
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Κανονική
+ - 1,25x
+ - 1,5x
+ - 2x
+
Βίντεο
Ήχος
Κείμενο
diff --git a/library/ui/src/main/res/values-en-rAU/strings.xml b/library/ui/src/main/res/values-en-rAU/strings.xml
index 4a33eb5ba7..c3a1c8a5aa 100644
--- a/library/ui/src/main/res/values-en-rAU/strings.xml
+++ b/library/ui/src/main/res/values-en-rAU/strings.xml
@@ -46,7 +46,15 @@
Disable subtitles
Enable subtitles
Speed
- Normal
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Normal
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Text
diff --git a/library/ui/src/main/res/values-en-rGB/strings.xml b/library/ui/src/main/res/values-en-rGB/strings.xml
index 4a33eb5ba7..c3a1c8a5aa 100644
--- a/library/ui/src/main/res/values-en-rGB/strings.xml
+++ b/library/ui/src/main/res/values-en-rGB/strings.xml
@@ -46,7 +46,15 @@
Disable subtitles
Enable subtitles
Speed
- Normal
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Normal
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Text
diff --git a/library/ui/src/main/res/values-en-rIN/strings.xml b/library/ui/src/main/res/values-en-rIN/strings.xml
index 4a33eb5ba7..c3a1c8a5aa 100644
--- a/library/ui/src/main/res/values-en-rIN/strings.xml
+++ b/library/ui/src/main/res/values-en-rIN/strings.xml
@@ -46,7 +46,15 @@
Disable subtitles
Enable subtitles
Speed
- Normal
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Normal
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Text
diff --git a/library/ui/src/main/res/values-es-rUS/strings.xml b/library/ui/src/main/res/values-es-rUS/strings.xml
index b4c770bd66..faaf430448 100644
--- a/library/ui/src/main/res/values-es-rUS/strings.xml
+++ b/library/ui/src/main/res/values-es-rUS/strings.xml
@@ -46,7 +46,15 @@
Inhabilitar subtítulos
Habilitar subtítulos
Velocidad
- Normal
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Normal
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Texto
diff --git a/library/ui/src/main/res/values-es/strings.xml b/library/ui/src/main/res/values-es/strings.xml
index e50a26c941..f333c1d068 100644
--- a/library/ui/src/main/res/values-es/strings.xml
+++ b/library/ui/src/main/res/values-es/strings.xml
@@ -46,7 +46,15 @@
Inhabilitar subtítulos
Habilitar subtítulos
Velocidad
- Normal
+
+ - ×0,25
+ - ×0,5
+ - ×0,75
+ - Normal
+ - ×1,25
+ - ×1,5
+ - ×2
+
Vídeo
Audio
Texto
diff --git a/library/ui/src/main/res/values-et/strings.xml b/library/ui/src/main/res/values-et/strings.xml
index e4e627b9d8..1f15da226d 100644
--- a/library/ui/src/main/res/values-et/strings.xml
+++ b/library/ui/src/main/res/values-et/strings.xml
@@ -46,7 +46,15 @@
Keela subtiitrid
Luba subtiitrid
Kiirus
- Tavaline
+
+ - 0,25-kordne
+ - 0,5-kordne
+ - 0,75-kordne
+ - Tavaline
+ - 1,25-kordne
+ - 1,5-kordne
+ - 2-kordne
+
Video
Heli
Tekst
diff --git a/library/ui/src/main/res/values-eu/strings.xml b/library/ui/src/main/res/values-eu/strings.xml
index d79641124c..9fb7fa9ce0 100644
--- a/library/ui/src/main/res/values-eu/strings.xml
+++ b/library/ui/src/main/res/values-eu/strings.xml
@@ -46,7 +46,15 @@
Desgaitu azpitituluak
Gaitu azpitituluak
Abiadura
- Normala
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normala
+ - 1,25x
+ - 1,5x
+ - 2x
+
Bideoa
Audioa
Testua
diff --git a/library/ui/src/main/res/values-fa/strings.xml b/library/ui/src/main/res/values-fa/strings.xml
index a1d0a26901..5fd0d954ca 100644
--- a/library/ui/src/main/res/values-fa/strings.xml
+++ b/library/ui/src/main/res/values-fa/strings.xml
@@ -46,7 +46,15 @@
غیرفعال کردن زیرنویس
فعال کردن زیرنویس
سرعت
- عادی
+
+ - ۰٫۲۵ برابر
+ - ۰٫۵ برابر
+ - ۰٫۷۵ برابر
+ - عادی
+ - ۱٫۲۵ برابر
+ - ۱٫۵ برابر
+ - ۲ برابر
+
ویدیو
صوتی
نوشتار
diff --git a/library/ui/src/main/res/values-fi/strings.xml b/library/ui/src/main/res/values-fi/strings.xml
index 4970206f6d..cc8acd5635 100644
--- a/library/ui/src/main/res/values-fi/strings.xml
+++ b/library/ui/src/main/res/values-fi/strings.xml
@@ -46,7 +46,15 @@
Poista tekstitykset käytöstä
Ota tekstitykset käyttöön
Nopeus
- Normaali
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normaali
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Ääni
Teksti
diff --git a/library/ui/src/main/res/values-fr-rCA/strings.xml b/library/ui/src/main/res/values-fr-rCA/strings.xml
index d73fc24685..f30d732a13 100644
--- a/library/ui/src/main/res/values-fr-rCA/strings.xml
+++ b/library/ui/src/main/res/values-fr-rCA/strings.xml
@@ -46,7 +46,15 @@
Désactiver les sous-titres
Activer les sous-titres
Vitesse
- Normale
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Vidéo
Audio
Texte
diff --git a/library/ui/src/main/res/values-fr/strings.xml b/library/ui/src/main/res/values-fr/strings.xml
index e279a2099d..6aaf078c29 100644
--- a/library/ui/src/main/res/values-fr/strings.xml
+++ b/library/ui/src/main/res/values-fr/strings.xml
@@ -46,7 +46,15 @@
Désactiver les sous-titres
Activer les sous-titres
Vitesse
- Normale
+
+ - x 0,25
+ - x 0,5
+ - x 0,75
+ - Normal
+ - x 1,25
+ - x 1,5
+ - x 2
+
Vidéo
Audio
Texte
diff --git a/library/ui/src/main/res/values-gl/strings.xml b/library/ui/src/main/res/values-gl/strings.xml
index 58ce87afff..fa815e60b1 100644
--- a/library/ui/src/main/res/values-gl/strings.xml
+++ b/library/ui/src/main/res/values-gl/strings.xml
@@ -46,7 +46,15 @@
Desactiva os subtítulos
Activa os subtítulos
Velocidade
- Normal
+
+ - x 0,25
+ - x 0,5
+ - x 0,75
+ - Normal
+ - x 1,25
+ - x 1,5
+ - x 2
+
Vídeo
Audio
Texto
diff --git a/library/ui/src/main/res/values-gu/strings.xml b/library/ui/src/main/res/values-gu/strings.xml
index 14c3efa66e..b870f1400a 100644
--- a/library/ui/src/main/res/values-gu/strings.xml
+++ b/library/ui/src/main/res/values-gu/strings.xml
@@ -46,7 +46,15 @@
સબટાઇટલ બંધ કરો
સબટાઇટલ ચાલુ કરો
ઝડપ
- સામાન્ય
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - સામાન્ય
+ - 1.25x
+ - 1.5x
+ - 2x
+
વીડિયો
ઑડિયો
ટેક્સ્ટ
diff --git a/library/ui/src/main/res/values-hi/strings.xml b/library/ui/src/main/res/values-hi/strings.xml
index fa68022b2b..c45305429f 100644
--- a/library/ui/src/main/res/values-hi/strings.xml
+++ b/library/ui/src/main/res/values-hi/strings.xml
@@ -46,7 +46,15 @@
सबटाइटल बंद करें
सबटाइटल चालू करें
रफ़्तार
- सामान्य
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - सामान्य
+ - 1.25x
+ - 1.5x
+ - 2x
+
वीडियो
ऑडियो
लेख
diff --git a/library/ui/src/main/res/values-hr/strings.xml b/library/ui/src/main/res/values-hr/strings.xml
index f608b300d7..38f630ac58 100644
--- a/library/ui/src/main/res/values-hr/strings.xml
+++ b/library/ui/src/main/res/values-hr/strings.xml
@@ -48,7 +48,15 @@
Onemogući titlove
Omogući titlove
Brzina
- Obično
+
+ - 0,25 x
+ - 0,5 x
+ - 0,75 x
+ - Uobičajeno
+ - 1,25 x
+ - 1,5 x
+ - 2 x
+
Videozapis
Audiozapis
Tekst
diff --git a/library/ui/src/main/res/values-hu/strings.xml b/library/ui/src/main/res/values-hu/strings.xml
index d34010dea4..c987398225 100644
--- a/library/ui/src/main/res/values-hu/strings.xml
+++ b/library/ui/src/main/res/values-hu/strings.xml
@@ -46,7 +46,15 @@
Feliratok kikapcsolása
Feliratok bekapcsolása
Sebesség
- Normál
+
+ - 0,25×
+ - 0,5×
+ - 0,75×
+ - Normál
+ - 1,25×
+ - 1,5×
+ - 2×
+
Videó
Hang
Szöveg
diff --git a/library/ui/src/main/res/values-hy/strings.xml b/library/ui/src/main/res/values-hy/strings.xml
index 8c96cfdb9f..2b8c7a7612 100644
--- a/library/ui/src/main/res/values-hy/strings.xml
+++ b/library/ui/src/main/res/values-hy/strings.xml
@@ -46,7 +46,15 @@
Անջատել ենթագրերը
Միացնել ենթագրերը
Արագություն
- Սովորական
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Սովորական
+ - 1,25x
+ - 1,5x
+ - 2x
+
Տեսանյութ
Աուդիո
Տեքստ
diff --git a/library/ui/src/main/res/values-in/strings.xml b/library/ui/src/main/res/values-in/strings.xml
index 5a1dd6674e..dd5571b4d5 100644
--- a/library/ui/src/main/res/values-in/strings.xml
+++ b/library/ui/src/main/res/values-in/strings.xml
@@ -46,7 +46,15 @@
Nonaktifkan subtitel
Aktifkan subtitel
Kecepatan
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Teks
diff --git a/library/ui/src/main/res/values-is/strings.xml b/library/ui/src/main/res/values-is/strings.xml
index f4e09eab56..01f3bcb362 100644
--- a/library/ui/src/main/res/values-is/strings.xml
+++ b/library/ui/src/main/res/values-is/strings.xml
@@ -46,7 +46,15 @@
Slökkva á skjátexta
Kveikja á skjátexta
Hraði
- Venjulegur
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Venjulegt
+ - 1,25x
+ - 1,5x
+ - 2x
+
Myndskeið
Hljóð
Texti
diff --git a/library/ui/src/main/res/values-it/strings.xml b/library/ui/src/main/res/values-it/strings.xml
index e863214012..8b50689367 100644
--- a/library/ui/src/main/res/values-it/strings.xml
+++ b/library/ui/src/main/res/values-it/strings.xml
@@ -29,12 +29,12 @@
Interrompi
Riavvolgi
- - Indietro di %d secondo
+ - Indietro di %d secondi
- Indietro di %d secondi
Avanti veloce
- - Avanti di %d secondo
+ - Avanti di %d secondi
- Avanti di %d secondi
Non ripetere nulla
@@ -46,7 +46,15 @@
Disattiva i sottotitoli
Attiva i sottotitoli
Velocità
- Normale
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normale
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Testo
diff --git a/library/ui/src/main/res/values-iw/strings.xml b/library/ui/src/main/res/values-iw/strings.xml
index 19fd41813b..adbe03100b 100644
--- a/library/ui/src/main/res/values-iw/strings.xml
+++ b/library/ui/src/main/res/values-iw/strings.xml
@@ -50,7 +50,15 @@
השבתת כתוביות
הפעלת כתוביות
מהירות
- רגילה
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - רגילה
+ - 1.25x
+ - 1.5x
+ - 2x
+
סרטון
אודיו
טקסט
diff --git a/library/ui/src/main/res/values-ja/strings.xml b/library/ui/src/main/res/values-ja/strings.xml
index c17ecf89a0..7333b977d4 100644
--- a/library/ui/src/main/res/values-ja/strings.xml
+++ b/library/ui/src/main/res/values-ja/strings.xml
@@ -46,7 +46,15 @@
字幕の無効化
字幕の有効化
速度
- 標準
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - 標準
+ - 1.25x
+ - 1.5x
+ - 2x
+
動画
音声
文字
diff --git a/library/ui/src/main/res/values-ka/strings.xml b/library/ui/src/main/res/values-ka/strings.xml
index 5f808f33a5..a18089e129 100644
--- a/library/ui/src/main/res/values-ka/strings.xml
+++ b/library/ui/src/main/res/values-ka/strings.xml
@@ -46,7 +46,15 @@
სუბტიტრების გათიშვა
სუბტიტრების ჩართვა
სიჩქარე
- ჩვეულებრივი
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - ჩვეულებრივი
+ - 1,25x
+ - 1,5x
+ - 2x
+
ვიდეო
აუდიო
ტექსტი
diff --git a/library/ui/src/main/res/values-kk/strings.xml b/library/ui/src/main/res/values-kk/strings.xml
index 7c5ac35e35..be14948ef1 100644
--- a/library/ui/src/main/res/values-kk/strings.xml
+++ b/library/ui/src/main/res/values-kk/strings.xml
@@ -46,7 +46,15 @@
Субтитрді өшіру
Субтитрді қосу
Жылдамдық
- Қалыпты
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Қалыпты
+ - 1,25x
+ - 1,5x
+ - 2x
+
Бейне
Aудиомазмұн
Мәтін
diff --git a/library/ui/src/main/res/values-km/strings.xml b/library/ui/src/main/res/values-km/strings.xml
index e7e2531638..4e1f62bd90 100644
--- a/library/ui/src/main/res/values-km/strings.xml
+++ b/library/ui/src/main/res/values-km/strings.xml
@@ -46,7 +46,15 @@
បិទអក្សររត់
បើកអក្សររត់
ល្បឿន
- ធម្មតា
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - ធម្មតា
+ - 1.25x
+ - 1.5x
+ - 2x
+
វីដេអូ
សំឡេង
អក្សរ
diff --git a/library/ui/src/main/res/values-kn/strings.xml b/library/ui/src/main/res/values-kn/strings.xml
index efb2632dae..28c9496216 100644
--- a/library/ui/src/main/res/values-kn/strings.xml
+++ b/library/ui/src/main/res/values-kn/strings.xml
@@ -46,7 +46,15 @@
ಸಬ್ಟೈಟಲ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ
ಸಬ್ಟೈಟಲ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ
ವೇಗ
- ಸಾಮಾನ್ಯ
+
+ - 0.25 ಪಟ್ಟು
+ - 0.5 ಪಟ್ಟು
+ - 0.75 ಪಟ್ಟು
+ - ಸಾಮಾನ್ಯ
+ - 1.25 ಪಟ್ಟು
+ - 1.5 ಪಟ್ಟು
+ - 2 ಪಟ್ಟು
+
ವೀಡಿಯೊ
ಆಡಿಯೊ
ಪಠ್ಯ
diff --git a/library/ui/src/main/res/values-ko/strings.xml b/library/ui/src/main/res/values-ko/strings.xml
index 10919b8ee5..0c06366b57 100644
--- a/library/ui/src/main/res/values-ko/strings.xml
+++ b/library/ui/src/main/res/values-ko/strings.xml
@@ -46,7 +46,15 @@
자막 사용 중지
자막 사용 설정
속도
- 일반
+
+ - 0.25배속
+ - 0.5배속
+ - 0.75배속
+ - 보통
+ - 1.25배속
+ - 1.5배속
+ - 2배속
+
동영상
오디오
텍스트
diff --git a/library/ui/src/main/res/values-ky/strings.xml b/library/ui/src/main/res/values-ky/strings.xml
index e61beffe15..4cb3932247 100644
--- a/library/ui/src/main/res/values-ky/strings.xml
+++ b/library/ui/src/main/res/values-ky/strings.xml
@@ -46,7 +46,15 @@
Коштомо жазууларды өчүрүү
Коштомо жазууларды иштетүү
Ылдамдык
- Орточо
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Орточо
+ - 1,25x
+ - 1,5x
+ - 2x
+
Видео
Аудио
Текст
diff --git a/library/ui/src/main/res/values-lo/strings.xml b/library/ui/src/main/res/values-lo/strings.xml
index 23e17a9458..8581b0bbc0 100644
--- a/library/ui/src/main/res/values-lo/strings.xml
+++ b/library/ui/src/main/res/values-lo/strings.xml
@@ -46,7 +46,15 @@
ປິດການນຳໃຊ້ຄຳແປ
ເປີດການນຳໃຊ້ຄຳແປ
ຄວາມໄວ
- ທົ່ວໄປ
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - ປົກກະຕິ
+ - 1.25x
+ - 1.5x
+ - 2x
+
ວິດີໂອ
ສຽງ
ຂໍ້ຄວາມ
diff --git a/library/ui/src/main/res/values-lt/strings.xml b/library/ui/src/main/res/values-lt/strings.xml
index 29d2921932..b8233d76a9 100644
--- a/library/ui/src/main/res/values-lt/strings.xml
+++ b/library/ui/src/main/res/values-lt/strings.xml
@@ -50,7 +50,15 @@
Išjungti subtitrus
Įgalinti subtitrus
Sparta
- Įprasta
+
+ - 0,25 k.
+ - 0,5 k.
+ - 0,75 k.
+ - Įprasta
+ - 1,25 k.
+ - 1,5 k.
+ - 2 k.
+
Vaizdo įrašas
Garso įrašas
Tekstas
diff --git a/library/ui/src/main/res/values-lv/strings.xml b/library/ui/src/main/res/values-lv/strings.xml
index c6311de85c..61f1c8f4dd 100644
--- a/library/ui/src/main/res/values-lv/strings.xml
+++ b/library/ui/src/main/res/values-lv/strings.xml
@@ -48,7 +48,15 @@
Atspējot subtitrus
Iespējot subtitrus
Ātrums
- Parasts
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normāls
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Teksts
diff --git a/library/ui/src/main/res/values-mk/strings.xml b/library/ui/src/main/res/values-mk/strings.xml
index 1668e27db5..8a4ff03039 100644
--- a/library/ui/src/main/res/values-mk/strings.xml
+++ b/library/ui/src/main/res/values-mk/strings.xml
@@ -46,7 +46,15 @@
Оневозможете ги титловите
Овозможете ги титловите
Брзина
- Нормална
+
+ - 0,25 пати
+ - 0,5 пати
+ - 0,75 пати
+ - Нормално
+ - 1,25 пати
+ - 1,5 пати
+ - 2 пати
+
Видео
Аудио
Текст
diff --git a/library/ui/src/main/res/values-ml/strings.xml b/library/ui/src/main/res/values-ml/strings.xml
index 3485bd97e1..12de370917 100644
--- a/library/ui/src/main/res/values-ml/strings.xml
+++ b/library/ui/src/main/res/values-ml/strings.xml
@@ -46,7 +46,15 @@
സബ്ടൈറ്റിലുകൾ പ്രവർത്തനരഹിതമാക്കുക
സബ്ടൈറ്റിലുകൾ പ്രവർത്തനക്ഷമമാക്കുക
വേഗത
- സാധാരണം
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - സാധാരണ വേഗത്തിൽ
+ - 1.25x
+ - 1.5x
+ - 2x
+
വീഡിയോ
ഓഡിയോ
ടെക്സ്റ്റ്
diff --git a/library/ui/src/main/res/values-mn/strings.xml b/library/ui/src/main/res/values-mn/strings.xml
index 69c34c991b..e9fbf7fe53 100644
--- a/library/ui/src/main/res/values-mn/strings.xml
+++ b/library/ui/src/main/res/values-mn/strings.xml
@@ -46,7 +46,15 @@
Хадмалыг идэвхгүй болгох
Хадмалыг идэвхжүүлэх
Хурд
- Хэвийн
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Энгийн
+ - 1.25x
+ - 1.5x
+ - 2x
+
Видео
Дуу
Текст
diff --git a/library/ui/src/main/res/values-mr/strings.xml b/library/ui/src/main/res/values-mr/strings.xml
index d2823a3d0d..5641af2a47 100644
--- a/library/ui/src/main/res/values-mr/strings.xml
+++ b/library/ui/src/main/res/values-mr/strings.xml
@@ -46,7 +46,15 @@
सबटायटल बंद करा
सबटायटल सुरू करा
वेग
- सामान्य
+
+ - ०.२५x
+ - ०.५x
+ - ०.७५x
+ - सामान्य
+ - १.२५x
+ - १.५x
+ - २x
+
व्हिडिओ
ऑडिओ
मजकूर
diff --git a/library/ui/src/main/res/values-ms/strings.xml b/library/ui/src/main/res/values-ms/strings.xml
index d90400b2cc..60cce968c2 100644
--- a/library/ui/src/main/res/values-ms/strings.xml
+++ b/library/ui/src/main/res/values-ms/strings.xml
@@ -46,7 +46,15 @@
Lumpuhkan sari kata
Dayakan sari kata
Kelajuan
- Biasa
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Biasa
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Teks
diff --git a/library/ui/src/main/res/values-my/strings.xml b/library/ui/src/main/res/values-my/strings.xml
index 9c46d2d4f2..07f0ad05ff 100644
--- a/library/ui/src/main/res/values-my/strings.xml
+++ b/library/ui/src/main/res/values-my/strings.xml
@@ -46,7 +46,15 @@
စာတန်းထိုး ပိတ်ပါ
စာတန်းထိုး ဖွင့်ပါ
မြန်နှုန်း
- ပုံမှန်
+
+ - ၀.၂၅ ဆ
+ - ၀.၅ ဆ
+ - ၀.၇၅ ဆ
+ - ပုံမှန်
+ - ၁.၂၅ ဆ
+ - ၁.၅ ဆ
+ - ၂ ဆ
+
ဗီဒီယို
အသံ
စာသား
diff --git a/library/ui/src/main/res/values-nb/strings.xml b/library/ui/src/main/res/values-nb/strings.xml
index ebb10985c4..03a2216962 100644
--- a/library/ui/src/main/res/values-nb/strings.xml
+++ b/library/ui/src/main/res/values-nb/strings.xml
@@ -46,7 +46,15 @@
Slå av undertekstene
Slå på undertekstene
Hastighet
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Lyd
Tekst
diff --git a/library/ui/src/main/res/values-ne/strings.xml b/library/ui/src/main/res/values-ne/strings.xml
index 8e8364c4cb..2806463f0b 100644
--- a/library/ui/src/main/res/values-ne/strings.xml
+++ b/library/ui/src/main/res/values-ne/strings.xml
@@ -46,7 +46,15 @@
सबटाइटलहरू असक्षम पार्नुहोस्
सबटाइटलहरू सक्षम पार्नुहोस्
गति
- सामान्य
+
+ - ०.२५ गुणा
+ - ०.५ गुणा
+ - ०.७५ गुणा
+ - सामान्य
+ - १.२५ गुणा
+ - १.५ गुणा
+ - २ गुणा
+
भिडियो
अडियो
पाठ
diff --git a/library/ui/src/main/res/values-nl/strings.xml b/library/ui/src/main/res/values-nl/strings.xml
index 005cf3cdfc..0b7c590443 100644
--- a/library/ui/src/main/res/values-nl/strings.xml
+++ b/library/ui/src/main/res/values-nl/strings.xml
@@ -46,7 +46,15 @@
Ondertiteling uitzetten
Ondertiteling aanzetten
Snelheid
- Normaal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normaal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Tekst
diff --git a/library/ui/src/main/res/values-pa/strings.xml b/library/ui/src/main/res/values-pa/strings.xml
index 2c7a531caa..efe5b908ab 100644
--- a/library/ui/src/main/res/values-pa/strings.xml
+++ b/library/ui/src/main/res/values-pa/strings.xml
@@ -46,7 +46,15 @@
ਉਪਸਿਰਲੇਖਾਂ ਨੂੰ ਬੰਦ ਕਰੋ
ਉਪਸਿਰਲੇਖਾਂ ਨੂੰ ਚਾਲੂ ਕਰੋ
ਗਤੀ
- ਸਧਾਰਨ
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - ਸਧਾਰਨ
+ - 1.25x
+ - 1.5x
+ - 2x
+
ਵੀਡੀਓ
ਆਡੀਓ
ਲਿਖਤ
diff --git a/library/ui/src/main/res/values-pl/strings.xml b/library/ui/src/main/res/values-pl/strings.xml
index ef355f178e..f12915791b 100644
--- a/library/ui/src/main/res/values-pl/strings.xml
+++ b/library/ui/src/main/res/values-pl/strings.xml
@@ -50,7 +50,15 @@
Wyłącz napisy
Włącz napisy
Szybkość
- Normalna
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normalna
+ - 1,25x
+ - 1,5x
+ - 2x
+
Film
Dźwięk
Tekst
diff --git a/library/ui/src/main/res/values-pt-rPT/strings.xml b/library/ui/src/main/res/values-pt-rPT/strings.xml
index 51cfe3e902..f791718436 100644
--- a/library/ui/src/main/res/values-pt-rPT/strings.xml
+++ b/library/ui/src/main/res/values-pt-rPT/strings.xml
@@ -29,12 +29,12 @@
Parar
Recuar
- - Retroceder %d segundo
+ - Retroceder %d segundo(s)
- Retroceder %d segundos
Avançar
- - Avançar %d segundo
+ - Avançar %d segundo(s)
- Avançar %d segundos
Não repetir nenhum
@@ -46,7 +46,15 @@
Desativar legendas
Ativar legendas
Velocidade
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Vídeo
Áudio
Texto
diff --git a/library/ui/src/main/res/values-pt/strings.xml b/library/ui/src/main/res/values-pt/strings.xml
index 25711d0ed9..af04650a35 100644
--- a/library/ui/src/main/res/values-pt/strings.xml
+++ b/library/ui/src/main/res/values-pt/strings.xml
@@ -46,7 +46,15 @@
Desativar legendas
Ativar legendas
Velocidade
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Vídeo
Áudio
Texto
diff --git a/library/ui/src/main/res/values-ro/strings.xml b/library/ui/src/main/res/values-ro/strings.xml
index ddcd79f943..db77aa55d1 100644
--- a/library/ui/src/main/res/values-ro/strings.xml
+++ b/library/ui/src/main/res/values-ro/strings.xml
@@ -48,7 +48,15 @@
Dezactivați subtitrările
Activați subtitrările
Viteză
- Normală
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normală
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Text
diff --git a/library/ui/src/main/res/values-ru/strings.xml b/library/ui/src/main/res/values-ru/strings.xml
index a515c13ba4..542517da8b 100644
--- a/library/ui/src/main/res/values-ru/strings.xml
+++ b/library/ui/src/main/res/values-ru/strings.xml
@@ -50,7 +50,15 @@
Выключить субтитры
Включить субтитры
Скорость
- Стандартная
+
+ - 0,25
+ - 0,5
+ - 0,75
+ - Обычная
+ - 1,25
+ - 1,5
+ - 2
+
Видео
Аудио
Текст
diff --git a/library/ui/src/main/res/values-si/strings.xml b/library/ui/src/main/res/values-si/strings.xml
index e0bbc6e0de..2f56ca1699 100644
--- a/library/ui/src/main/res/values-si/strings.xml
+++ b/library/ui/src/main/res/values-si/strings.xml
@@ -46,7 +46,15 @@
උපසිරැසි අබල කරන්න
උපසිරැසි සබල කරන්න
වේගය
- සාමාන්ය
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - සාමාන්ය
+ - 1.25x
+ - 1.5x
+ - 2x
+
වීඩියෝ
ශ්රව්ය
පෙළ
diff --git a/library/ui/src/main/res/values-sk/strings.xml b/library/ui/src/main/res/values-sk/strings.xml
index 9f57220b95..4f365fb034 100644
--- a/library/ui/src/main/res/values-sk/strings.xml
+++ b/library/ui/src/main/res/values-sk/strings.xml
@@ -50,7 +50,15 @@
Zakázať titulky
Povoliť titulky
Rýchlosť
- Normálna
+
+ - 0,25 ×
+ - 0,5 ×
+ - 0,75 ×
+ - Normálne
+ - 1,25 ×
+ - 1,5 ×
+ - 2 ×
+
Video
Zvuk
Text
diff --git a/library/ui/src/main/res/values-sl/strings.xml b/library/ui/src/main/res/values-sl/strings.xml
index 74c2197a7c..1ddc0ba757 100644
--- a/library/ui/src/main/res/values-sl/strings.xml
+++ b/library/ui/src/main/res/values-sl/strings.xml
@@ -50,7 +50,15 @@
Onemogočanje podnapisov
Omogočanje podnapisov
Hitrost
- Običajna
+
+ - 0,25-kratna
+ - 0,5-kratna
+ - 0,75-kratna
+ - Običajna
+ - 1,25-kratna
+ - 1,5-kratna
+ - 2-kratna
+
Videoposnetki
Zvočni posnetki
Podnapisi
diff --git a/library/ui/src/main/res/values-sq/strings.xml b/library/ui/src/main/res/values-sq/strings.xml
index 0321c6e6f1..59941e5e8e 100644
--- a/library/ui/src/main/res/values-sq/strings.xml
+++ b/library/ui/src/main/res/values-sq/strings.xml
@@ -46,7 +46,15 @@
Çaktivizo titrat
Aktivizo titrat
Shpejtësia
- Normale
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normale
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Tekst
diff --git a/library/ui/src/main/res/values-sr/strings.xml b/library/ui/src/main/res/values-sr/strings.xml
index 8a06044431..c748764e9b 100644
--- a/library/ui/src/main/res/values-sr/strings.xml
+++ b/library/ui/src/main/res/values-sr/strings.xml
@@ -48,7 +48,15 @@
Онемогући титлове
Омогући титлове
Брзина
- Уобичајена
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Нормално
+ - 1,25x
+ - 1,5x
+ - 2x
+
Видео
Аудио
Текст
diff --git a/library/ui/src/main/res/values-sv/strings.xml b/library/ui/src/main/res/values-sv/strings.xml
index b45a7edfe7..bb23c56b56 100644
--- a/library/ui/src/main/res/values-sv/strings.xml
+++ b/library/ui/src/main/res/values-sv/strings.xml
@@ -46,7 +46,15 @@
Inaktivera undertexter
Aktivera undertexter
Hastighet
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Ljud
Text
diff --git a/library/ui/src/main/res/values-sw/strings.xml b/library/ui/src/main/res/values-sw/strings.xml
index 02a6174ea9..c594838faf 100644
--- a/library/ui/src/main/res/values-sw/strings.xml
+++ b/library/ui/src/main/res/values-sw/strings.xml
@@ -46,7 +46,15 @@
Zima manukuu
Washa manukuu
Kasi
- Kawaida
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Ya kawaida
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Sauti
Maandishi
diff --git a/library/ui/src/main/res/values-ta/strings.xml b/library/ui/src/main/res/values-ta/strings.xml
index c5053480c4..d107f42a10 100644
--- a/library/ui/src/main/res/values-ta/strings.xml
+++ b/library/ui/src/main/res/values-ta/strings.xml
@@ -46,7 +46,15 @@
வசனங்களை முடக்கும்
வசனங்களை இயக்கும்
வேகம்
- இயல்பு
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - இயல்பு
+ - 1.25x
+ - 1.5x
+ - 2x
+
வீடியோ
ஆடியோ
உரை
diff --git a/library/ui/src/main/res/values-te/strings.xml b/library/ui/src/main/res/values-te/strings.xml
index 90208f6e3a..435128311e 100644
--- a/library/ui/src/main/res/values-te/strings.xml
+++ b/library/ui/src/main/res/values-te/strings.xml
@@ -46,7 +46,15 @@
ఉప శీర్షికలను డిజేబుల్ చేయి
ఉప శీర్షికలను ఎనేబుల్ చేయి
వేగం
- సాధారణం
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - సాధారణం
+ - 1.25x
+ - 1.5x
+ - 2x
+
వీడియో
ఆడియో
వచనం
diff --git a/library/ui/src/main/res/values-th/strings.xml b/library/ui/src/main/res/values-th/strings.xml
index 6aecddefdb..387e9fffe3 100644
--- a/library/ui/src/main/res/values-th/strings.xml
+++ b/library/ui/src/main/res/values-th/strings.xml
@@ -46,7 +46,15 @@
ปิดใช้คำบรรยาย
เปิดใช้คำบรรยาย
ความเร็ว
- ปกติ
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - ปกติ
+ - 1.25x
+ - 1.5x
+ - 2x
+
วิดีโอ
เสียง
ข้อความ
diff --git a/library/ui/src/main/res/values-tl/strings.xml b/library/ui/src/main/res/values-tl/strings.xml
index 7931b0ca5a..5715b393ac 100644
--- a/library/ui/src/main/res/values-tl/strings.xml
+++ b/library/ui/src/main/res/values-tl/strings.xml
@@ -46,7 +46,15 @@
I-disable ang mga subtitle
I-enable ang mga subtitle
Bilis
- Normal
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Normal
+ - 1.25x
+ - 1.5x
+ - 2x
+
Video
Audio
Text
diff --git a/library/ui/src/main/res/values-tr/strings.xml b/library/ui/src/main/res/values-tr/strings.xml
index 8b55689e74..f367f44bb2 100644
--- a/library/ui/src/main/res/values-tr/strings.xml
+++ b/library/ui/src/main/res/values-tr/strings.xml
@@ -46,7 +46,15 @@
Altyazıları devre dışı bırak
Altyazıları etkinleştir
Hız
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Ses
Metin
diff --git a/library/ui/src/main/res/values-uk/strings.xml b/library/ui/src/main/res/values-uk/strings.xml
index da8a7b6caa..f8f2c47064 100644
--- a/library/ui/src/main/res/values-uk/strings.xml
+++ b/library/ui/src/main/res/values-uk/strings.xml
@@ -50,7 +50,15 @@
Вимкнути субтитри
Увімкнути субтитри
Швидкість
- Звичайна
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Звичайна
+ - 1,25x
+ - 1,5x
+ - 2x
+
Відео
Аудіо
Текст
diff --git a/library/ui/src/main/res/values-ur/strings.xml b/library/ui/src/main/res/values-ur/strings.xml
index d7f60590bb..f7b46d01f4 100644
--- a/library/ui/src/main/res/values-ur/strings.xml
+++ b/library/ui/src/main/res/values-ur/strings.xml
@@ -46,7 +46,15 @@
سب ٹائٹلز کو غیر فعال کریں
سب ٹائٹلز کو فعال کریں
رفتار
- عام
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - عام
+ - 1.25x
+ - 1.5x
+ - 2X
+
ویڈیو
آڈیو
متن
diff --git a/library/ui/src/main/res/values-uz/strings.xml b/library/ui/src/main/res/values-uz/strings.xml
index 3a15f1ad01..f0c4677b9c 100644
--- a/library/ui/src/main/res/values-uz/strings.xml
+++ b/library/ui/src/main/res/values-uz/strings.xml
@@ -46,7 +46,15 @@
Taglavhalarni faolsizlantirish
Taglavhalarni yoqish
Tezlik
- Normal
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Normal
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Audio
Matn
diff --git a/library/ui/src/main/res/values-vi/strings.xml b/library/ui/src/main/res/values-vi/strings.xml
index 4459fc7e21..290d96f167 100644
--- a/library/ui/src/main/res/values-vi/strings.xml
+++ b/library/ui/src/main/res/values-vi/strings.xml
@@ -46,7 +46,15 @@
Tắt phụ đề
Bật phụ đề
Tốc độ
- Bình thường
+
+ - 0,25x
+ - 0,5x
+ - 0,75x
+ - Bình thường
+ - 1,25x
+ - 1,5x
+ - 2x
+
Video
Âm thanh
Văn bản
diff --git a/library/ui/src/main/res/values-zh-rCN/strings.xml b/library/ui/src/main/res/values-zh-rCN/strings.xml
index 896d390e6a..436449df6d 100644
--- a/library/ui/src/main/res/values-zh-rCN/strings.xml
+++ b/library/ui/src/main/res/values-zh-rCN/strings.xml
@@ -46,7 +46,15 @@
停用字幕
启用字幕
速度
- 正常
+
+ - 0.25 倍
+ - 0.5 倍
+ - 0.75 倍
+ - 正常
+ - 1.25 倍
+ - 1.5 倍
+ - 2 倍
+
视频
音频
文字
diff --git a/library/ui/src/main/res/values-zh-rHK/strings.xml b/library/ui/src/main/res/values-zh-rHK/strings.xml
index b145cbaac1..4fe9ee9b41 100644
--- a/library/ui/src/main/res/values-zh-rHK/strings.xml
+++ b/library/ui/src/main/res/values-zh-rHK/strings.xml
@@ -46,7 +46,15 @@
停用字幕
啟用字幕
速度
- 正常
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - 正常
+ - 1.25x
+ - 1.5x
+ - 2x
+
影片
音訊
文字
diff --git a/library/ui/src/main/res/values-zh-rTW/strings.xml b/library/ui/src/main/res/values-zh-rTW/strings.xml
index 538a45f028..591afff6b5 100644
--- a/library/ui/src/main/res/values-zh-rTW/strings.xml
+++ b/library/ui/src/main/res/values-zh-rTW/strings.xml
@@ -46,7 +46,15 @@
停用字幕 (Subtitle)
啟用字幕 (Subtitle)
速度
- 正常
+
+ - 0.25 倍
+ - 0.5 倍
+ - 0.75 倍
+ - 正常
+ - 1.25 倍
+ - 1.5 倍
+ - 2 倍
+
影片
音訊
文字
diff --git a/library/ui/src/main/res/values-zu/strings.xml b/library/ui/src/main/res/values-zu/strings.xml
index 2da4f09884..409adc0e70 100644
--- a/library/ui/src/main/res/values-zu/strings.xml
+++ b/library/ui/src/main/res/values-zu/strings.xml
@@ -46,7 +46,15 @@
Khubaza imibhalo engezansi
Nika amandla imibhalo engezansi
Isivinini
- Ivamile
+
+ - 0.25x
+ - 0.5x
+ - 0.75x
+ - Okujwayelekile
+ - 1.25x
+ - 1.5x
+ - 2x
+
Ividiyo
Umsindo
Umbhalo
diff --git a/library/ui/src/main/res/values/arrays.xml b/library/ui/src/main/res/values/arrays.xml
deleted file mode 100644
index 8b326c3d4d..0000000000
--- a/library/ui/src/main/res/values/arrays.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
- - 25
- - 50
- - 75
- - 100
- - 125
- - 150
- - 200
-
-
-
- - 0.25x
- - 0.5x
- - 0.75x
- - @string/exo_controls_playback_speed_normal
- - 1.25x
- - 1.5x
- - 2x
-
-
diff --git a/library/ui/src/main/res/values/strings.xml b/library/ui/src/main/res/values/strings.xml
index c04899db4a..c15b966540 100644
--- a/library/ui/src/main/res/values/strings.xml
+++ b/library/ui/src/main/res/values/strings.xml
@@ -72,8 +72,7 @@
Enable subtitles
Speed
-
- Normal
+
- 0.25x
@@ -84,6 +83,7 @@
- 1.5x
- 2x
+
%1$.2f x
diff --git a/missing_aar_type_workaround.gradle b/missing_aar_type_workaround.gradle
index 2bbbd3c2e3..276743ca60 100644
--- a/missing_aar_type_workaround.gradle
+++ b/missing_aar_type_workaround.gradle
@@ -74,8 +74,8 @@ def addMissingAarTypeToXml(xml) {
boolean hasJar =
jar_only_dependencies.contains(dependencyName)
boolean hasAar =
- isProjectLibrary
- || aar_dependencies.contains(dependencyName)
+ (isProjectLibrary
+ || aar_dependencies.contains(dependencyName))
if (!hasJar && !hasAar) {
throw new IllegalStateException(
dependencyName + " is not on the JAR or AAR list in missing_aar_type_workaround.gradle")
diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DebugRenderersFactory.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DebugRenderersFactory.java
index 0d546926db..35939af005 100644
--- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DebugRenderersFactory.java
+++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DebugRenderersFactory.java
@@ -149,14 +149,18 @@ import java.util.ArrayList;
@Override
protected void onCodecInitialized(
- String name, long initializedTimestampMs, long initializationDurationMs) {
+ String name,
+ MediaCodecAdapter.Configuration configuration,
+ long initializedTimestampMs,
+ long initializationDurationMs) {
// If the codec was initialized whilst the renderer is started, default behavior is to
// render the first frame (i.e. the keyframe before the current position), then drop frames up
// to the current playback position. For test runs that place a maximum limit on the number of
// dropped frames allowed, this is not desired behavior. Hence we skip (rather than drop)
// frames up to the current playback position [Internal: b/66494991].
skipToPositionBeforeRenderingFirstFrame = getState() == Renderer.STATE_STARTED;
- super.onCodecInitialized(name, initializedTimestampMs, initializationDurationMs);
+ super.onCodecInitialized(
+ name, configuration, initializedTimestampMs, initializationDurationMs);
}
@Override
diff --git a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/PlaybackOutput.java b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/PlaybackOutput.java
index 000f9e627e..c927077ae5 100644
--- a/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/PlaybackOutput.java
+++ b/robolectricutils/src/main/java/com/google/android/exoplayer2/robolectric/PlaybackOutput.java
@@ -23,7 +23,6 @@ import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.dvbsi.AppInfoTable;
import com.google.android.exoplayer2.metadata.emsg.EventMessage;
import com.google.android.exoplayer2.metadata.flac.PictureFrame;
-import com.google.android.exoplayer2.metadata.flac.VorbisComment;
import com.google.android.exoplayer2.metadata.icy.IcyHeaders;
import com.google.android.exoplayer2.metadata.icy.IcyInfo;
import com.google.android.exoplayer2.metadata.id3.Id3Frame;
@@ -32,6 +31,7 @@ import com.google.android.exoplayer2.metadata.mp4.MotionPhotoMetadata;
import com.google.android.exoplayer2.metadata.mp4.SlowMotionData;
import com.google.android.exoplayer2.metadata.mp4.SmtaMetadataEntry;
import com.google.android.exoplayer2.metadata.scte35.SpliceCommand;
+import com.google.android.exoplayer2.metadata.vorbis.VorbisComment;
import com.google.android.exoplayer2.testutil.CapturingRenderersFactory;
import com.google.android.exoplayer2.testutil.Dumper;
import com.google.android.exoplayer2.text.Cue;
diff --git a/settings.gradle b/settings.gradle
index c73ad7a1e0..4d88f52af7 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -26,6 +26,8 @@ include modulePrefix + 'demo-gl'
project(modulePrefix + 'demo-gl').projectDir = new File(rootDir, 'demos/gl')
include modulePrefix + 'demo-surface'
project(modulePrefix + 'demo-surface').projectDir = new File(rootDir, 'demos/surface')
+include modulePrefix + 'demo-transformer'
+project(modulePrefix + 'demo-transformer').projectDir = new File(rootDir, 'demos/transformer')
include modulePrefix + 'playbacktests'
project(modulePrefix + 'playbacktests').projectDir = new File(rootDir, 'playbacktests')
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.0.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.0.dump
new file mode 100644
index 0000000000..68b4fdada9
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.0.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 55
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 55, hash F96B22E6
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.1.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.1.dump
new file mode 100644
index 0000000000..68b4fdada9
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.1.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 55
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 55, hash F96B22E6
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.2.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.2.dump
new file mode 100644
index 0000000000..68b4fdada9
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.2.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 55
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 55, hash F96B22E6
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.3.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.3.dump
new file mode 100644
index 0000000000..68b4fdada9
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.3.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 55
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 55, hash F96B22E6
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.unknown_length.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.unknown_length.dump
new file mode 100644
index 0000000000..68b4fdada9
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.unknown_length.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 55
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 55, hash F96B22E6
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.0.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.0.dump
new file mode 100644
index 0000000000..e79174312b
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.0.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 65
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 65, hash 3EC9965C
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.1.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.1.dump
new file mode 100644
index 0000000000..e79174312b
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.1.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 65
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 65, hash 3EC9965C
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.2.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.2.dump
new file mode 100644
index 0000000000..e79174312b
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.2.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 65
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 65, hash 3EC9965C
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.3.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.3.dump
new file mode 100644
index 0000000000..e79174312b
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.3.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 65
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 65, hash 3EC9965C
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.unknown_length.dump b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.unknown_length.dump
new file mode 100644
index 0000000000..e79174312b
--- /dev/null
+++ b/testdata/src/test/assets/extractordumps/mkv/sample_with_vtt_subtitles.mkv.unknown_length.dump
@@ -0,0 +1,281 @@
+seekMap:
+ isSeekable = true
+ duration = 1234000
+ getPosition(0) = [[timeUs=0, position=5661]]
+ getPosition(1) = [[timeUs=0, position=5661]]
+ getPosition(617000) = [[timeUs=0, position=5661]]
+ getPosition(1234000) = [[timeUs=0, position=5661]]
+numberOfTracks = 3
+track 1:
+ total output bytes = 89502
+ sample count = 30
+ format 0:
+ id = 1
+ sampleMimeType = video/avc
+ codecs = avc1.640034
+ width = 1080
+ height = 720
+ selectionFlags = 1
+ language = und
+ initializationData:
+ data = length 30, hash F6F3D010
+ data = length 10, hash 7A0D0F2B
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 36477, hash F0F36CFE
+ sample 1:
+ time = 67000
+ flags = 0
+ data = length 5341, hash 40B85E2
+ sample 2:
+ time = 33000
+ flags = 0
+ data = length 596, hash 357B4D92
+ sample 3:
+ time = 200000
+ flags = 0
+ data = length 7704, hash A39EDA06
+ sample 4:
+ time = 133000
+ flags = 0
+ data = length 989, hash 2813C72D
+ sample 5:
+ time = 100000
+ flags = 0
+ data = length 721, hash C50D1C73
+ sample 6:
+ time = 167000
+ flags = 0
+ data = length 519, hash 65FE1911
+ sample 7:
+ time = 333000
+ flags = 0
+ data = length 6160, hash E1CAC0EC
+ sample 8:
+ time = 267000
+ flags = 0
+ data = length 953, hash 7160C661
+ sample 9:
+ time = 233000
+ flags = 0
+ data = length 620, hash 7A7AE07C
+ sample 10:
+ time = 300000
+ flags = 0
+ data = length 405, hash 5CC7F4E7
+ sample 11:
+ time = 433000
+ flags = 0
+ data = length 4852, hash 9DB6979D
+ sample 12:
+ time = 400000
+ flags = 0
+ data = length 547, hash E31A6979
+ sample 13:
+ time = 367000
+ flags = 0
+ data = length 570, hash FEC40D00
+ sample 14:
+ time = 567000
+ flags = 0
+ data = length 5525, hash 7C478F7E
+ sample 15:
+ time = 500000
+ flags = 0
+ data = length 1082, hash DA07059A
+ sample 16:
+ time = 467000
+ flags = 0
+ data = length 807, hash 93478E6B
+ sample 17:
+ time = 533000
+ flags = 0
+ data = length 744, hash 9A8E6026
+ sample 18:
+ time = 700000
+ flags = 0
+ data = length 4732, hash C73B23C0
+ sample 19:
+ time = 633000
+ flags = 0
+ data = length 1004, hash 8A19A228
+ sample 20:
+ time = 600000
+ flags = 0
+ data = length 794, hash 8126022C
+ sample 21:
+ time = 667000
+ flags = 0
+ data = length 645, hash F08300E5
+ sample 22:
+ time = 833000
+ flags = 0
+ data = length 2684, hash 727FE378
+ sample 23:
+ time = 767000
+ flags = 0
+ data = length 787, hash 419A7821
+ sample 24:
+ time = 733000
+ flags = 0
+ data = length 649, hash 5C159346
+ sample 25:
+ time = 800000
+ flags = 0
+ data = length 509, hash F912D655
+ sample 26:
+ time = 967000
+ flags = 0
+ data = length 1226, hash 29815C21
+ sample 27:
+ time = 900000
+ flags = 0
+ data = length 898, hash D997AD0A
+ sample 28:
+ time = 867000
+ flags = 0
+ data = length 476, hash A0423645
+ sample 29:
+ time = 933000
+ flags = 0
+ data = length 486, hash DDF32CBB
+track 2:
+ total output bytes = 12120
+ sample count = 29
+ format 0:
+ id = 2
+ sampleMimeType = audio/ac3
+ channelCount = 1
+ sampleRate = 44100
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 62000
+ flags = 1
+ data = length 416, hash 211F2286
+ sample 1:
+ time = 96829
+ flags = 1
+ data = length 418, hash 77425A86
+ sample 2:
+ time = 131659
+ flags = 1
+ data = length 418, hash A0FE5CA1
+ sample 3:
+ time = 166489
+ flags = 1
+ data = length 418, hash 2309B066
+ sample 4:
+ time = 201319
+ flags = 1
+ data = length 418, hash 928A653B
+ sample 5:
+ time = 236149
+ flags = 1
+ data = length 418, hash 3422F0CB
+ sample 6:
+ time = 270979
+ flags = 1
+ data = length 418, hash EFF43D5B
+ sample 7:
+ time = 305809
+ flags = 1
+ data = length 418, hash FC8093C7
+ sample 8:
+ time = 341000
+ flags = 1
+ data = length 418, hash CCC08A16
+ sample 9:
+ time = 375829
+ flags = 1
+ data = length 418, hash 2A6EE863
+ sample 10:
+ time = 410659
+ flags = 1
+ data = length 418, hash D69A9251
+ sample 11:
+ time = 445489
+ flags = 1
+ data = length 418, hash BCFB758D
+ sample 12:
+ time = 480319
+ flags = 1
+ data = length 418, hash 11B66799
+ sample 13:
+ time = 515149
+ flags = 1
+ data = length 418, hash C824D392
+ sample 14:
+ time = 549979
+ flags = 1
+ data = length 418, hash C167D872
+ sample 15:
+ time = 584809
+ flags = 1
+ data = length 418, hash 4221C855
+ sample 16:
+ time = 620000
+ flags = 1
+ data = length 418, hash 4D4FF934
+ sample 17:
+ time = 654829
+ flags = 1
+ data = length 418, hash 984AA025
+ sample 18:
+ time = 689659
+ flags = 1
+ data = length 418, hash BB788B46
+ sample 19:
+ time = 724489
+ flags = 1
+ data = length 418, hash 9EFBFD97
+ sample 20:
+ time = 759319
+ flags = 1
+ data = length 418, hash DF1A460C
+ sample 21:
+ time = 794149
+ flags = 1
+ data = length 418, hash 2BDB56A
+ sample 22:
+ time = 828979
+ flags = 1
+ data = length 418, hash CA230060
+ sample 23:
+ time = 863809
+ flags = 1
+ data = length 418, hash D2F19F41
+ sample 24:
+ time = 898000
+ flags = 1
+ data = length 418, hash AF392D79
+ sample 25:
+ time = 932829
+ flags = 1
+ data = length 418, hash C5D7F2A3
+ sample 26:
+ time = 967659
+ flags = 1
+ data = length 418, hash 733A35AE
+ sample 27:
+ time = 1002489
+ flags = 1
+ data = length 418, hash DE46E5D3
+ sample 28:
+ time = 1037319
+ flags = 1
+ data = length 418, hash 56AB8D37
+track 3:
+ total output bytes = 65
+ sample count = 1
+ format 0:
+ id = 3
+ sampleMimeType = text/vtt
+ selectionFlags = 1
+ language = und
+ sample 0:
+ time = 0
+ flags = 1
+ data = length 65, hash 3EC9965C
+tracksEnded = true
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear.opus.0.dump b/testdata/src/test/assets/extractordumps/ogg/bear.opus.0.dump
index 2dccaa69ac..e47df0d32f 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear.opus.0.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear.opus.0.dump
@@ -13,6 +13,7 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: encoder=Lavf54.20.4]
initializationData:
data = length 19, hash BFE794DB
data = length 8, hash CA22068C
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear.opus.1.dump b/testdata/src/test/assets/extractordumps/ogg/bear.opus.1.dump
index c5786e3492..151cf73ae2 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear.opus.1.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear.opus.1.dump
@@ -13,6 +13,7 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: encoder=Lavf54.20.4]
initializationData:
data = length 19, hash BFE794DB
data = length 8, hash CA22068C
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear.opus.2.dump b/testdata/src/test/assets/extractordumps/ogg/bear.opus.2.dump
index 14d68f3b8f..4b10cd0a34 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear.opus.2.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear.opus.2.dump
@@ -13,6 +13,7 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: encoder=Lavf54.20.4]
initializationData:
data = length 19, hash BFE794DB
data = length 8, hash CA22068C
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear.opus.3.dump b/testdata/src/test/assets/extractordumps/ogg/bear.opus.3.dump
index b4d5e824e3..e82e7e5065 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear.opus.3.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear.opus.3.dump
@@ -13,6 +13,7 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: encoder=Lavf54.20.4]
initializationData:
data = length 19, hash BFE794DB
data = length 8, hash CA22068C
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear.opus.unknown_length.dump b/testdata/src/test/assets/extractordumps/ogg/bear.opus.unknown_length.dump
index aa34535336..b5f4b1b400 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear.opus.unknown_length.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear.opus.unknown_length.dump
@@ -10,6 +10,7 @@ track 0:
sampleMimeType = audio/opus
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: encoder=Lavf54.20.4]
initializationData:
data = length 19, hash BFE794DB
data = length 8, hash CA22068C
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.0.dump b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.0.dump
index 92aec373b5..94ec8d38d2 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.0.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.0.dump
@@ -14,6 +14,7 @@ track 0:
sampleMimeType = audio/vorbis
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: TITLE=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ARTIST=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ALBUM=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: PERFORMER=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: LOCATION=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: encoder=Lavf58.45.100]
initializationData:
data = length 30, hash 9A8FF207
data = length 3832, hash 8A406249
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.1.dump b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.1.dump
index 1a71ebbb10..6da8690c7a 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.1.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.1.dump
@@ -14,6 +14,7 @@ track 0:
sampleMimeType = audio/vorbis
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: TITLE=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ARTIST=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ALBUM=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: PERFORMER=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: LOCATION=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: encoder=Lavf58.45.100]
initializationData:
data = length 30, hash 9A8FF207
data = length 3832, hash 8A406249
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.2.dump b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.2.dump
index 50b21ade22..f60275d116 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.2.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.2.dump
@@ -14,6 +14,7 @@ track 0:
sampleMimeType = audio/vorbis
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: TITLE=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ARTIST=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ALBUM=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: PERFORMER=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: LOCATION=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: encoder=Lavf58.45.100]
initializationData:
data = length 30, hash 9A8FF207
data = length 3832, hash 8A406249
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.3.dump b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.3.dump
index 1d76d892d3..8359acfb49 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.3.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.3.dump
@@ -14,6 +14,7 @@ track 0:
sampleMimeType = audio/vorbis
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: TITLE=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ARTIST=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ALBUM=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: PERFORMER=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: LOCATION=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: encoder=Lavf58.45.100]
initializationData:
data = length 30, hash 9A8FF207
data = length 3832, hash 8A406249
diff --git a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.unknown_length.dump b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.unknown_length.dump
index 9830a08357..f16c4f2e57 100644
--- a/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.unknown_length.dump
+++ b/testdata/src/test/assets/extractordumps/ogg/bear_vorbis_with_large_metadata.ogg.unknown_length.dump
@@ -11,6 +11,7 @@ track 0:
sampleMimeType = audio/vorbis
channelCount = 2
sampleRate = 48000
+ metadata = entries=[VC: TITLE=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ARTIST=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: ALBUM=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: PERFORMER=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: LOCATION=FooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBarFooBar, VC: encoder=Lavf58.45.100]
initializationData:
data = length 30, hash 9A8FF207
data = length 3832, hash 8A406249
diff --git a/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_rotate90.png b/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_rotate90.png
new file mode 100644
index 0000000000..ac721443c9
Binary files /dev/null and b/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_rotate90.png differ
diff --git a/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_scale_narrow.png b/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_scale_narrow.png
new file mode 100644
index 0000000000..0c53022a09
Binary files /dev/null and b/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_scale_narrow.png differ
diff --git a/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_translate_right.png b/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_translate_right.png
new file mode 100644
index 0000000000..8ad95fe043
Binary files /dev/null and b/testdata/src/test/assets/media/bitmap/sample_mp4_first_frame_translate_right.png differ
diff --git a/testdata/src/test/assets/media/mkv/sample_with_null_terminated_vtt_subtitles.mkv b/testdata/src/test/assets/media/mkv/sample_with_null_terminated_vtt_subtitles.mkv
new file mode 100644
index 0000000000..1a0a94c5d8
Binary files /dev/null and b/testdata/src/test/assets/media/mkv/sample_with_null_terminated_vtt_subtitles.mkv differ
diff --git a/testdata/src/test/assets/media/mkv/sample_with_vtt_subtitles.mkv b/testdata/src/test/assets/media/mkv/sample_with_vtt_subtitles.mkv
new file mode 100644
index 0000000000..5ba4d21f3b
Binary files /dev/null and b/testdata/src/test/assets/media/mkv/sample_with_vtt_subtitles.mkv differ
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_availabilityTimeOffset_baseUrl b/testdata/src/test/assets/media/mpd/sample_mpd_availabilityTimeOffset_baseUrl
index 365416825c..7db98f166a 100644
--- a/testdata/src/test/assets/media/mpd/sample_mpd_availabilityTimeOffset_baseUrl
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_availabilityTimeOffset_baseUrl
@@ -3,7 +3,7 @@
xmlns="urn:mpeg:DASH:schema:MPD:2011"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd"
xmlns:dvb="urn:dvb:dash:dash-extensions:2014-1"
- profiles="urn:mpeg:dash:profile:isoff-main:2011"
+ profiles="urn:mpeg:dash:profile:isoff-main:2011,urn:dvb:dash:profile:dvb-dash:2014"
type="dynamic"
availabilityStartTime="2016-10-14T17:00:17">
http://video.com/baseUrl
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_multiple_baseUrls b/testdata/src/test/assets/media/mpd/sample_mpd_multiple_baseUrls
index 228e64a03b..cb09376176 100644
--- a/testdata/src/test/assets/media/mpd/sample_mpd_multiple_baseUrls
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_multiple_baseUrls
@@ -3,7 +3,7 @@
xmlns="urn:mpeg:DASH:schema:MPD:2011"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd"
xmlns:dvb="urn:dvb:dash:dash-extensions:2014-1"
- profiles="urn:mpeg:dash:profile:isoff-main:2011"
+ profiles="urn:mpeg:dash:profile:isoff-main:2011,urn:dvb:dash:profile:dvb-dash:2014"
type="dynamic"
availabilityStartTime="2016-10-14T17:00:17">
http://video.com/baseUrl/a/
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_relative_baseUrls_dvb_profile_declared b/testdata/src/test/assets/media/mpd/sample_mpd_relative_baseUrls_dvb_profile_declared
new file mode 100644
index 0000000000..270df26127
--- /dev/null
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_relative_baseUrls_dvb_profile_declared
@@ -0,0 +1,17 @@
+
+
+
+ //anotherhost.com/some/url/1/
+ //anotherhost.com/some/url/2/
+
+
+
+
+
+
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_relative_baseUrls_dvb_profile_not_declared b/testdata/src/test/assets/media/mpd/sample_mpd_relative_baseUrls_dvb_profile_not_declared
new file mode 100644
index 0000000000..c622ba56a3
--- /dev/null
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_relative_baseUrls_dvb_profile_not_declared
@@ -0,0 +1,16 @@
+
+
+
+ //anotherhost.com/some/url/1/
+ //anotherhost.com/some/url/2/
+
+
+
+
+
+
diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_vod_location_fallback b/testdata/src/test/assets/media/mpd/sample_mpd_vod_location_fallback
index 32207dde45..acc7886b83 100644
--- a/testdata/src/test/assets/media/mpd/sample_mpd_vod_location_fallback
+++ b/testdata/src/test/assets/media/mpd/sample_mpd_vod_location_fallback
@@ -4,7 +4,7 @@
xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011"
xmlns:dvb="urn:dvb:dash:dash-extensions:2014-1"
minBufferTime="PT1S"
- profiles="urn:mpeg:dash:profile:isoff-main:2011"
+ profiles="urn:mpeg:dash:profile:isoff-main:2011,urn:dvb:dash:profile:dvb-dash:2014"
type="static"
mediaPresentationDuration="PT904S">
http://video.com/baseUrl/a/
diff --git a/testdata/src/test/assets/playbackdumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.dump b/testdata/src/test/assets/playbackdumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.dump
new file mode 100644
index 0000000000..2279019f2c
--- /dev/null
+++ b/testdata/src/test/assets/playbackdumps/mkv/sample_with_null_terminated_vtt_subtitles.mkv.dump
@@ -0,0 +1,65 @@
+MediaCodecAdapter (exotest.audio.ac3):
+ buffers.length = 30
+ buffers[0] = length 416, hash 211F2286
+ buffers[1] = length 418, hash 77425A86
+ buffers[2] = length 418, hash A0FE5CA1
+ buffers[3] = length 418, hash 2309B066
+ buffers[4] = length 418, hash 928A653B
+ buffers[5] = length 418, hash 3422F0CB
+ buffers[6] = length 418, hash EFF43D5B
+ buffers[7] = length 418, hash FC8093C7
+ buffers[8] = length 418, hash CCC08A16
+ buffers[9] = length 418, hash 2A6EE863
+ buffers[10] = length 418, hash D69A9251
+ buffers[11] = length 418, hash BCFB758D
+ buffers[12] = length 418, hash 11B66799
+ buffers[13] = length 418, hash C824D392
+ buffers[14] = length 418, hash C167D872
+ buffers[15] = length 418, hash 4221C855
+ buffers[16] = length 418, hash 4D4FF934
+ buffers[17] = length 418, hash 984AA025
+ buffers[18] = length 418, hash BB788B46
+ buffers[19] = length 418, hash 9EFBFD97
+ buffers[20] = length 418, hash DF1A460C
+ buffers[21] = length 418, hash 2BDB56A
+ buffers[22] = length 418, hash CA230060
+ buffers[23] = length 418, hash D2F19F41
+ buffers[24] = length 418, hash AF392D79
+ buffers[25] = length 418, hash C5D7F2A3
+ buffers[26] = length 418, hash 733A35AE
+ buffers[27] = length 418, hash DE46E5D3
+ buffers[28] = length 418, hash 56AB8D37
+ buffers[29] = length 0, hash 1
+MediaCodecAdapter (exotest.video.avc):
+ buffers.length = 31
+ buffers[0] = length 36477, hash F0F36CFE
+ buffers[1] = length 5341, hash 40B85E2
+ buffers[2] = length 596, hash 357B4D92
+ buffers[3] = length 7704, hash A39EDA06
+ buffers[4] = length 989, hash 2813C72D
+ buffers[5] = length 721, hash C50D1C73
+ buffers[6] = length 519, hash 65FE1911
+ buffers[7] = length 6160, hash E1CAC0EC
+ buffers[8] = length 953, hash 7160C661
+ buffers[9] = length 620, hash 7A7AE07C
+ buffers[10] = length 405, hash 5CC7F4E7
+ buffers[11] = length 4852, hash 9DB6979D
+ buffers[12] = length 547, hash E31A6979
+ buffers[13] = length 570, hash FEC40D00
+ buffers[14] = length 5525, hash 7C478F7E
+ buffers[15] = length 1082, hash DA07059A
+ buffers[16] = length 807, hash 93478E6B
+ buffers[17] = length 744, hash 9A8E6026
+ buffers[18] = length 4732, hash C73B23C0
+ buffers[19] = length 1004, hash 8A19A228
+ buffers[20] = length 794, hash 8126022C
+ buffers[21] = length 645, hash F08300E5
+ buffers[22] = length 2684, hash 727FE378
+ buffers[23] = length 787, hash 419A7821
+ buffers[24] = length 649, hash 5C159346
+ buffers[25] = length 509, hash F912D655
+ buffers[26] = length 1226, hash 29815C21
+ buffers[27] = length 898, hash D997AD0A
+ buffers[28] = length 476, hash A0423645
+ buffers[29] = length 486, hash DDF32CBB
+ buffers[30] = length 0, hash 1
diff --git a/testdata/src/test/assets/playbackdumps/mkv/sample_with_vtt_subtitles.mkv.dump b/testdata/src/test/assets/playbackdumps/mkv/sample_with_vtt_subtitles.mkv.dump
new file mode 100644
index 0000000000..2279019f2c
--- /dev/null
+++ b/testdata/src/test/assets/playbackdumps/mkv/sample_with_vtt_subtitles.mkv.dump
@@ -0,0 +1,65 @@
+MediaCodecAdapter (exotest.audio.ac3):
+ buffers.length = 30
+ buffers[0] = length 416, hash 211F2286
+ buffers[1] = length 418, hash 77425A86
+ buffers[2] = length 418, hash A0FE5CA1
+ buffers[3] = length 418, hash 2309B066
+ buffers[4] = length 418, hash 928A653B
+ buffers[5] = length 418, hash 3422F0CB
+ buffers[6] = length 418, hash EFF43D5B
+ buffers[7] = length 418, hash FC8093C7
+ buffers[8] = length 418, hash CCC08A16
+ buffers[9] = length 418, hash 2A6EE863
+ buffers[10] = length 418, hash D69A9251
+ buffers[11] = length 418, hash BCFB758D
+ buffers[12] = length 418, hash 11B66799
+ buffers[13] = length 418, hash C824D392
+ buffers[14] = length 418, hash C167D872
+ buffers[15] = length 418, hash 4221C855
+ buffers[16] = length 418, hash 4D4FF934
+ buffers[17] = length 418, hash 984AA025
+ buffers[18] = length 418, hash BB788B46
+ buffers[19] = length 418, hash 9EFBFD97
+ buffers[20] = length 418, hash DF1A460C
+ buffers[21] = length 418, hash 2BDB56A
+ buffers[22] = length 418, hash CA230060
+ buffers[23] = length 418, hash D2F19F41
+ buffers[24] = length 418, hash AF392D79
+ buffers[25] = length 418, hash C5D7F2A3
+ buffers[26] = length 418, hash 733A35AE
+ buffers[27] = length 418, hash DE46E5D3
+ buffers[28] = length 418, hash 56AB8D37
+ buffers[29] = length 0, hash 1
+MediaCodecAdapter (exotest.video.avc):
+ buffers.length = 31
+ buffers[0] = length 36477, hash F0F36CFE
+ buffers[1] = length 5341, hash 40B85E2
+ buffers[2] = length 596, hash 357B4D92
+ buffers[3] = length 7704, hash A39EDA06
+ buffers[4] = length 989, hash 2813C72D
+ buffers[5] = length 721, hash C50D1C73
+ buffers[6] = length 519, hash 65FE1911
+ buffers[7] = length 6160, hash E1CAC0EC
+ buffers[8] = length 953, hash 7160C661
+ buffers[9] = length 620, hash 7A7AE07C
+ buffers[10] = length 405, hash 5CC7F4E7
+ buffers[11] = length 4852, hash 9DB6979D
+ buffers[12] = length 547, hash E31A6979
+ buffers[13] = length 570, hash FEC40D00
+ buffers[14] = length 5525, hash 7C478F7E
+ buffers[15] = length 1082, hash DA07059A
+ buffers[16] = length 807, hash 93478E6B
+ buffers[17] = length 744, hash 9A8E6026
+ buffers[18] = length 4732, hash C73B23C0
+ buffers[19] = length 1004, hash 8A19A228
+ buffers[20] = length 794, hash 8126022C
+ buffers[21] = length 645, hash F08300E5
+ buffers[22] = length 2684, hash 727FE378
+ buffers[23] = length 787, hash 419A7821
+ buffers[24] = length 649, hash 5C159346
+ buffers[25] = length 509, hash F912D655
+ buffers[26] = length 1226, hash 29815C21
+ buffers[27] = length 898, hash D997AD0A
+ buffers[28] = length 476, hash A0423645
+ buffers[29] = length 486, hash DDF32CBB
+ buffers[30] = length 0, hash 1
diff --git a/testdata/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump b/testdata/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump
new file mode 100644
index 0000000000..d97f474a1d
--- /dev/null
+++ b/testdata/src/test/assets/transformerdumps/mp4/sample_ac3.mp4.fallback.dump
@@ -0,0 +1,61 @@
+containerMimeType = video/mp4
+format 0:
+ sampleMimeType = audio/mp4a-latm
+ channelCount = 6
+ sampleRate = 48000
+ pcmEncoding = 2
+sample:
+ trackIndex = 0
+ dataHashCode = 1896404418
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 0
+sample:
+ trackIndex = 0
+ dataHashCode = -2134951116
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 2667
+sample:
+ trackIndex = 0
+ dataHashCode = 97556101
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 5334
+sample:
+ trackIndex = 0
+ dataHashCode = -1448980924
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 8000
+sample:
+ trackIndex = 0
+ dataHashCode = 1871012467
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 10667
+sample:
+ trackIndex = 0
+ dataHashCode = -1317831364
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 13334
+sample:
+ trackIndex = 0
+ dataHashCode = -1728189539
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 16000
+sample:
+ trackIndex = 0
+ dataHashCode = -1715881661
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 18667
+sample:
+ trackIndex = 0
+ dataHashCode = -1428554542
+ size = 1536
+ isKeyFrame = true
+ presentationTimeUs = 21334
+released = true
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
index 136327739f..19c833b42b 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java
@@ -357,12 +357,6 @@ public class StubExoPlayer extends StubPlayer implements ExoPlayer {
throw new UnsupportedOperationException();
}
- @Deprecated
- @Override
- public void setThrowsWhenUsingWrongThread(boolean throwsWhenUsingWrongThread) {
- throw new UnsupportedOperationException();
- }
-
@Override
public void experimentalSetOffloadSchedulingEnabled(boolean offloadSchedulingEnabled) {
throw new UnsupportedOperationException();