Skip to content

Commit 5e7a210

Browse files
author
Aman Choudhary
committed
Added Kotlin and Java snippets for Media3 Inspector module
1 parent aea6b59 commit 5e7a210

File tree

4 files changed

+235
-2
lines changed

4 files changed

+235
-2
lines changed

gradle/libs.versions.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ maps-compose = "6.12.2"
6767
material = "1.14.0-alpha07"
6868
material3-adaptive = "1.2.0"
6969
material3-adaptive-navigation-suite = "1.4.0"
70-
media3 = "1.8.0"
71-
media3Ui = "1.8.0"
70+
media3 = "1.9.0-alpha01"
71+
media3Ui = "1.9.0-alpha01"
7272
# @keep
7373
minSdk = "36"
7474
okHttp = "5.3.2"
@@ -163,6 +163,7 @@ androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-view
163163
androidx-material-icons-core = { module = "androidx.compose.material:material-icons-core" }
164164
androidx-media3-common = { module = "androidx.media3:media3-common", version.ref = "media3" }
165165
androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3" }
166+
androidx-media3-inspector = { module = "androidx.media3:media3-inspector", version.ref = "media3" }
166167
androidx-media3-ui = { module = "androidx.media3:media3-ui", version.ref = "media3Ui" }
167168
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }
168169
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "androidx-navigation3" }

misc/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,13 @@ dependencies {
6060
implementation(libs.androidx.compose.material3)
6161
implementation(libs.androidx.media3.common)
6262
implementation(libs.androidx.media3.exoplayer)
63+
implementation(libs.androidx.media3.inspector)
6364
implementation(libs.androidx.tracing)
6465

6566
implementation(libs.hilt.android)
6667
implementation(libs.androidx.hilt.navigation.compose)
6768
implementation(libs.kotlinx.serialization.json)
69+
implementation(libs.kotlinx.coroutines.guava)
6870
ksp(libs.hilt.compiler)
6971

7072
implementation(libs.androidx.constraintlayout)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.example.snippets;
2+
3+
import android.content.Context;
4+
import android.media.MediaFormat;
5+
import android.util.Log;
6+
7+
import androidx.annotation.NonNull;
8+
import androidx.annotation.OptIn;
9+
import androidx.media3.common.MediaItem;
10+
import androidx.media3.common.Timeline;
11+
import androidx.media3.common.util.UnstableApi;
12+
import androidx.media3.exoplayer.MediaExtractorCompat;
13+
import androidx.media3.exoplayer.source.TrackGroupArray;
14+
import androidx.media3.inspector.FrameExtractor;
15+
import androidx.media3.inspector.MetadataRetriever;
16+
17+
import com.google.common.util.concurrent.FutureCallback;
18+
import com.google.common.util.concurrent.Futures;
19+
import com.google.common.util.concurrent.ListenableFuture;
20+
21+
import java.io.IOException;
22+
import java.nio.ByteBuffer;
23+
import java.util.List;
24+
import java.util.concurrent.Executor;
25+
import java.util.concurrent.Executors;
26+
27+
import kotlin.Suppress;
28+
29+
@Suppress(names = "unused_parameter")
30+
@OptIn(markerClass = UnstableApi.class)
31+
public class InspectorModuleJavaSnippets {
32+
private final String TAG = "InspectorModuleLog";
33+
34+
// [START android_media3_inspector_MetadataRetriever_java]
35+
public void retrieveMetadata(Context context, MediaItem mediaItem) {
36+
try (MetadataRetriever metadataRetriever = new MetadataRetriever.Builder(context, mediaItem).build()) {
37+
ListenableFuture<TrackGroupArray> trackGroupsFuture = metadataRetriever.retrieveTrackGroups();
38+
ListenableFuture<Timeline> timelineFuture = metadataRetriever.retrieveTimeline();
39+
ListenableFuture<Long> durationUsFuture = metadataRetriever.retrieveDurationUs();
40+
41+
ListenableFuture<List<Object>> allFutures = Futures.allAsList(trackGroupsFuture, timelineFuture, durationUsFuture);
42+
Executor executor = Executors.newSingleThreadExecutor();
43+
Futures.addCallback(allFutures, new FutureCallback<>() {
44+
@Override
45+
public void onSuccess(List<Object> result) {
46+
handleMetadata(
47+
Futures.getUnchecked(trackGroupsFuture),
48+
Futures.getUnchecked(timelineFuture),
49+
Futures.getUnchecked(durationUsFuture));
50+
}
51+
52+
@Override
53+
public void onFailure(@NonNull Throwable t) {
54+
handleFailure(t);
55+
}
56+
}, executor);
57+
}
58+
}
59+
// [END android_media3_inspector_MetadataRetriever_java]
60+
61+
// [START android_media3_inspector_FrameExtractor_java]
62+
public void extractFrame(Context context, MediaItem mediaItem) {
63+
try (FrameExtractor frameExtractor = new FrameExtractor.Builder(context, mediaItem).build()) {
64+
ListenableFuture<FrameExtractor.Frame> frameFuture = frameExtractor.getFrame(5000L);
65+
66+
Executor executor = Executors.newSingleThreadExecutor();
67+
Futures.addCallback(frameFuture, new FutureCallback<Object>() {
68+
@OptIn(markerClass = UnstableApi.class)
69+
@Override
70+
public void onSuccess(Object result) {
71+
long presentationTimeMs = Futures.getUnchecked(frameFuture).presentationTimeMs;
72+
Log.d(TAG, "Extracted frame at " + presentationTimeMs);
73+
}
74+
75+
@Override
76+
public void onFailure(@NonNull Throwable t) {
77+
handleFailure(t);
78+
}
79+
}, executor);
80+
}
81+
}
82+
// [END android_media3_inspector_FrameExtractor_java]
83+
84+
// [START android_media3_inspector_MediaExtractorCompat_java]
85+
public void extractSamples(Context context, String mediaPath) {
86+
MediaExtractorCompat extractor = new MediaExtractorCompat(context);
87+
try {
88+
// 1. Setup the extractor
89+
extractor.setDataSource(mediaPath);
90+
91+
// Find and select available tracks
92+
for (int i = 0; i < extractor.getTrackCount(); i++) {
93+
MediaFormat format = extractor.getTrackFormat(i);
94+
extractor.selectTrack(i);
95+
}
96+
97+
// 2. Process samples
98+
ByteBuffer buffer = ByteBuffer.allocate(10 * 1024 * 1024);
99+
while (true) {
100+
// Read an encoded sample into the buffer.
101+
int bytesRead = extractor.readSampleData(buffer, 0);
102+
if (bytesRead < 0) break;
103+
104+
// Access sample metadata
105+
int trackIndex = extractor.getSampleTrackIndex();
106+
Long presentationTimeUs = extractor.getSampleTime();
107+
Long sampleSize = extractor.getSampleSize();
108+
109+
extractor.advance();
110+
}
111+
} catch (IOException e) {
112+
throw new RuntimeException(e);
113+
} finally {
114+
extractor.release(); // 3. Release the extractor
115+
}
116+
}
117+
// [END android_media3_inspector_MediaExtractorCompat_java]
118+
119+
private void handleMetadata(TrackGroupArray trackGroups, Timeline timeline, Long durationUs) {
120+
Log.d(TAG, "TrackGroups: " + trackGroups);
121+
Log.d(TAG, "Timeline: " + timeline);
122+
Log.d(TAG, "Duration: " + durationUs);
123+
}
124+
125+
private void handleFailure(@NonNull Throwable t) {
126+
Log.e(TAG, "Error retrieving metadata: " + t.getMessage());
127+
}
128+
129+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.example.snippets
2+
3+
import android.content.Context
4+
import android.graphics.Bitmap
5+
import android.util.Log
6+
import androidx.annotation.OptIn
7+
import androidx.media3.common.MediaItem
8+
import androidx.media3.common.Timeline
9+
import androidx.media3.common.util.UnstableApi
10+
import androidx.media3.exoplayer.MediaExtractorCompat
11+
import androidx.media3.exoplayer.source.TrackGroupArray
12+
import androidx.media3.inspector.FrameExtractor
13+
import androidx.media3.inspector.MetadataRetriever
14+
import kotlinx.coroutines.guava.await
15+
import java.io.IOException
16+
import java.nio.ByteBuffer
17+
18+
const val TAG = "InspectorModuleLog"
19+
20+
@Suppress("unused_parameter")
21+
@OptIn(UnstableApi::class)
22+
class InspectorModuleKotlinSnippets {
23+
24+
// [START android_media3_inspector_MetadataRetriever_kotlin]
25+
suspend fun retrieveMetadata(context: Context, mediaItem: MediaItem) {
26+
try {
27+
// 1. Build the retriever and open a .use block.
28+
// This automatically calls close() when the block finishes.
29+
MetadataRetriever.Builder(context, mediaItem).build().use { retriever ->
30+
// 2. Retrieve metadata asynchronously.
31+
val trackGroups = retriever.retrieveTrackGroups().await()
32+
val timeline = retriever.retrieveTimeline().await()
33+
val durationUs = retriever.retrieveDurationUs().await()
34+
handleMetadata(trackGroups, timeline, durationUs)
35+
}
36+
} catch (e: Exception) {
37+
throw RuntimeException(e)
38+
}
39+
}
40+
// [END android_media3_inspector_MetadataRetriever_kotlin]
41+
42+
// [START android_media3_inspector_FrameExtractor_kotlin]
43+
suspend fun extractFrame(context: Context, mediaItem: MediaItem): Bitmap? {
44+
return try {
45+
// 1. Build the extractor and open a .use block.
46+
// This automatically calls close() when the block finishes.
47+
FrameExtractor.Builder(context, mediaItem).build().use { extractor ->
48+
// 2. Extract the specific frame at the 5000ms (5-second) mark
49+
val frame = extractor.getFrame(5000L).await()
50+
Log.d(TAG, "Extracted frame at ${frame.presentationTimeMs} ms")
51+
frame.bitmap
52+
}
53+
} catch (e: Exception) {
54+
Log.e(TAG, "Exception: $e")
55+
null
56+
}
57+
}
58+
// [END android_media3_inspector_FrameExtractor_kotlin]
59+
60+
// [START android_media3_inspector_MediaExtractorCompat_kotlin]
61+
fun extractSamples(context: Context, mediaPath: String){
62+
val extractor = MediaExtractorCompat(context)
63+
try {
64+
// 1. Setup the extractor
65+
extractor.setDataSource(mediaPath)
66+
67+
// Find and select available tracks
68+
for (i in 0 until extractor.trackCount) {
69+
val format = extractor.getTrackFormat(i)
70+
extractor.selectTrack(i)
71+
}
72+
73+
// 2. Process samples
74+
val buffer = ByteBuffer.allocate(10 * 1024 * 1024)
75+
while (true) {
76+
// Read an encoded sample into the buffer.
77+
val bytesRead = extractor.readSampleData(buffer, 0)
78+
if (bytesRead < 0) break
79+
80+
// Access sample metadata
81+
val trackIndex = extractor.sampleTrackIndex
82+
val presentationTimeUs: Long = extractor.sampleTime
83+
val sampleSize: Long = extractor.sampleSize
84+
85+
extractor.advance()
86+
}
87+
} catch (e: IOException) {
88+
throw RuntimeException(e)
89+
} finally {
90+
extractor.release() // 3. Release the extractor
91+
}
92+
}
93+
// [END android_media3_inspector_MediaExtractorCompat_kotlin]
94+
95+
private fun handleMetadata(trackGroups: TrackGroupArray, timeline: Timeline, durationUs: Long) {
96+
Log.d(TAG, "TrackGroups: $trackGroups us")
97+
Log.d(TAG, "Timeline: $timeline us")
98+
Log.d(TAG, "Duration: $durationUs us")
99+
}
100+
101+
}

0 commit comments

Comments
 (0)