Create a new MetricsReporter.Factory

This includes creating a new Factory for `MetricsReporter` and adding it to Transformer. This is done as we need to create a new `MetricsReporter` for each export operation, so it makes sense to have a Factory.

PiperOrigin-RevId: 727798528
(cherry picked from commit 6d408c2d31bddacb254bb0cc917e4ecd5d0e4b66)
This commit is contained in:
shahddaghash 2025-02-17 03:33:05 -08:00 committed by oceanjules
parent bb358241b9
commit e58d9120bc
2 changed files with 78 additions and 13 deletions

View File

@ -16,6 +16,7 @@
package androidx.media3.transformer; package androidx.media3.transformer;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.usToMs; import static androidx.media3.common.util.Util.usToMs;
import android.content.Context; import android.content.Context;
@ -32,6 +33,7 @@ import androidx.media3.common.C;
import androidx.media3.common.ColorInfo; import androidx.media3.common.ColorInfo;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.SystemClock; import androidx.media3.common.util.SystemClock;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
@ -45,6 +47,11 @@ import java.util.List;
/** Reports the collected metrics. */ /** Reports the collected metrics. */
public interface MetricsReporter extends AutoCloseable { public interface MetricsReporter extends AutoCloseable {
/** Factory for metrics reporters */
interface Factory {
/** Returns a new {@link MetricsReporter}. */
MetricsReporter create();
}
/** /**
* Reports the given {@link EditingEndedEvent}. * Reports the given {@link EditingEndedEvent}.
@ -59,16 +66,31 @@ import java.util.List;
* EditingSession}. * EditingSession}.
*/ */
static final class DefaultMetricsReporter implements MetricsReporter { static final class DefaultMetricsReporter implements MetricsReporter {
/** A {@link MetricsReporter.Factory} for {@link DefaultMetricsReporter}. */
/** The {@link EditingSession} to report collected metrics to. */ public static final class Factory implements MetricsReporter.Factory {
@Nullable private EditingSession editingSession; private final Context context;
/** /**
* Creates an instance. * Creates an instance.
* *
* @param context A {@link Context}. * @param context The {@link Context}.
*/ */
public DefaultMetricsReporter(Context context) { public Factory(Context context) {
this.context = context;
}
@Override
public MetricsReporter create() {
return new DefaultMetricsReporter(context);
}
}
/** The {@link EditingSession} to report collected metrics to. */
@Nullable private EditingSession editingSession;
private boolean metricsReported;
private DefaultMetricsReporter(Context context) {
@Nullable @Nullable
MediaMetricsManager mediaMetricsManager = MediaMetricsManager mediaMetricsManager =
(MediaMetricsManager) context.getSystemService(Context.MEDIA_METRICS_SERVICE); (MediaMetricsManager) context.getSystemService(Context.MEDIA_METRICS_SERVICE);
@ -79,9 +101,10 @@ import java.util.List;
@Override @Override
public void reportMetrics(EditingEndedEvent editingEndedEvent) { public void reportMetrics(EditingEndedEvent editingEndedEvent) {
checkState(!metricsReported, "Metrics have already been reported.");
if (editingSession != null) { if (editingSession != null) {
editingSession.reportEditingEndedEvent(editingEndedEvent); editingSession.reportEditingEndedEvent(editingEndedEvent);
close(); metricsReported = true;
} }
} }
@ -94,6 +117,7 @@ import java.util.List;
} }
} }
private static final String TAG = "EditingMetricsCollector";
// TODO: b/386328723 - Add missing error codes to EditingEndedEvent.ErrorCode. // TODO: b/386328723 - Add missing error codes to EditingEndedEvent.ErrorCode.
private static final SparseIntArray ERROR_CODE_CONVERSION_MAP = new SparseIntArray(); private static final SparseIntArray ERROR_CODE_CONVERSION_MAP = new SparseIntArray();
private static final SparseIntArray DATA_SPACE_STANDARD_CONVERSION_MAP = new SparseIntArray(); private static final SparseIntArray DATA_SPACE_STANDARD_CONVERSION_MAP = new SparseIntArray();
@ -222,6 +246,11 @@ import java.util.List;
editingEndedEventBuilder.setOutputMediaItemInfo(getOutputMediaItemInfo(exportResult)); editingEndedEventBuilder.setOutputMediaItemInfo(getOutputMediaItemInfo(exportResult));
metricsReporter.reportMetrics(editingEndedEventBuilder.build()); metricsReporter.reportMetrics(editingEndedEventBuilder.build());
try {
metricsReporter.close();
} catch (Exception e) {
Log.e(TAG, "error while closing the metrics reporter", e);
}
} }
/** /**
@ -250,6 +279,11 @@ import java.util.List;
editingEndedEventBuilder.setOutputMediaItemInfo(getOutputMediaItemInfo(exportResult)); editingEndedEventBuilder.setOutputMediaItemInfo(getOutputMediaItemInfo(exportResult));
metricsReporter.reportMetrics(editingEndedEventBuilder.build()); metricsReporter.reportMetrics(editingEndedEventBuilder.build());
try {
metricsReporter.close();
} catch (Exception e) {
Log.e(TAG, "error while closing the metrics reporter", e);
}
} }
/** /**
@ -266,6 +300,11 @@ import java.util.List;
} }
metricsReporter.reportMetrics(editingEndedEventBuilder.build()); metricsReporter.reportMetrics(editingEndedEventBuilder.build());
try {
metricsReporter.close();
} catch (Exception e) {
Log.e(TAG, "error while closing the metrics reporter", e);
}
} }
private EditingEndedEvent.Builder createEditingEndedEventBuilder(int finalState) { private EditingEndedEvent.Builder createEditingEndedEventBuilder(int finalState) {

View File

@ -122,6 +122,8 @@ public final class Transformer {
private Looper looper; private Looper looper;
private DebugViewProvider debugViewProvider; private DebugViewProvider debugViewProvider;
private Clock clock; private Clock clock;
private EditingMetricsCollector.MetricsReporter.@MonotonicNonNull Factory
metricsReporterFactory;
/** /**
* Creates a builder with default values. * Creates a builder with default values.
@ -142,6 +144,10 @@ public final class Transformer {
debugViewProvider = DebugViewProvider.NONE; debugViewProvider = DebugViewProvider.NONE;
clock = Clock.DEFAULT; clock = Clock.DEFAULT;
listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {}); listeners = new ListenerSet<>(looper, clock, (listener, flags) -> {});
if (SDK_INT >= 35) {
metricsReporterFactory =
new EditingMetricsCollector.DefaultMetricsReporter.Factory(context);
}
} }
/** Creates a builder with the values of the provided {@link Transformer}. */ /** Creates a builder with the values of the provided {@link Transformer}. */
@ -169,6 +175,7 @@ public final class Transformer {
this.looper = transformer.looper; this.looper = transformer.looper;
this.debugViewProvider = transformer.debugViewProvider; this.debugViewProvider = transformer.debugViewProvider;
this.clock = transformer.clock; this.clock = transformer.clock;
this.metricsReporterFactory = transformer.metricsReporterFactory;
} }
/** /**
@ -515,6 +522,23 @@ public final class Transformer {
return this; return this;
} }
/**
* Sets the {@link EditingMetricsCollector.MetricsReporter.Factory} that will be used to report
* the metrics.
*
* <p>The default value is {@link EditingMetricsCollector.DefaultMetricsReporter.Factory}.
*
* @param metricsReporterFactory A {@link EditingMetricsCollector.MetricsReporter.Factory}.
* @return This builder.
*/
@CanIgnoreReturnValue
@VisibleForTesting
/* package */ Builder setMetricsReporterFactory(
EditingMetricsCollector.MetricsReporter.Factory metricsReporterFactory) {
this.metricsReporterFactory = metricsReporterFactory;
return this;
}
/** /**
* Sets whether transformer reports diagnostics data to the Android platform. * Sets whether transformer reports diagnostics data to the Android platform.
* *
@ -582,7 +606,8 @@ public final class Transformer {
muxerFactory, muxerFactory,
looper, looper,
debugViewProvider, debugViewProvider,
clock); clock,
metricsReporterFactory);
} }
private void checkSampleMimeType(String sampleMimeType) { private void checkSampleMimeType(String sampleMimeType) {
@ -772,7 +797,7 @@ public final class Transformer {
private final HandlerWrapper applicationHandler; private final HandlerWrapper applicationHandler;
private final ComponentListener componentListener; private final ComponentListener componentListener;
private final ExportResult.Builder exportResultBuilder; private final ExportResult.Builder exportResultBuilder;
private @MonotonicNonNull EditingMetricsCollector editingMetricsCollector; @Nullable private final EditingMetricsCollector.MetricsReporter.Factory metricsReporterFactory;
@Nullable private TransformerInternal transformerInternal; @Nullable private TransformerInternal transformerInternal;
@Nullable private MuxerWrapper remuxingMuxerWrapper; @Nullable private MuxerWrapper remuxingMuxerWrapper;
@ -783,6 +808,7 @@ public final class Transformer {
private TransmuxTranscodeHelper.@MonotonicNonNull ResumeMetadata resumeMetadata; private TransmuxTranscodeHelper.@MonotonicNonNull ResumeMetadata resumeMetadata;
private @MonotonicNonNull ListenableFuture<TransmuxTranscodeHelper.ResumeMetadata> private @MonotonicNonNull ListenableFuture<TransmuxTranscodeHelper.ResumeMetadata>
getResumeMetadataFuture; getResumeMetadataFuture;
private @MonotonicNonNull EditingMetricsCollector editingMetricsCollector;
private @MonotonicNonNull ListenableFuture<Void> copyOutputFuture; private @MonotonicNonNull ListenableFuture<Void> copyOutputFuture;
@Nullable private Mp4Info mediaItemInfo; @Nullable private Mp4Info mediaItemInfo;
@Nullable private WatchdogTimer exportWatchdogTimer; @Nullable private WatchdogTimer exportWatchdogTimer;
@ -808,7 +834,8 @@ public final class Transformer {
Muxer.Factory muxerFactory, Muxer.Factory muxerFactory,
Looper looper, Looper looper,
DebugViewProvider debugViewProvider, DebugViewProvider debugViewProvider,
Clock clock) { Clock clock,
@Nullable EditingMetricsCollector.MetricsReporter.Factory metricsReporterFactory) {
checkState(!removeAudio || !removeVideo, "Audio and video cannot both be removed."); checkState(!removeAudio || !removeVideo, "Audio and video cannot both be removed.");
this.context = context; this.context = context;
this.transformationRequest = transformationRequest; this.transformationRequest = transformationRequest;
@ -831,6 +858,7 @@ public final class Transformer {
this.looper = looper; this.looper = looper;
this.debugViewProvider = debugViewProvider; this.debugViewProvider = debugViewProvider;
this.clock = clock; this.clock = clock;
this.metricsReporterFactory = metricsReporterFactory;
transformerState = TRANSFORMER_STATE_PROCESS_FULL_INPUT; transformerState = TRANSFORMER_STATE_PROCESS_FULL_INPUT;
applicationHandler = clock.createHandler(looper, /* callback= */ null); applicationHandler = clock.createHandler(looper, /* callback= */ null);
componentListener = new ComponentListener(); componentListener = new ComponentListener();
@ -1590,9 +1618,7 @@ public final class Transformer {
} }
editingMetricsCollector = editingMetricsCollector =
new EditingMetricsCollector( new EditingMetricsCollector(
new EditingMetricsCollector.DefaultMetricsReporter(context), checkNotNull(metricsReporterFactory).create(), EXPORTER_NAME, muxerName);
EXPORTER_NAME,
muxerName);
} }
transformerInternal = transformerInternal =
new TransformerInternal( new TransformerInternal(