Introduce GlEffect interface for effect specification.
PiperOrigin-RevId: 446143537
This commit is contained in:
parent
90ce9a6787
commit
b410a922fe
@ -58,7 +58,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
public static final String ENABLE_FALLBACK = "enable_fallback";
|
public static final String ENABLE_FALLBACK = "enable_fallback";
|
||||||
public static final String ENABLE_REQUEST_SDR_TONE_MAPPING = "enable_request_sdr_tone_mapping";
|
public static final String ENABLE_REQUEST_SDR_TONE_MAPPING = "enable_request_sdr_tone_mapping";
|
||||||
public static final String ENABLE_HDR_EDITING = "enable_hdr_editing";
|
public static final String ENABLE_HDR_EDITING = "enable_hdr_editing";
|
||||||
public static final String DEMO_FRAME_PROCESSORS_SELECTIONS = "demo_frame_processors_selections";
|
public static final String DEMO_EFFECTS_SELECTIONS = "demo_effects_selections";
|
||||||
public static final String PERIODIC_VIGNETTE_CENTER_X = "periodic_vignette_center_x";
|
public static final String PERIODIC_VIGNETTE_CENTER_X = "periodic_vignette_center_x";
|
||||||
public static final String PERIODIC_VIGNETTE_CENTER_Y = "periodic_vignette_center_y";
|
public static final String PERIODIC_VIGNETTE_CENTER_Y = "periodic_vignette_center_y";
|
||||||
public static final String PERIODIC_VIGNETTE_INNER_RADIUS = "periodic_vignette_inner_radius";
|
public static final String PERIODIC_VIGNETTE_INNER_RADIUS = "periodic_vignette_inner_radius";
|
||||||
@ -91,7 +91,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
"DASH stream with non-square pixels",
|
"DASH stream with non-square pixels",
|
||||||
"MP4 with HDR (HDR10) H265 video (encoding may fail)",
|
"MP4 with HDR (HDR10) H265 video (encoding may fail)",
|
||||||
};
|
};
|
||||||
private static final String[] DEMO_FRAME_PROCESSORS = {
|
private static final String[] DEMO_EFFECTS = {
|
||||||
"Dizzy crop", "Periodic vignette", "3D spin", "Overlay logo & timer", "Zoom in start"
|
"Dizzy crop", "Periodic vignette", "3D spin", "Overlay logo & timer", "Zoom in start"
|
||||||
};
|
};
|
||||||
private static final int PERIODIC_VIGNETTE_INDEX = 1;
|
private static final int PERIODIC_VIGNETTE_INDEX = 1;
|
||||||
@ -111,8 +111,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
private @MonotonicNonNull CheckBox enableFallbackCheckBox;
|
private @MonotonicNonNull CheckBox enableFallbackCheckBox;
|
||||||
private @MonotonicNonNull CheckBox enableRequestSdrToneMappingCheckBox;
|
private @MonotonicNonNull CheckBox enableRequestSdrToneMappingCheckBox;
|
||||||
private @MonotonicNonNull CheckBox enableHdrEditingCheckBox;
|
private @MonotonicNonNull CheckBox enableHdrEditingCheckBox;
|
||||||
private @MonotonicNonNull Button selectDemoFrameProcessorsButton;
|
private @MonotonicNonNull Button selectDemoEffectsButton;
|
||||||
private boolean @MonotonicNonNull [] demoFrameProcessorsSelections;
|
private boolean @MonotonicNonNull [] demoEffectsSelections;
|
||||||
private int inputUriPosition;
|
private int inputUriPosition;
|
||||||
private float periodicVignetteCenterX;
|
private float periodicVignetteCenterX;
|
||||||
private float periodicVignetteCenterY;
|
private float periodicVignetteCenterY;
|
||||||
@ -187,9 +187,9 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
findViewById(R.id.request_sdr_tone_mapping).setEnabled(isRequestSdrToneMappingSupported());
|
findViewById(R.id.request_sdr_tone_mapping).setEnabled(isRequestSdrToneMappingSupported());
|
||||||
enableHdrEditingCheckBox = findViewById(R.id.hdr_editing_checkbox);
|
enableHdrEditingCheckBox = findViewById(R.id.hdr_editing_checkbox);
|
||||||
|
|
||||||
demoFrameProcessorsSelections = new boolean[DEMO_FRAME_PROCESSORS.length];
|
demoEffectsSelections = new boolean[DEMO_EFFECTS.length];
|
||||||
selectDemoFrameProcessorsButton = findViewById(R.id.select_demo_frameprocessors_button);
|
selectDemoEffectsButton = findViewById(R.id.select_demo_effects_button);
|
||||||
selectDemoFrameProcessorsButton.setOnClickListener(this::selectFrameProcessors);
|
selectDemoEffectsButton.setOnClickListener(this::selectDemoEffects);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -220,7 +220,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
"enableFallbackCheckBox",
|
"enableFallbackCheckBox",
|
||||||
"enableRequestSdrToneMappingCheckBox",
|
"enableRequestSdrToneMappingCheckBox",
|
||||||
"enableHdrEditingCheckBox",
|
"enableHdrEditingCheckBox",
|
||||||
"demoFrameProcessorsSelections"
|
"demoEffectsSelections"
|
||||||
})
|
})
|
||||||
private void startTransformation(View view) {
|
private void startTransformation(View view) {
|
||||||
Intent transformerIntent = new Intent(/* packageContext= */ this, TransformerActivity.class);
|
Intent transformerIntent = new Intent(/* packageContext= */ this, TransformerActivity.class);
|
||||||
@ -255,7 +255,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
bundle.putBoolean(
|
bundle.putBoolean(
|
||||||
ENABLE_REQUEST_SDR_TONE_MAPPING, enableRequestSdrToneMappingCheckBox.isChecked());
|
ENABLE_REQUEST_SDR_TONE_MAPPING, enableRequestSdrToneMappingCheckBox.isChecked());
|
||||||
bundle.putBoolean(ENABLE_HDR_EDITING, enableHdrEditingCheckBox.isChecked());
|
bundle.putBoolean(ENABLE_HDR_EDITING, enableHdrEditingCheckBox.isChecked());
|
||||||
bundle.putBooleanArray(DEMO_FRAME_PROCESSORS_SELECTIONS, demoFrameProcessorsSelections);
|
bundle.putBooleanArray(DEMO_EFFECTS_SELECTIONS, demoEffectsSelections);
|
||||||
bundle.putFloat(PERIODIC_VIGNETTE_CENTER_X, periodicVignetteCenterX);
|
bundle.putFloat(PERIODIC_VIGNETTE_CENTER_X, periodicVignetteCenterX);
|
||||||
bundle.putFloat(PERIODIC_VIGNETTE_CENTER_Y, periodicVignetteCenterY);
|
bundle.putFloat(PERIODIC_VIGNETTE_CENTER_Y, periodicVignetteCenterY);
|
||||||
bundle.putFloat(PERIODIC_VIGNETTE_INNER_RADIUS, periodicVignetteInnerRadius);
|
bundle.putFloat(PERIODIC_VIGNETTE_INNER_RADIUS, periodicVignetteInnerRadius);
|
||||||
@ -278,13 +278,11 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectFrameProcessors(View view) {
|
private void selectDemoEffects(View view) {
|
||||||
new AlertDialog.Builder(/* context= */ this)
|
new AlertDialog.Builder(/* context= */ this)
|
||||||
.setTitle(R.string.select_demo_frameprocessors)
|
.setTitle(R.string.select_demo_effects)
|
||||||
.setMultiChoiceItems(
|
.setMultiChoiceItems(
|
||||||
DEMO_FRAME_PROCESSORS,
|
DEMO_EFFECTS, checkNotNull(demoEffectsSelections), this::selectDemoEffect)
|
||||||
checkNotNull(demoFrameProcessorsSelections),
|
|
||||||
this::selectFrameProcessor)
|
|
||||||
.setPositiveButton(android.R.string.ok, /* listener= */ null)
|
.setPositiveButton(android.R.string.ok, /* listener= */ null)
|
||||||
.create()
|
.create()
|
||||||
.show();
|
.show();
|
||||||
@ -296,9 +294,9 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
selectedFileTextView.setText(URI_DESCRIPTIONS[inputUriPosition]);
|
selectedFileTextView.setText(URI_DESCRIPTIONS[inputUriPosition]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresNonNull("demoFrameProcessorsSelections")
|
@RequiresNonNull("demoEffectsSelections")
|
||||||
private void selectFrameProcessor(DialogInterface dialog, int which, boolean isChecked) {
|
private void selectDemoEffect(DialogInterface dialog, int which, boolean isChecked) {
|
||||||
demoFrameProcessorsSelections[which] = isChecked;
|
demoEffectsSelections[which] = isChecked;
|
||||||
if (!isChecked || which != PERIODIC_VIGNETTE_INDEX) {
|
if (!isChecked || which != PERIODIC_VIGNETTE_INDEX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -337,7 +335,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
"rotateSpinner",
|
"rotateSpinner",
|
||||||
"enableRequestSdrToneMappingCheckBox",
|
"enableRequestSdrToneMappingCheckBox",
|
||||||
"enableHdrEditingCheckBox",
|
"enableHdrEditingCheckBox",
|
||||||
"selectDemoFrameProcessorsButton"
|
"selectDemoEffectsButton"
|
||||||
})
|
})
|
||||||
private void onRemoveAudio(View view) {
|
private void onRemoveAudio(View view) {
|
||||||
if (((CheckBox) view).isChecked()) {
|
if (((CheckBox) view).isChecked()) {
|
||||||
@ -357,7 +355,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
"rotateSpinner",
|
"rotateSpinner",
|
||||||
"enableRequestSdrToneMappingCheckBox",
|
"enableRequestSdrToneMappingCheckBox",
|
||||||
"enableHdrEditingCheckBox",
|
"enableHdrEditingCheckBox",
|
||||||
"selectDemoFrameProcessorsButton"
|
"selectDemoEffectsButton"
|
||||||
})
|
})
|
||||||
private void onRemoveVideo(View view) {
|
private void onRemoveVideo(View view) {
|
||||||
if (((CheckBox) view).isChecked()) {
|
if (((CheckBox) view).isChecked()) {
|
||||||
@ -376,7 +374,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
"rotateSpinner",
|
"rotateSpinner",
|
||||||
"enableRequestSdrToneMappingCheckBox",
|
"enableRequestSdrToneMappingCheckBox",
|
||||||
"enableHdrEditingCheckBox",
|
"enableHdrEditingCheckBox",
|
||||||
"selectDemoFrameProcessorsButton"
|
"selectDemoEffectsButton"
|
||||||
})
|
})
|
||||||
private void enableTrackSpecificOptions(boolean isAudioEnabled, boolean isVideoEnabled) {
|
private void enableTrackSpecificOptions(boolean isAudioEnabled, boolean isVideoEnabled) {
|
||||||
audioMimeSpinner.setEnabled(isAudioEnabled);
|
audioMimeSpinner.setEnabled(isAudioEnabled);
|
||||||
@ -387,7 +385,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
|||||||
enableRequestSdrToneMappingCheckBox.setEnabled(
|
enableRequestSdrToneMappingCheckBox.setEnabled(
|
||||||
isRequestSdrToneMappingSupported() && isVideoEnabled);
|
isRequestSdrToneMappingSupported() && isVideoEnabled);
|
||||||
enableHdrEditingCheckBox.setEnabled(isVideoEnabled);
|
enableHdrEditingCheckBox.setEnabled(isVideoEnabled);
|
||||||
selectDemoFrameProcessorsButton.setEnabled(isVideoEnabled);
|
selectDemoEffectsButton.setEnabled(isVideoEnabled);
|
||||||
|
|
||||||
findViewById(R.id.audio_mime_text_view).setEnabled(isAudioEnabled);
|
findViewById(R.id.audio_mime_text_view).setEnabled(isAudioEnabled);
|
||||||
findViewById(R.id.video_mime_text_view).setEnabled(isVideoEnabled);
|
findViewById(R.id.video_mime_text_view).setEnabled(isVideoEnabled);
|
||||||
|
@ -40,7 +40,7 @@ import androidx.media3.exoplayer.ExoPlayer;
|
|||||||
import androidx.media3.exoplayer.util.DebugTextViewHelper;
|
import androidx.media3.exoplayer.util.DebugTextViewHelper;
|
||||||
import androidx.media3.transformer.DefaultEncoderFactory;
|
import androidx.media3.transformer.DefaultEncoderFactory;
|
||||||
import androidx.media3.transformer.EncoderSelector;
|
import androidx.media3.transformer.EncoderSelector;
|
||||||
import androidx.media3.transformer.GlFrameProcessor;
|
import androidx.media3.transformer.GlEffect;
|
||||||
import androidx.media3.transformer.ProgressHolder;
|
import androidx.media3.transformer.ProgressHolder;
|
||||||
import androidx.media3.transformer.TransformationException;
|
import androidx.media3.transformer.TransformationException;
|
||||||
import androidx.media3.transformer.TransformationRequest;
|
import androidx.media3.transformer.TransformationRequest;
|
||||||
@ -240,16 +240,17 @@ public final class TransformerActivity extends AppCompatActivity {
|
|||||||
EncoderSelector.DEFAULT,
|
EncoderSelector.DEFAULT,
|
||||||
/* enableFallback= */ bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK)));
|
/* enableFallback= */ bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK)));
|
||||||
|
|
||||||
ImmutableList.Builder<GlFrameProcessor> frameProcessors = new ImmutableList.Builder<>();
|
ImmutableList.Builder<GlEffect> effects = new ImmutableList.Builder<>();
|
||||||
@Nullable
|
@Nullable
|
||||||
boolean[] selectedFrameProcessors =
|
boolean[] selectedEffects =
|
||||||
bundle.getBooleanArray(ConfigurationActivity.DEMO_FRAME_PROCESSORS_SELECTIONS);
|
bundle.getBooleanArray(ConfigurationActivity.DEMO_EFFECTS_SELECTIONS);
|
||||||
if (selectedFrameProcessors != null) {
|
if (selectedEffects != null) {
|
||||||
if (selectedFrameProcessors[0]) {
|
if (selectedEffects[0]) {
|
||||||
frameProcessors.add(AdvancedFrameProcessorFactory.createDizzyCropFrameProcessor());
|
effects.add(AdvancedFrameProcessorFactory::createDizzyCropFrameProcessor);
|
||||||
}
|
}
|
||||||
if (selectedFrameProcessors[1]) {
|
if (selectedEffects[1]) {
|
||||||
frameProcessors.add(
|
effects.add(
|
||||||
|
() ->
|
||||||
new PeriodicVignetteFrameProcessor(
|
new PeriodicVignetteFrameProcessor(
|
||||||
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X),
|
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_X),
|
||||||
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_Y),
|
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_CENTER_Y),
|
||||||
@ -259,16 +260,16 @@ public final class TransformerActivity extends AppCompatActivity {
|
|||||||
ConfigurationActivity.PERIODIC_VIGNETTE_OUTER_RADIUS),
|
ConfigurationActivity.PERIODIC_VIGNETTE_OUTER_RADIUS),
|
||||||
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_OUTER_RADIUS)));
|
bundle.getFloat(ConfigurationActivity.PERIODIC_VIGNETTE_OUTER_RADIUS)));
|
||||||
}
|
}
|
||||||
if (selectedFrameProcessors[2]) {
|
if (selectedEffects[2]) {
|
||||||
frameProcessors.add(AdvancedFrameProcessorFactory.createSpin3dFrameProcessor());
|
effects.add(AdvancedFrameProcessorFactory::createSpin3dFrameProcessor);
|
||||||
}
|
}
|
||||||
if (selectedFrameProcessors[3]) {
|
if (selectedEffects[3]) {
|
||||||
frameProcessors.add(new BitmapOverlayFrameProcessor());
|
effects.add(BitmapOverlayFrameProcessor::new);
|
||||||
}
|
}
|
||||||
if (selectedFrameProcessors[4]) {
|
if (selectedEffects[4]) {
|
||||||
frameProcessors.add(AdvancedFrameProcessorFactory.createZoomInTransitionFrameProcessor());
|
effects.add(AdvancedFrameProcessorFactory::createZoomInTransitionFrameProcessor);
|
||||||
}
|
}
|
||||||
transformerBuilder.setFrameProcessors(frameProcessors.build());
|
transformerBuilder.setVideoFrameEffects(effects.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return transformerBuilder
|
return transformerBuilder
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/selected_file_text_view"
|
app:layout_constraintTop_toBottomOf="@+id/selected_file_text_view"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/select_demo_frameprocessors_button">
|
app:layout_constraintBottom_toTopOf="@+id/select_demo_effects_button">
|
||||||
<TableLayout
|
<TableLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -192,13 +192,13 @@
|
|||||||
</TableLayout>
|
</TableLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/select_demo_frameprocessors_button"
|
android:id="@+id/select_demo_effects_button"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="32dp"
|
||||||
android:layout_marginStart="32dp"
|
android:layout_marginStart="32dp"
|
||||||
android:layout_marginEnd="32dp"
|
android:layout_marginEnd="32dp"
|
||||||
android:text="@string/select_demo_frameprocessors"
|
android:text="@string/select_demo_effects"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/transform_button"
|
app:layout_constraintBottom_toTopOf="@+id/transform_button"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<string name="enable_fallback" translatable="false">Enable fallback</string>
|
<string name="enable_fallback" translatable="false">Enable fallback</string>
|
||||||
<string name="request_sdr_tone_mapping" translatable="false">Request SDR tone-mapping (API 31+)</string>
|
<string name="request_sdr_tone_mapping" translatable="false">Request SDR tone-mapping (API 31+)</string>
|
||||||
<string name="hdr_editing" translatable="false">[Experimental] HDR editing</string>
|
<string name="hdr_editing" translatable="false">[Experimental] HDR editing</string>
|
||||||
<string name="select_demo_frameprocessors" translatable="false">Add demo effects</string>
|
<string name="select_demo_effects" translatable="false">Add demo effects</string>
|
||||||
<string name="periodic_vignette_options" translatable="false">Periodic vignette options</string>
|
<string name="periodic_vignette_options" translatable="false">Periodic vignette options</string>
|
||||||
<string name="transform" translatable="false">Transform</string>
|
<string name="transform" translatable="false">Transform</string>
|
||||||
<string name="debug_preview" translatable="false">Debug preview:</string>
|
<string name="debug_preview" translatable="false">Debug preview:</string>
|
||||||
|
@ -130,7 +130,7 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
Matrix translateRightMatrix = new Matrix();
|
Matrix translateRightMatrix = new Matrix();
|
||||||
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
|
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
|
||||||
GlFrameProcessor glFrameProcessor = new AdvancedFrameProcessor(translateRightMatrix);
|
GlFrameProcessor glFrameProcessor = new AdvancedFrameProcessor(translateRightMatrix);
|
||||||
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, glFrameProcessor);
|
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, () -> glFrameProcessor);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
|
||||||
|
|
||||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||||
@ -155,7 +155,9 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
GlFrameProcessor rotate45FrameProcessor =
|
GlFrameProcessor rotate45FrameProcessor =
|
||||||
new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
|
new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
|
||||||
setUpAndPrepareFirstFrame(
|
setUpAndPrepareFirstFrame(
|
||||||
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, translateRightFrameProcessor, rotate45FrameProcessor);
|
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO,
|
||||||
|
() -> translateRightFrameProcessor,
|
||||||
|
() -> rotate45FrameProcessor);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_THEN_ROTATE_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_THEN_ROTATE_PNG_ASSET_PATH);
|
||||||
|
|
||||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||||
@ -180,7 +182,9 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
GlFrameProcessor translateRightFrameProcessor =
|
GlFrameProcessor translateRightFrameProcessor =
|
||||||
new AdvancedFrameProcessor(translateRightMatrix);
|
new AdvancedFrameProcessor(translateRightMatrix);
|
||||||
setUpAndPrepareFirstFrame(
|
setUpAndPrepareFirstFrame(
|
||||||
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, rotate45FrameProcessor, translateRightFrameProcessor);
|
DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO,
|
||||||
|
() -> rotate45FrameProcessor,
|
||||||
|
() -> translateRightFrameProcessor);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_THEN_TRANSLATE_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_THEN_TRANSLATE_PNG_ASSET_PATH);
|
||||||
|
|
||||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||||
@ -200,7 +204,7 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
String testId = "processData_withPresentationFrameProcessor_setResolution";
|
String testId = "processData_withPresentationFrameProcessor_setResolution";
|
||||||
GlFrameProcessor glFrameProcessor =
|
GlFrameProcessor glFrameProcessor =
|
||||||
new PresentationFrameProcessor.Builder().setResolution(480).build();
|
new PresentationFrameProcessor.Builder().setResolution(480).build();
|
||||||
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, glFrameProcessor);
|
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, () -> glFrameProcessor);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(REQUEST_OUTPUT_HEIGHT_PNG_ASSET_PATH);
|
||||||
|
|
||||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||||
@ -220,7 +224,7 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
String testId = "processData_withScaleToFitFrameProcessor_rotate45";
|
String testId = "processData_withScaleToFitFrameProcessor_rotate45";
|
||||||
GlFrameProcessor glFrameProcessor =
|
GlFrameProcessor glFrameProcessor =
|
||||||
new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
|
new ScaleToFitFrameProcessor.Builder().setRotationDegrees(45).build();
|
||||||
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, glFrameProcessor);
|
setUpAndPrepareFirstFrame(DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO, () -> glFrameProcessor);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE45_SCALE_TO_FIT_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE45_SCALE_TO_FIT_PNG_ASSET_PATH);
|
||||||
|
|
||||||
Bitmap actualBitmap = processFirstFrameAndEnd();
|
Bitmap actualBitmap = processFirstFrameAndEnd();
|
||||||
@ -240,11 +244,10 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
* accessed on the {@link FrameProcessorChain}'s output {@code outputImageReader}.
|
* accessed on the {@link FrameProcessorChain}'s output {@code outputImageReader}.
|
||||||
*
|
*
|
||||||
* @param pixelWidthHeightRatio The ratio of width over height for each pixel.
|
* @param pixelWidthHeightRatio The ratio of width over height for each pixel.
|
||||||
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors} that will apply changes
|
* @param effects The {@link GlEffect GlEffects} to apply to the input frame.
|
||||||
* to the input frame.
|
|
||||||
*/
|
*/
|
||||||
private void setUpAndPrepareFirstFrame(
|
private void setUpAndPrepareFirstFrame(float pixelWidthHeightRatio, GlEffect... effects)
|
||||||
float pixelWidthHeightRatio, GlFrameProcessor... frameProcessors) throws Exception {
|
throws Exception {
|
||||||
// Set up the extractor to read the first video frame and get its format.
|
// Set up the extractor to read the first video frame and get its format.
|
||||||
MediaExtractor mediaExtractor = new MediaExtractor();
|
MediaExtractor mediaExtractor = new MediaExtractor();
|
||||||
@Nullable MediaCodec mediaCodec = null;
|
@Nullable MediaCodec mediaCodec = null;
|
||||||
@ -267,7 +270,7 @@ public final class FrameProcessorChainPixelTest {
|
|||||||
pixelWidthHeightRatio,
|
pixelWidthHeightRatio,
|
||||||
inputWidth,
|
inputWidth,
|
||||||
inputHeight,
|
inputHeight,
|
||||||
asList(frameProcessors),
|
asList(effects),
|
||||||
/* enableExperimentalHdrEditing= */ false);
|
/* enableExperimentalHdrEditing= */ false);
|
||||||
Size outputSize = frameProcessorChain.getOutputSize();
|
Size outputSize = frameProcessorChain.getOutputSize();
|
||||||
outputImageReader =
|
outputImageReader =
|
||||||
|
@ -112,16 +112,16 @@ public final class FrameProcessorChainTest {
|
|||||||
private static FrameProcessorChain createFrameProcessorChainWithFakeFrameProcessors(
|
private static FrameProcessorChain createFrameProcessorChainWithFakeFrameProcessors(
|
||||||
float pixelWidthHeightRatio, Size inputSize, List<Size> frameProcessorOutputSizes)
|
float pixelWidthHeightRatio, Size inputSize, List<Size> frameProcessorOutputSizes)
|
||||||
throws TransformationException {
|
throws TransformationException {
|
||||||
ImmutableList.Builder<GlFrameProcessor> frameProcessors = new ImmutableList.Builder<>();
|
ImmutableList.Builder<GlEffect> effects = new ImmutableList.Builder<>();
|
||||||
for (Size element : frameProcessorOutputSizes) {
|
for (Size element : frameProcessorOutputSizes) {
|
||||||
frameProcessors.add(new FakeFrameProcessor(element));
|
effects.add(() -> new FakeFrameProcessor(element));
|
||||||
}
|
}
|
||||||
return FrameProcessorChain.create(
|
return FrameProcessorChain.create(
|
||||||
getApplicationContext(),
|
getApplicationContext(),
|
||||||
pixelWidthHeightRatio,
|
pixelWidthHeightRatio,
|
||||||
inputSize.getWidth(),
|
inputSize.getWidth(),
|
||||||
inputSize.getHeight(),
|
inputSize.getHeight(),
|
||||||
frameProcessors.build(),
|
effects.build(),
|
||||||
/* enableExperimentalHdrEditing= */ false);
|
/* enableExperimentalHdrEditing= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
* by this ratio so that the output frame's pixels have a ratio of 1.
|
* by this ratio so that the output frame's pixels have a ratio of 1.
|
||||||
* @param inputWidth The input frame width, in pixels.
|
* @param inputWidth The input frame width, in pixels.
|
||||||
* @param inputHeight The input frame height, in pixels.
|
* @param inputHeight The input frame height, in pixels.
|
||||||
* @param frameProcessors The {@link GlFrameProcessor GlFrameProcessors} to apply to each frame.
|
* @param effects The {@link GlEffect GlEffects} to apply to each frame.
|
||||||
* @param enableExperimentalHdrEditing Whether to attempt to process the input as an HDR signal.
|
* @param enableExperimentalHdrEditing Whether to attempt to process the input as an HDR signal.
|
||||||
* @return A new instance.
|
* @return A new instance.
|
||||||
* @throws TransformationException If reading shader files fails, or an OpenGL error occurs while
|
* @throws TransformationException If reading shader files fails, or an OpenGL error occurs while
|
||||||
@ -86,7 +86,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
float pixelWidthHeightRatio,
|
float pixelWidthHeightRatio,
|
||||||
int inputWidth,
|
int inputWidth,
|
||||||
int inputHeight,
|
int inputHeight,
|
||||||
List<GlFrameProcessor> frameProcessors,
|
List<GlEffect> effects,
|
||||||
boolean enableExperimentalHdrEditing)
|
boolean enableExperimentalHdrEditing)
|
||||||
throws TransformationException {
|
throws TransformationException {
|
||||||
checkArgument(inputWidth > 0, "inputWidth must be positive");
|
checkArgument(inputWidth > 0, "inputWidth must be positive");
|
||||||
@ -103,7 +103,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
pixelWidthHeightRatio,
|
pixelWidthHeightRatio,
|
||||||
inputWidth,
|
inputWidth,
|
||||||
inputHeight,
|
inputHeight,
|
||||||
frameProcessors,
|
effects,
|
||||||
enableExperimentalHdrEditing,
|
enableExperimentalHdrEditing,
|
||||||
singleThreadExecutorService))
|
singleThreadExecutorService))
|
||||||
.get();
|
.get();
|
||||||
@ -118,8 +118,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the OpenGL textures, framebuffers, initializes the {@link GlFrameProcessor
|
* Creates the OpenGL textures and framebuffers, initializes the {@link GlFrameProcessor
|
||||||
* GlFrameProcessors} and returns a new {@code FrameProcessorChain}.
|
* GlFrameProcessors} corresponding to the {@link GlEffect GlEffects}, and returns a new {@code
|
||||||
|
* FrameProcessorChain}.
|
||||||
*
|
*
|
||||||
* <p>This method must be executed using the {@code singleThreadExecutorService}.
|
* <p>This method must be executed using the {@code singleThreadExecutorService}.
|
||||||
*/
|
*/
|
||||||
@ -129,15 +130,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
float pixelWidthHeightRatio,
|
float pixelWidthHeightRatio,
|
||||||
int inputWidth,
|
int inputWidth,
|
||||||
int inputHeight,
|
int inputHeight,
|
||||||
List<GlFrameProcessor> frameProcessors,
|
List<GlEffect> effects,
|
||||||
boolean enableExperimentalHdrEditing,
|
boolean enableExperimentalHdrEditing,
|
||||||
ExecutorService singleThreadExecutorService)
|
ExecutorService singleThreadExecutorService)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
checkState(Thread.currentThread().getName().equals(THREAD_NAME));
|
checkState(Thread.currentThread().getName().equals(THREAD_NAME));
|
||||||
|
|
||||||
EGLDisplay eglDisplay = GlUtil.createEglDisplay();
|
EGLDisplay eglDisplay = GlUtil.createEglDisplay();
|
||||||
ExternalCopyFrameProcessor externalCopyFrameProcessor =
|
|
||||||
new ExternalCopyFrameProcessor(enableExperimentalHdrEditing);
|
|
||||||
EGLContext eglContext =
|
EGLContext eglContext =
|
||||||
enableExperimentalHdrEditing
|
enableExperimentalHdrEditing
|
||||||
? GlUtil.createEglContextEs3Rgba1010102(eglDisplay)
|
? GlUtil.createEglContextEs3Rgba1010102(eglDisplay)
|
||||||
@ -153,20 +152,21 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
GlUtil.focusPlaceholderEglSurface(eglContext, eglDisplay);
|
GlUtil.focusPlaceholderEglSurface(eglContext, eglDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImmutableList<GlFrameProcessor> expandedFrameProcessors =
|
ExternalCopyFrameProcessor externalCopyFrameProcessor =
|
||||||
getExpandedFrameProcessors(
|
new ExternalCopyFrameProcessor(enableExperimentalHdrEditing);
|
||||||
externalCopyFrameProcessor, pixelWidthHeightRatio, frameProcessors);
|
ImmutableList<GlFrameProcessor> frameProcessors =
|
||||||
|
getFrameProcessors(externalCopyFrameProcessor, pixelWidthHeightRatio, effects);
|
||||||
|
|
||||||
// Initialize frame processors.
|
// Initialize frame processors.
|
||||||
int inputExternalTexId = GlUtil.createExternalTexture();
|
int inputExternalTexId = GlUtil.createExternalTexture();
|
||||||
externalCopyFrameProcessor.initialize(context, inputExternalTexId, inputWidth, inputHeight);
|
externalCopyFrameProcessor.initialize(context, inputExternalTexId, inputWidth, inputHeight);
|
||||||
|
|
||||||
int[] framebuffers = new int[expandedFrameProcessors.size() - 1];
|
int[] framebuffers = new int[frameProcessors.size() - 1];
|
||||||
Size inputSize = externalCopyFrameProcessor.getOutputSize();
|
Size inputSize = externalCopyFrameProcessor.getOutputSize();
|
||||||
for (int i = 1; i < expandedFrameProcessors.size(); i++) {
|
for (int i = 1; i < frameProcessors.size(); i++) {
|
||||||
int inputTexId = GlUtil.createTexture(inputSize.getWidth(), inputSize.getHeight());
|
int inputTexId = GlUtil.createTexture(inputSize.getWidth(), inputSize.getHeight());
|
||||||
framebuffers[i - 1] = GlUtil.createFboForTexture(inputTexId);
|
framebuffers[i - 1] = GlUtil.createFboForTexture(inputTexId);
|
||||||
GlFrameProcessor frameProcessor = expandedFrameProcessors.get(i);
|
GlFrameProcessor frameProcessor = frameProcessors.get(i);
|
||||||
frameProcessor.initialize(context, inputTexId, inputSize.getWidth(), inputSize.getHeight());
|
frameProcessor.initialize(context, inputTexId, inputSize.getWidth(), inputSize.getHeight());
|
||||||
inputSize = frameProcessor.getOutputSize();
|
inputSize = frameProcessor.getOutputSize();
|
||||||
}
|
}
|
||||||
@ -176,31 +176,34 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
singleThreadExecutorService,
|
singleThreadExecutorService,
|
||||||
inputExternalTexId,
|
inputExternalTexId,
|
||||||
framebuffers,
|
framebuffers,
|
||||||
expandedFrameProcessors,
|
frameProcessors,
|
||||||
enableExperimentalHdrEditing);
|
enableExperimentalHdrEditing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ImmutableList<GlFrameProcessor> getExpandedFrameProcessors(
|
private static ImmutableList<GlFrameProcessor> getFrameProcessors(
|
||||||
ExternalCopyFrameProcessor externalCopyFrameProcessor,
|
ExternalCopyFrameProcessor externalCopyFrameProcessor,
|
||||||
float pixelWidthHeightRatio,
|
float pixelWidthHeightRatio,
|
||||||
List<GlFrameProcessor> frameProcessors) {
|
List<GlEffect> effects) {
|
||||||
ImmutableList.Builder<GlFrameProcessor> frameProcessorListBuilder =
|
ImmutableList.Builder<GlFrameProcessor> frameProcessors =
|
||||||
new ImmutableList.Builder<GlFrameProcessor>().add(externalCopyFrameProcessor);
|
new ImmutableList.Builder<GlFrameProcessor>().add(externalCopyFrameProcessor);
|
||||||
|
|
||||||
// Scale to expand the frame to apply the pixelWidthHeightRatio.
|
// Scale to expand the frame to apply the pixelWidthHeightRatio.
|
||||||
if (pixelWidthHeightRatio > 1f) {
|
if (pixelWidthHeightRatio > 1f) {
|
||||||
frameProcessorListBuilder.add(
|
frameProcessors.add(
|
||||||
new ScaleToFitFrameProcessor.Builder()
|
new ScaleToFitFrameProcessor.Builder()
|
||||||
.setScale(/* scaleX= */ pixelWidthHeightRatio, /* scaleY= */ 1f)
|
.setScale(/* scaleX= */ pixelWidthHeightRatio, /* scaleY= */ 1f)
|
||||||
.build());
|
.build());
|
||||||
} else if (pixelWidthHeightRatio < 1f) {
|
} else if (pixelWidthHeightRatio < 1f) {
|
||||||
frameProcessorListBuilder.add(
|
frameProcessors.add(
|
||||||
new ScaleToFitFrameProcessor.Builder()
|
new ScaleToFitFrameProcessor.Builder()
|
||||||
.setScale(/* scaleX= */ 1f, /* scaleY= */ 1f / pixelWidthHeightRatio)
|
.setScale(/* scaleX= */ 1f, /* scaleY= */ 1f / pixelWidthHeightRatio)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
frameProcessorListBuilder.addAll(frameProcessors);
|
|
||||||
return frameProcessorListBuilder.build();
|
for (int i = 0; i < effects.size(); i++) {
|
||||||
|
frameProcessors.add(effects.get(i).toGlFrameProcessor());
|
||||||
|
}
|
||||||
|
return frameProcessors.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "FrameProcessorChain";
|
private static final String TAG = "FrameProcessorChain";
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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 androidx.media3.transformer;
|
||||||
|
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a video frame effect with a {@link GlFrameProcessor} implementation.
|
||||||
|
*
|
||||||
|
* <p>Implementations contain information specifying the effect and can be {@linkplain
|
||||||
|
* #toGlFrameProcessor() converted} to a {@link GlFrameProcessor} which applies the effect.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
public interface GlEffect {
|
||||||
|
|
||||||
|
/** Returns a {@link GlFrameProcessor} that applies the the effect. */
|
||||||
|
GlFrameProcessor toGlFrameProcessor();
|
||||||
|
}
|
@ -104,7 +104,7 @@ public final class Transformer {
|
|||||||
private boolean removeVideo;
|
private boolean removeVideo;
|
||||||
private String containerMimeType;
|
private String containerMimeType;
|
||||||
private TransformationRequest transformationRequest;
|
private TransformationRequest transformationRequest;
|
||||||
private ImmutableList<GlFrameProcessor> frameProcessors;
|
private ImmutableList<GlEffect> videoFrameEffects;
|
||||||
private ListenerSet<Transformer.Listener> listeners;
|
private ListenerSet<Transformer.Listener> listeners;
|
||||||
private DebugViewProvider debugViewProvider;
|
private DebugViewProvider debugViewProvider;
|
||||||
private Looper looper;
|
private Looper looper;
|
||||||
@ -124,7 +124,7 @@ public final class Transformer {
|
|||||||
debugViewProvider = DebugViewProvider.NONE;
|
debugViewProvider = DebugViewProvider.NONE;
|
||||||
containerMimeType = MimeTypes.VIDEO_MP4;
|
containerMimeType = MimeTypes.VIDEO_MP4;
|
||||||
transformationRequest = new TransformationRequest.Builder().build();
|
transformationRequest = new TransformationRequest.Builder().build();
|
||||||
frameProcessors = ImmutableList.of();
|
videoFrameEffects = ImmutableList.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,7 +142,7 @@ public final class Transformer {
|
|||||||
debugViewProvider = DebugViewProvider.NONE;
|
debugViewProvider = DebugViewProvider.NONE;
|
||||||
containerMimeType = MimeTypes.VIDEO_MP4;
|
containerMimeType = MimeTypes.VIDEO_MP4;
|
||||||
transformationRequest = new TransformationRequest.Builder().build();
|
transformationRequest = new TransformationRequest.Builder().build();
|
||||||
frameProcessors = ImmutableList.of();
|
videoFrameEffects = ImmutableList.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a builder with the values of the provided {@link Transformer}. */
|
/** Creates a builder with the values of the provided {@link Transformer}. */
|
||||||
@ -154,7 +154,7 @@ public final class Transformer {
|
|||||||
this.removeVideo = transformer.removeVideo;
|
this.removeVideo = transformer.removeVideo;
|
||||||
this.containerMimeType = transformer.containerMimeType;
|
this.containerMimeType = transformer.containerMimeType;
|
||||||
this.transformationRequest = transformer.transformationRequest;
|
this.transformationRequest = transformer.transformationRequest;
|
||||||
this.frameProcessors = transformer.frameProcessors;
|
this.videoFrameEffects = transformer.videoFrameEffects;
|
||||||
this.listeners = transformer.listeners;
|
this.listeners = transformer.listeners;
|
||||||
this.looper = transformer.looper;
|
this.looper = transformer.looper;
|
||||||
this.encoderFactory = transformer.encoderFactory;
|
this.encoderFactory = transformer.encoderFactory;
|
||||||
@ -187,20 +187,20 @@ public final class Transformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@linkplain GlFrameProcessor frame processors} to apply to each frame.
|
* Sets the {@linkplain GlEffect effects} to apply to each video frame.
|
||||||
*
|
*
|
||||||
* <p>The {@linkplain GlFrameProcessor frame processors} are applied before any {@linkplain
|
* <p>The {@linkplain GlEffect effects} are applied before any {@linkplain
|
||||||
* TransformationRequest.Builder#setScale(float, float) scale}, {@linkplain
|
* TransformationRequest.Builder#setScale(float, float) scale}, {@linkplain
|
||||||
* TransformationRequest.Builder#setRotationDegrees(float) rotation}, or {@linkplain
|
* TransformationRequest.Builder#setRotationDegrees(float) rotation}, or {@linkplain
|
||||||
* TransformationRequest.Builder#setResolution(int) resolution} changes specified in the {@link
|
* TransformationRequest.Builder#setResolution(int) resolution} changes specified in the {@link
|
||||||
* #setTransformationRequest(TransformationRequest) TransformationRequest} but after {@linkplain
|
* #setTransformationRequest(TransformationRequest) TransformationRequest} but after {@linkplain
|
||||||
* TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
|
* TransformationRequest.Builder#setFlattenForSlowMotion(boolean) slow-motion flattening}.
|
||||||
*
|
*
|
||||||
* @param frameProcessors The {@linkplain GlFrameProcessor frame processors}.
|
* @param effects The {@linkplain GlEffect effects} to apply to each video frame.
|
||||||
* @return This builder.
|
* @return This builder.
|
||||||
*/
|
*/
|
||||||
public Builder setFrameProcessors(List<GlFrameProcessor> frameProcessors) {
|
public Builder setVideoFrameEffects(List<GlEffect> effects) {
|
||||||
this.frameProcessors = ImmutableList.copyOf(frameProcessors);
|
this.videoFrameEffects = ImmutableList.copyOf(effects);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +432,7 @@ public final class Transformer {
|
|||||||
removeVideo,
|
removeVideo,
|
||||||
containerMimeType,
|
containerMimeType,
|
||||||
transformationRequest,
|
transformationRequest,
|
||||||
frameProcessors,
|
videoFrameEffects,
|
||||||
listeners,
|
listeners,
|
||||||
looper,
|
looper,
|
||||||
clock,
|
clock,
|
||||||
@ -554,7 +554,7 @@ public final class Transformer {
|
|||||||
private final boolean removeVideo;
|
private final boolean removeVideo;
|
||||||
private final String containerMimeType;
|
private final String containerMimeType;
|
||||||
private final TransformationRequest transformationRequest;
|
private final TransformationRequest transformationRequest;
|
||||||
private final ImmutableList<GlFrameProcessor> frameProcessors;
|
private final ImmutableList<GlEffect> videoFrameEffects;
|
||||||
private final Looper looper;
|
private final Looper looper;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Codec.EncoderFactory encoderFactory;
|
private final Codec.EncoderFactory encoderFactory;
|
||||||
@ -575,7 +575,7 @@ public final class Transformer {
|
|||||||
boolean removeVideo,
|
boolean removeVideo,
|
||||||
String containerMimeType,
|
String containerMimeType,
|
||||||
TransformationRequest transformationRequest,
|
TransformationRequest transformationRequest,
|
||||||
ImmutableList<GlFrameProcessor> frameProcessors,
|
ImmutableList<GlEffect> videoFrameEffects,
|
||||||
ListenerSet<Transformer.Listener> listeners,
|
ListenerSet<Transformer.Listener> listeners,
|
||||||
Looper looper,
|
Looper looper,
|
||||||
Clock clock,
|
Clock clock,
|
||||||
@ -590,7 +590,7 @@ public final class Transformer {
|
|||||||
this.removeVideo = removeVideo;
|
this.removeVideo = removeVideo;
|
||||||
this.containerMimeType = containerMimeType;
|
this.containerMimeType = containerMimeType;
|
||||||
this.transformationRequest = transformationRequest;
|
this.transformationRequest = transformationRequest;
|
||||||
this.frameProcessors = frameProcessors;
|
this.videoFrameEffects = videoFrameEffects;
|
||||||
this.listeners = listeners;
|
this.listeners = listeners;
|
||||||
this.looper = looper;
|
this.looper = looper;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
@ -730,7 +730,7 @@ public final class Transformer {
|
|||||||
removeAudio,
|
removeAudio,
|
||||||
removeVideo,
|
removeVideo,
|
||||||
transformationRequest,
|
transformationRequest,
|
||||||
frameProcessors,
|
videoFrameEffects,
|
||||||
encoderFactory,
|
encoderFactory,
|
||||||
decoderFactory,
|
decoderFactory,
|
||||||
new FallbackListener(mediaItem, listeners, transformationRequest),
|
new FallbackListener(mediaItem, listeners, transformationRequest),
|
||||||
@ -842,7 +842,7 @@ public final class Transformer {
|
|||||||
private final boolean removeAudio;
|
private final boolean removeAudio;
|
||||||
private final boolean removeVideo;
|
private final boolean removeVideo;
|
||||||
private final TransformationRequest transformationRequest;
|
private final TransformationRequest transformationRequest;
|
||||||
private final ImmutableList<GlFrameProcessor> frameProcessors;
|
private final ImmutableList<GlEffect> videoFrameEffects;
|
||||||
private final Codec.EncoderFactory encoderFactory;
|
private final Codec.EncoderFactory encoderFactory;
|
||||||
private final Codec.DecoderFactory decoderFactory;
|
private final Codec.DecoderFactory decoderFactory;
|
||||||
private final FallbackListener fallbackListener;
|
private final FallbackListener fallbackListener;
|
||||||
@ -854,7 +854,7 @@ public final class Transformer {
|
|||||||
boolean removeAudio,
|
boolean removeAudio,
|
||||||
boolean removeVideo,
|
boolean removeVideo,
|
||||||
TransformationRequest transformationRequest,
|
TransformationRequest transformationRequest,
|
||||||
ImmutableList<GlFrameProcessor> frameProcessors,
|
ImmutableList<GlEffect> videoFrameEffects,
|
||||||
Codec.EncoderFactory encoderFactory,
|
Codec.EncoderFactory encoderFactory,
|
||||||
Codec.DecoderFactory decoderFactory,
|
Codec.DecoderFactory decoderFactory,
|
||||||
FallbackListener fallbackListener,
|
FallbackListener fallbackListener,
|
||||||
@ -864,7 +864,7 @@ public final class Transformer {
|
|||||||
this.removeAudio = removeAudio;
|
this.removeAudio = removeAudio;
|
||||||
this.removeVideo = removeVideo;
|
this.removeVideo = removeVideo;
|
||||||
this.transformationRequest = transformationRequest;
|
this.transformationRequest = transformationRequest;
|
||||||
this.frameProcessors = frameProcessors;
|
this.videoFrameEffects = videoFrameEffects;
|
||||||
this.encoderFactory = encoderFactory;
|
this.encoderFactory = encoderFactory;
|
||||||
this.decoderFactory = decoderFactory;
|
this.decoderFactory = decoderFactory;
|
||||||
this.fallbackListener = fallbackListener;
|
this.fallbackListener = fallbackListener;
|
||||||
@ -900,7 +900,7 @@ public final class Transformer {
|
|||||||
muxerWrapper,
|
muxerWrapper,
|
||||||
mediaClock,
|
mediaClock,
|
||||||
transformationRequest,
|
transformationRequest,
|
||||||
frameProcessors,
|
videoFrameEffects,
|
||||||
encoderFactory,
|
encoderFactory,
|
||||||
decoderFactory,
|
decoderFactory,
|
||||||
fallbackListener,
|
fallbackListener,
|
||||||
|
@ -35,7 +35,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
private static final String TAG = "TVideoRenderer";
|
private static final String TAG = "TVideoRenderer";
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final ImmutableList<GlFrameProcessor> frameProcessors;
|
private final ImmutableList<GlEffect> effects;
|
||||||
private final Codec.EncoderFactory encoderFactory;
|
private final Codec.EncoderFactory encoderFactory;
|
||||||
private final Codec.DecoderFactory decoderFactory;
|
private final Codec.DecoderFactory decoderFactory;
|
||||||
private final Transformer.DebugViewProvider debugViewProvider;
|
private final Transformer.DebugViewProvider debugViewProvider;
|
||||||
@ -48,14 +48,14 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
MuxerWrapper muxerWrapper,
|
MuxerWrapper muxerWrapper,
|
||||||
TransformerMediaClock mediaClock,
|
TransformerMediaClock mediaClock,
|
||||||
TransformationRequest transformationRequest,
|
TransformationRequest transformationRequest,
|
||||||
ImmutableList<GlFrameProcessor> frameProcessors,
|
ImmutableList<GlEffect> effects,
|
||||||
Codec.EncoderFactory encoderFactory,
|
Codec.EncoderFactory encoderFactory,
|
||||||
Codec.DecoderFactory decoderFactory,
|
Codec.DecoderFactory decoderFactory,
|
||||||
FallbackListener fallbackListener,
|
FallbackListener fallbackListener,
|
||||||
Transformer.DebugViewProvider debugViewProvider) {
|
Transformer.DebugViewProvider debugViewProvider) {
|
||||||
super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest, fallbackListener);
|
super(C.TRACK_TYPE_VIDEO, muxerWrapper, mediaClock, transformationRequest, fallbackListener);
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.frameProcessors = frameProcessors;
|
this.effects = effects;
|
||||||
this.encoderFactory = encoderFactory;
|
this.encoderFactory = encoderFactory;
|
||||||
this.decoderFactory = decoderFactory;
|
this.decoderFactory = decoderFactory;
|
||||||
this.debugViewProvider = debugViewProvider;
|
this.debugViewProvider = debugViewProvider;
|
||||||
@ -90,7 +90,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
context,
|
context,
|
||||||
inputFormat,
|
inputFormat,
|
||||||
transformationRequest,
|
transformationRequest,
|
||||||
frameProcessors,
|
effects,
|
||||||
decoderFactory,
|
decoderFactory,
|
||||||
encoderFactory,
|
encoderFactory,
|
||||||
muxerWrapper.getSupportedSampleMimeTypes(getTrackType()),
|
muxerWrapper.getSupportedSampleMimeTypes(getTrackType()),
|
||||||
@ -137,7 +137,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
&& transformationRequest.outputHeight != inputFormat.height) {
|
&& transformationRequest.outputHeight != inputFormat.height) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!frameProcessors.isEmpty()) {
|
if (!effects.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -50,7 +50,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
Context context,
|
Context context,
|
||||||
Format inputFormat,
|
Format inputFormat,
|
||||||
TransformationRequest transformationRequest,
|
TransformationRequest transformationRequest,
|
||||||
ImmutableList<GlFrameProcessor> frameProcessors,
|
ImmutableList<GlEffect> effects,
|
||||||
Codec.DecoderFactory decoderFactory,
|
Codec.DecoderFactory decoderFactory,
|
||||||
Codec.EncoderFactory encoderFactory,
|
Codec.EncoderFactory encoderFactory,
|
||||||
List<String> allowedOutputMimeTypes,
|
List<String> allowedOutputMimeTypes,
|
||||||
@ -68,33 +68,35 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
int decodedHeight =
|
int decodedHeight =
|
||||||
(inputFormat.rotationDegrees % 180 == 0) ? inputFormat.height : inputFormat.width;
|
(inputFormat.rotationDegrees % 180 == 0) ? inputFormat.height : inputFormat.width;
|
||||||
|
|
||||||
ImmutableList.Builder<GlFrameProcessor> frameProcessorsListBuilder =
|
ImmutableList.Builder<GlEffect> effectsListBuilder =
|
||||||
new ImmutableList.Builder<GlFrameProcessor>().addAll(frameProcessors);
|
new ImmutableList.Builder<GlEffect>().addAll(effects);
|
||||||
if (transformationRequest.scaleX != 1f
|
if (transformationRequest.scaleX != 1f
|
||||||
|| transformationRequest.scaleY != 1f
|
|| transformationRequest.scaleY != 1f
|
||||||
|| transformationRequest.rotationDegrees != 0f) {
|
|| transformationRequest.rotationDegrees != 0f) {
|
||||||
frameProcessorsListBuilder.add(
|
effectsListBuilder.add(
|
||||||
|
() ->
|
||||||
new ScaleToFitFrameProcessor.Builder()
|
new ScaleToFitFrameProcessor.Builder()
|
||||||
.setScale(transformationRequest.scaleX, transformationRequest.scaleY)
|
.setScale(transformationRequest.scaleX, transformationRequest.scaleY)
|
||||||
.setRotationDegrees(transformationRequest.rotationDegrees)
|
.setRotationDegrees(transformationRequest.rotationDegrees)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
if (transformationRequest.outputHeight != C.LENGTH_UNSET) {
|
if (transformationRequest.outputHeight != C.LENGTH_UNSET) {
|
||||||
frameProcessorsListBuilder.add(
|
effectsListBuilder.add(
|
||||||
|
() ->
|
||||||
new PresentationFrameProcessor.Builder()
|
new PresentationFrameProcessor.Builder()
|
||||||
.setResolution(transformationRequest.outputHeight)
|
.setResolution(transformationRequest.outputHeight)
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
EncoderCompatibilityFrameProcessor encoderCompatibilityFrameProcessor =
|
EncoderCompatibilityFrameProcessor encoderCompatibilityFrameProcessor =
|
||||||
new EncoderCompatibilityFrameProcessor();
|
new EncoderCompatibilityFrameProcessor();
|
||||||
frameProcessorsListBuilder.add(encoderCompatibilityFrameProcessor);
|
effectsListBuilder.add(() -> encoderCompatibilityFrameProcessor);
|
||||||
frameProcessorChain =
|
frameProcessorChain =
|
||||||
FrameProcessorChain.create(
|
FrameProcessorChain.create(
|
||||||
context,
|
context,
|
||||||
inputFormat.pixelWidthHeightRatio,
|
inputFormat.pixelWidthHeightRatio,
|
||||||
/* inputWidth= */ decodedWidth,
|
/* inputWidth= */ decodedWidth,
|
||||||
/* inputHeight= */ decodedHeight,
|
/* inputHeight= */ decodedHeight,
|
||||||
frameProcessorsListBuilder.build(),
|
effectsListBuilder.build(),
|
||||||
transformationRequest.enableHdrEditing);
|
transformationRequest.enableHdrEditing);
|
||||||
Size requestedEncoderSize = frameProcessorChain.getOutputSize();
|
Size requestedEncoderSize = frameProcessorChain.getOutputSize();
|
||||||
outputRotationDegrees = encoderCompatibilityFrameProcessor.getOutputRotationDegrees();
|
outputRotationDegrees = encoderCompatibilityFrameProcessor.getOutputRotationDegrees();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user