mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add MediaMetadata
to playback test dump files
This change also adds some runtime redirection of calls to `Dumper.add(String, Object)` to `add(String, byte[])` if `value instanceof byte[]`. This simplifies the implementation of `PlaybackOutput.dumpIfNotEqual` and seems like a reasonable amound of 'magic' for a test utility. Issue: androidx/media#1305 PiperOrigin-RevId: 628119473
This commit is contained in:
parent
5ee6c9b16d
commit
acb3a54dee
@ -343,3 +343,10 @@ AudioSink:
|
|||||||
buffer #32:
|
buffer #32:
|
||||||
time = 1000002730666
|
time = 1000002730666
|
||||||
data = 1
|
data = 1
|
||||||
|
Listener.onMediaMetadata:
|
||||||
|
MediaMetadata[0]:
|
||||||
|
title = 那么爱你为什么
|
||||||
|
artist = 阿强
|
||||||
|
albumTitle = 华丽的外衣
|
||||||
|
artworkData = length 46215, hash 948F5BED
|
||||||
|
artworkDataType = front cover
|
||||||
|
@ -343,3 +343,7 @@ AudioSink:
|
|||||||
buffer #32:
|
buffer #32:
|
||||||
time = 1000002730666
|
time = 1000002730666
|
||||||
data = 1
|
data = 1
|
||||||
|
Listener.onMediaMetadata:
|
||||||
|
MediaMetadata[0]:
|
||||||
|
artworkData = length 30943, hash CE3D27AF
|
||||||
|
artworkDataType = front cover
|
||||||
|
@ -343,3 +343,7 @@ AudioSink:
|
|||||||
buffer #32:
|
buffer #32:
|
||||||
time = 1000002730666
|
time = 1000002730666
|
||||||
data = 1
|
data = 1
|
||||||
|
Listener.onMediaMetadata:
|
||||||
|
MediaMetadata[0]:
|
||||||
|
title = test title
|
||||||
|
artist = test artist
|
||||||
|
@ -1183,3 +1183,10 @@ AudioSink:
|
|||||||
buffer #116:
|
buffer #116:
|
||||||
time = 1000002784000
|
time = 1000002784000
|
||||||
data = 1
|
data = 1
|
||||||
|
Listener.onMediaMetadata:
|
||||||
|
MediaMetadata[0]:
|
||||||
|
title = Test title
|
||||||
|
artist = Test Artist
|
||||||
|
albumTitle = Test Album
|
||||||
|
artworkData = length 38946, hash 87684827
|
||||||
|
artworkDataType = other
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1461,3 +1461,7 @@ MetadataOutput:
|
|||||||
presentationTimeUs = 23219
|
presentationTimeUs = 23219
|
||||||
entry[0] = COMM: language=eng, description=description
|
entry[0] = COMM: language=eng, description=description
|
||||||
entry[1] = APIC: mimeType=image/jpeg, description=Hello World
|
entry[1] = APIC: mimeType=image/jpeg, description=Hello World
|
||||||
|
Listener.onMediaMetadata:
|
||||||
|
MediaMetadata[0]:
|
||||||
|
artworkData = length 10, hash C5D38B5C
|
||||||
|
artworkDataType = video capture
|
||||||
|
@ -51,6 +51,9 @@ public final class Dumper {
|
|||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public Dumper add(String field, @Nullable Object value) {
|
public Dumper add(String field, @Nullable Object value) {
|
||||||
checkNotNull(value);
|
checkNotNull(value);
|
||||||
|
if (value instanceof byte[]) {
|
||||||
|
return add(field, (byte[]) value);
|
||||||
|
}
|
||||||
String[] lines = Util.split(value.toString(), "\n");
|
String[] lines = Util.split(value.toString(), "\n");
|
||||||
addLine(field + " = " + lines[0]);
|
addLine(field + " = " + lines[0]);
|
||||||
int fieldValueAdditionalIndent = field.length() + 3;
|
int fieldValueAdditionalIndent = field.length() + 3;
|
||||||
|
@ -19,8 +19,16 @@ import static java.lang.Math.max;
|
|||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.media3.common.HeartRating;
|
||||||
|
import androidx.media3.common.MediaMetadata;
|
||||||
|
import androidx.media3.common.MediaMetadata.MediaType;
|
||||||
|
import androidx.media3.common.MediaMetadata.PictureType;
|
||||||
import androidx.media3.common.Metadata;
|
import androidx.media3.common.Metadata;
|
||||||
|
import androidx.media3.common.PercentageRating;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
|
import androidx.media3.common.Rating;
|
||||||
|
import androidx.media3.common.StarRating;
|
||||||
|
import androidx.media3.common.ThumbRating;
|
||||||
import androidx.media3.common.text.Cue;
|
import androidx.media3.common.text.Cue;
|
||||||
import androidx.media3.common.text.CueGroup;
|
import androidx.media3.common.text.CueGroup;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
@ -58,6 +66,7 @@ public final class PlaybackOutput implements Dumper.Dumpable {
|
|||||||
private final CapturingRenderersFactory capturingRenderersFactory;
|
private final CapturingRenderersFactory capturingRenderersFactory;
|
||||||
|
|
||||||
private final List<Metadata> metadatas;
|
private final List<Metadata> metadatas;
|
||||||
|
private final List<MediaMetadata> mediaMetadatas;
|
||||||
private final List<CueGroup> subtitles;
|
private final List<CueGroup> subtitles;
|
||||||
private final List<List<Cue>> subtitlesFromDeprecatedTextOutput;
|
private final List<List<Cue>> subtitlesFromDeprecatedTextOutput;
|
||||||
|
|
||||||
@ -65,6 +74,7 @@ public final class PlaybackOutput implements Dumper.Dumpable {
|
|||||||
this.capturingRenderersFactory = capturingRenderersFactory;
|
this.capturingRenderersFactory = capturingRenderersFactory;
|
||||||
|
|
||||||
metadatas = Collections.synchronizedList(new ArrayList<>());
|
metadatas = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
mediaMetadatas = Collections.synchronizedList(new ArrayList<>());
|
||||||
subtitles = Collections.synchronizedList(new ArrayList<>());
|
subtitles = Collections.synchronizedList(new ArrayList<>());
|
||||||
subtitlesFromDeprecatedTextOutput = Collections.synchronizedList(new ArrayList<>());
|
subtitlesFromDeprecatedTextOutput = Collections.synchronizedList(new ArrayList<>());
|
||||||
// TODO: Consider passing playback position into MetadataOutput. Calling
|
// TODO: Consider passing playback position into MetadataOutput. Calling
|
||||||
@ -77,6 +87,11 @@ public final class PlaybackOutput implements Dumper.Dumpable {
|
|||||||
metadatas.add(metadata);
|
metadatas.add(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMediaMetadataChanged(MediaMetadata mediaMetadata) {
|
||||||
|
mediaMetadatas.add(mediaMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation") // Intentionally testing deprecated output
|
@SuppressWarnings("deprecation") // Intentionally testing deprecated output
|
||||||
@Override
|
@Override
|
||||||
public void onCues(List<Cue> cues) {
|
public void onCues(List<Cue> cues) {
|
||||||
@ -112,6 +127,7 @@ public final class PlaybackOutput implements Dumper.Dumpable {
|
|||||||
capturingRenderersFactory.dump(dumper);
|
capturingRenderersFactory.dump(dumper);
|
||||||
|
|
||||||
dumpMetadata(dumper);
|
dumpMetadata(dumper);
|
||||||
|
dumpMediaMetadata(dumper);
|
||||||
dumpSubtitles(dumper);
|
dumpSubtitles(dumper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +173,206 @@ public final class PlaybackOutput implements Dumper.Dumpable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void dumpMediaMetadata(Dumper dumper) {
|
||||||
|
if (mediaMetadatas.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dumper.startBlock("Listener.onMediaMetadata");
|
||||||
|
for (int i = 0; i < mediaMetadatas.size(); i++) {
|
||||||
|
dumper.startBlock("MediaMetadata[" + i + "]");
|
||||||
|
MediaMetadata mediaMetadata = mediaMetadatas.get(i);
|
||||||
|
dumpIfNotEqual(dumper, "title", mediaMetadata.title, null);
|
||||||
|
dumpIfNotEqual(dumper, "artist", mediaMetadata.artist, null);
|
||||||
|
dumpIfNotEqual(dumper, "albumTitle", mediaMetadata.albumTitle, null);
|
||||||
|
dumpIfNotEqual(dumper, "albumArtist", mediaMetadata.albumArtist, null);
|
||||||
|
dumpIfNotEqual(dumper, "displayTitle", mediaMetadata.displayTitle, null);
|
||||||
|
dumpIfNotEqual(dumper, "subtitle", mediaMetadata.subtitle, null);
|
||||||
|
dumpIfNotEqual(dumper, "description", mediaMetadata.description, null);
|
||||||
|
dumpIfNotEqual(dumper, "userRating", ratingString(mediaMetadata.userRating), null);
|
||||||
|
dumpIfNotEqual(dumper, "overallRating", ratingString(mediaMetadata.overallRating), null);
|
||||||
|
dumpIfNotEqual(dumper, "artworkData", mediaMetadata.artworkData, null);
|
||||||
|
dumpIfNotEqual(
|
||||||
|
dumper, "artworkDataType", pictureTypeString(mediaMetadata.artworkDataType), null);
|
||||||
|
dumpIfNotEqual(dumper, "artworkUri", mediaMetadata.artworkUri, null);
|
||||||
|
dumpIfNotEqual(dumper, "trackNumber", mediaMetadata.trackNumber, null);
|
||||||
|
dumpIfNotEqual(dumper, "totalTrackCount", mediaMetadata.totalTrackCount, null);
|
||||||
|
dumpIfNotEqual(dumper, "isBrowsable", mediaMetadata.isBrowsable, null);
|
||||||
|
dumpIfNotEqual(dumper, "isPlayable", mediaMetadata.isPlayable, null);
|
||||||
|
dumpIfNotEqual(dumper, "recordingYear", mediaMetadata.recordingYear, null);
|
||||||
|
dumpIfNotEqual(dumper, "recordingMonth", mediaMetadata.recordingMonth, null);
|
||||||
|
dumpIfNotEqual(dumper, "recordingDay", mediaMetadata.recordingDay, null);
|
||||||
|
dumpIfNotEqual(dumper, "releaseYear", mediaMetadata.releaseYear, null);
|
||||||
|
dumpIfNotEqual(dumper, "releaseMonth", mediaMetadata.releaseMonth, null);
|
||||||
|
dumpIfNotEqual(dumper, "releaseDay", mediaMetadata.releaseDay, null);
|
||||||
|
dumpIfNotEqual(dumper, "writer", mediaMetadata.writer, null);
|
||||||
|
dumpIfNotEqual(dumper, "composer", mediaMetadata.composer, null);
|
||||||
|
dumpIfNotEqual(dumper, "conductor", mediaMetadata.conductor, null);
|
||||||
|
dumpIfNotEqual(dumper, "discNumber", mediaMetadata.discNumber, null);
|
||||||
|
dumpIfNotEqual(dumper, "totalDiscCount", mediaMetadata.totalDiscCount, null);
|
||||||
|
dumpIfNotEqual(dumper, "genre", mediaMetadata.genre, null);
|
||||||
|
dumpIfNotEqual(dumper, "compilation", mediaMetadata.compilation, null);
|
||||||
|
dumpIfNotEqual(dumper, "station", mediaMetadata.station, null);
|
||||||
|
dumpIfNotEqual(dumper, "mediaType", mediaTypeString(mediaMetadata.mediaType), null);
|
||||||
|
dumpIfNotEqual(dumper, "extras", mediaMetadata.extras, null);
|
||||||
|
dumper.endBlock();
|
||||||
|
}
|
||||||
|
dumper.endBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String pictureTypeString(@Nullable @PictureType Integer pictureType) {
|
||||||
|
if (pictureType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (pictureType) {
|
||||||
|
case MediaMetadata.PICTURE_TYPE_OTHER:
|
||||||
|
return "other";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_FILE_ICON:
|
||||||
|
return "file icon";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_FILE_ICON_OTHER:
|
||||||
|
return "file icon (other)";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_FRONT_COVER:
|
||||||
|
return "front cover";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_BACK_COVER:
|
||||||
|
return "back cover";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_LEAFLET_PAGE:
|
||||||
|
return "leaflet page";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_MEDIA:
|
||||||
|
return "media";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_LEAD_ARTIST_PERFORMER:
|
||||||
|
return "lead performer";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_ARTIST_PERFORMER:
|
||||||
|
return "performer";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_CONDUCTOR:
|
||||||
|
return "conductor";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_BAND_ORCHESTRA:
|
||||||
|
return "orchestra";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_COMPOSER:
|
||||||
|
return "composer";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_LYRICIST:
|
||||||
|
return "lyricist";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_RECORDING_LOCATION:
|
||||||
|
return "recording location";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_DURING_RECORDING:
|
||||||
|
return "during recording";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_DURING_PERFORMANCE:
|
||||||
|
return "during performance";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_MOVIE_VIDEO_SCREEN_CAPTURE:
|
||||||
|
return "video capture";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_A_BRIGHT_COLORED_FISH:
|
||||||
|
return "bright colored fish";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_ILLUSTRATION:
|
||||||
|
return "illustration";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_BAND_ARTIST_LOGO:
|
||||||
|
return "artist logo";
|
||||||
|
case MediaMetadata.PICTURE_TYPE_PUBLISHER_STUDIO_LOGO:
|
||||||
|
return "publisher logo";
|
||||||
|
default:
|
||||||
|
return "unrecognised: " + pictureType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String mediaTypeString(@Nullable @MediaType Integer mediaType) {
|
||||||
|
if (mediaType == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (mediaType) {
|
||||||
|
case MediaMetadata.MEDIA_TYPE_MIXED:
|
||||||
|
return "mixed";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_MUSIC:
|
||||||
|
return "music";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_AUDIO_BOOK_CHAPTER:
|
||||||
|
return "audiobook chapter";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_PODCAST_EPISODE:
|
||||||
|
return "podcast episode";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_RADIO_STATION:
|
||||||
|
return "radio station";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_NEWS:
|
||||||
|
return "news";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_VIDEO:
|
||||||
|
return "video";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_TRAILER:
|
||||||
|
return "trailer";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_MOVIE:
|
||||||
|
return "movie";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_TV_SHOW:
|
||||||
|
return "tv show";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_ALBUM:
|
||||||
|
return "album";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_ARTIST:
|
||||||
|
return "artist";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_GENRE:
|
||||||
|
return "genre";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_PLAYLIST:
|
||||||
|
return "playlist";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_YEAR:
|
||||||
|
return "year";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_AUDIO_BOOK:
|
||||||
|
return "audiobook";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_PODCAST:
|
||||||
|
return "podcast";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_TV_CHANNEL:
|
||||||
|
return "tv channel";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_TV_SERIES:
|
||||||
|
return "tv series";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_TV_SEASON:
|
||||||
|
return "tv season";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_MIXED:
|
||||||
|
return "folder (mixed)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_ALBUMS:
|
||||||
|
return "folder (albums)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_ARTISTS:
|
||||||
|
return "folder (artists)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_GENRES:
|
||||||
|
return "folder (genres)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_PLAYLISTS:
|
||||||
|
return "folder (playlists)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_YEARS:
|
||||||
|
return "folder (years)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_AUDIO_BOOKS:
|
||||||
|
return "folder (audiobooks)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_PODCASTS:
|
||||||
|
return "folder (podcasts)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_TV_CHANNELS:
|
||||||
|
return "folder (tv channels)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_TV_SERIES:
|
||||||
|
return "folder (tv series)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_TV_SHOWS:
|
||||||
|
return "folder (tv shows)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_RADIO_STATIONS:
|
||||||
|
return "folder (radio stations)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_NEWS:
|
||||||
|
return "folder (news)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_VIDEOS:
|
||||||
|
return "folder (videos)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_TRAILERS:
|
||||||
|
return "folder (trailers)";
|
||||||
|
case MediaMetadata.MEDIA_TYPE_FOLDER_MOVIES:
|
||||||
|
return "folder (movies)";
|
||||||
|
default:
|
||||||
|
return "unrecognised: " + mediaType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String ratingString(@Nullable Rating rating) {
|
||||||
|
if (rating == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (rating instanceof StarRating) {
|
||||||
|
StarRating starRating = (StarRating) rating;
|
||||||
|
return starRating.getStarRating() + "/" + starRating.getMaxStars() + " stars";
|
||||||
|
} else if (rating instanceof PercentageRating) {
|
||||||
|
return ((PercentageRating) rating).getPercent() + "%";
|
||||||
|
} else if (rating instanceof HeartRating) {
|
||||||
|
return ((HeartRating) rating).isHeart() ? "❤️" : "\uD83D\uDC94";
|
||||||
|
} else if (rating instanceof ThumbRating) {
|
||||||
|
return ((ThumbRating) rating).isThumbsUp() ? "\uD83D\uDC4D" : "\uD83D\uDC4E";
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Unrecognized Rating subclass: " + rating);
|
||||||
|
}
|
||||||
|
|
||||||
private void dumpSubtitles(Dumper dumper) {
|
private void dumpSubtitles(Dumper dumper) {
|
||||||
if (subtitles.size() != subtitlesFromDeprecatedTextOutput.size()) {
|
if (subtitles.size() != subtitlesFromDeprecatedTextOutput.size()) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user