ID3 refactoring to match apple's player behavior #67

This commit is contained in:
Andrey Udovenko 2014-11-05 11:54:45 -05:00
parent b946ad9234
commit 71f918c01b
7 changed files with 41 additions and 33 deletions

View File

@ -25,7 +25,7 @@ import com.google.android.exoplayer.demo.full.player.DemoPlayer;
import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder; import com.google.android.exoplayer.demo.full.player.DemoPlayer.RendererBuilder;
import com.google.android.exoplayer.demo.full.player.HlsRendererBuilder; import com.google.android.exoplayer.demo.full.player.HlsRendererBuilder;
import com.google.android.exoplayer.demo.full.player.SmoothStreamingRendererBuilder; import com.google.android.exoplayer.demo.full.player.SmoothStreamingRendererBuilder;
import com.google.android.exoplayer.metadata.Metadata; import com.google.android.exoplayer.metadata.TxxxMetadata;
import com.google.android.exoplayer.text.CaptionStyleCompat; import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.google.android.exoplayer.text.SubtitleView; import com.google.android.exoplayer.text.SubtitleView;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
@ -56,7 +56,7 @@ import android.widget.PopupMenu;
import android.widget.PopupMenu.OnMenuItemClickListener; import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.TextView; import android.widget.TextView;
import java.util.List; import java.util.Map;
/** /**
* An activity that plays media using {@link DemoPlayer}. * An activity that plays media using {@link DemoPlayer}.
@ -415,10 +415,13 @@ public class FullPlayerActivity extends Activity implements SurfaceHolder.Callba
// DemoPlayer.MetadataListener implementation // DemoPlayer.MetadataListener implementation
@Override @Override
public void onMetadata(List<Metadata> metadata) { public void onMetadata(Map<String, Object> metadata) {
for (int i = 0; i < metadata.size(); i++) { for (int i = 0; i < metadata.size(); i++) {
Metadata next = metadata.get(i); if (metadata.containsKey(TxxxMetadata.TYPE)) {
Log.i(TAG, "ID3 TimedMetadata: key=" + next.key + ", value=" + next.value); TxxxMetadata txxxMetadata = (TxxxMetadata) metadata.get(TxxxMetadata.TYPE);
Log.i(TAG, String.format("ID3 TimedMetadata: description=%s, value=%s",
txxxMetadata.description, txxxMetadata.value));
}
} }
} }

View File

@ -26,7 +26,6 @@ import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.ChunkSampleSource; import com.google.android.exoplayer.chunk.ChunkSampleSource;
import com.google.android.exoplayer.chunk.MultiTrackChunkSource; import com.google.android.exoplayer.chunk.MultiTrackChunkSource;
import com.google.android.exoplayer.drm.StreamingDrmSessionManager; import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer.metadata.Metadata;
import com.google.android.exoplayer.metadata.MetadataTrackRenderer; import com.google.android.exoplayer.metadata.MetadataTrackRenderer;
import com.google.android.exoplayer.text.TextTrackRenderer; import com.google.android.exoplayer.text.TextTrackRenderer;
import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
@ -38,7 +37,7 @@ import android.os.Looper;
import android.view.Surface; import android.view.Surface;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
/** /**
@ -141,7 +140,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
* A listener for receiving metadata parsed from the media stream. * A listener for receiving metadata parsed from the media stream.
*/ */
public interface MetadataListener { public interface MetadataListener {
void onMetadata(List<Metadata> metadata); void onMetadata(Map<String, Object> metadata);
} }
// Constants pulled into this class for convenience. // Constants pulled into this class for convenience.
@ -475,7 +474,7 @@ public class DemoPlayer implements ExoPlayer.Listener, ChunkSampleSource.EventLi
} }
@Override @Override
public void onMetadata(List<Metadata> metadata) { public void onMetadata(Map<String, Object> metadata) {
if (metadataListener != null) { if (metadataListener != null) {
metadataListener.onMetadata(metadata); metadataListener.onMetadata(metadata);
} }

View File

@ -94,7 +94,7 @@ public class HlsRendererBuilder implements RendererBuilder, ManifestCallback<Hls
DataSource dataSource = new UriDataSource(userAgent, null); DataSource dataSource = new UriDataSource(userAgent, null);
HlsChunkSource chunkSource = new HlsChunkSource(dataSource, manifest); HlsChunkSource chunkSource = new HlsChunkSource(dataSource, manifest);
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl, HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, 2); VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true, 3);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource, MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, player.getMainHandler(), player, 50); MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, player.getMainHandler(), player, 50);
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource); MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);

View File

@ -20,9 +20,9 @@ import com.google.android.exoplayer.parser.ts.BitsArray;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.HashMap;
import java.util.Map;
/** /**
* Extracts individual TXXX text frames from raw ID3 data. * Extracts individual TXXX text frames from raw ID3 data.
@ -35,12 +35,12 @@ public class Id3Parser implements MetadataParser {
} }
@Override @Override
public List<Metadata> parse(byte[] data, int size) public Map<String, Object> parse(byte[] data, int size)
throws UnsupportedEncodingException, ParserException { throws UnsupportedEncodingException, ParserException {
BitsArray id3Buffer = new BitsArray(data, size); BitsArray id3Buffer = new BitsArray(data, size);
int id3Size = parseId3Header(id3Buffer); int id3Size = parseId3Header(id3Buffer);
List<Metadata> metadata = new ArrayList<Metadata>(); Map<String, Object> metadata = new HashMap<String, Object>();
while (id3Size > 0) { while (id3Size > 0) {
int frameId0 = id3Buffer.readUnsignedByte(); int frameId0 = id3Buffer.readUnsignedByte();
@ -63,20 +63,23 @@ public class Id3Parser implements MetadataParser {
id3Buffer.readBytes(frame, 0, frameSize - 1); id3Buffer.readBytes(frame, 0, frameSize - 1);
int firstZeroIndex = indexOf(frame, 0, (byte) 0); int firstZeroIndex = indexOf(frame, 0, (byte) 0);
String key = new String(frame, 0, firstZeroIndex, charset); String description = new String(frame, 0, firstZeroIndex, charset);
int valueStartIndex = indexOfNot(frame, firstZeroIndex, (byte) 0); int valueStartIndex = indexOfNot(frame, firstZeroIndex, (byte) 0);
int valueEndIndex = indexOf(frame, valueStartIndex, (byte) 0); int valueEndIndex = indexOf(frame, valueStartIndex, (byte) 0);
String value = new String(frame, valueStartIndex, valueEndIndex - valueStartIndex, String value = new String(frame, valueStartIndex, valueEndIndex - valueStartIndex,
charset); charset);
metadata.add(new Metadata(key, value)); metadata.put(TxxxMetadata.TYPE, new TxxxMetadata(description, value));
} else { } else {
id3Buffer.skipBytes(frameSize); String type = String.format("%c%c%c%c", frameId0, frameId1, frameId2, frameId3);
byte[] frame = new byte[frameSize];
id3Buffer.readBytes(frame, 0, frameSize);
metadata.put(type, frame);
} }
id3Size -= frameSize + 10 /* header size */; id3Size -= frameSize + 10 /* header size */;
} }
return Collections.unmodifiableList(metadata); return Collections.unmodifiableMap(metadata);
} }
private static int indexOf(byte[] data, int fromIndex, byte key) { private static int indexOf(byte[] data, int fromIndex, byte key) {

View File

@ -16,7 +16,7 @@
package com.google.android.exoplayer.metadata; package com.google.android.exoplayer.metadata;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.Map;
/** /**
* Parses {@link Metadata}s from binary data. * Parses {@link Metadata}s from binary data.
@ -32,14 +32,14 @@ public interface MetadataParser {
public boolean canParse(String mimeType); public boolean canParse(String mimeType);
/** /**
* Parses a list of {@link Metadata} objects from the provided binary data. * Parses a map of metadata type to metadata objects from the provided binary data.
* *
* @param data The raw binary data from which to parse the metadata. * @param data The raw binary data from which to parse the metadata.
* @param size The size of the input data. * @param size The size of the input data.
* @return A parsed {@link List} of {@link Metadata} objects. * @return A parsed {@link Map} of metadata type to metadata objects.
* @throws IOException If a problem occurred parsing the data. * @throws IOException If a problem occurred parsing the data.
*/ */
public List<Metadata> parse(byte[] data, int size) public Map<String, Object> parse(byte[] data, int size)
throws IOException; throws IOException;
} }

View File

@ -28,7 +28,7 @@ import android.os.Looper;
import android.os.Message; import android.os.Message;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.Map;
/** /**
* A {@link TrackRenderer} for metadata embedded in a media stream. * A {@link TrackRenderer} for metadata embedded in a media stream.
@ -45,7 +45,7 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback {
* *
* @param metadata The metadata to process. * @param metadata The metadata to process.
*/ */
void onMetadata(List<Metadata> metadata); void onMetadata(Map<String, Object> metadata);
} }
@ -63,7 +63,7 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback {
private boolean inputStreamEnded; private boolean inputStreamEnded;
private long pendingMetadataTimestamp; private long pendingMetadataTimestamp;
private List<Metadata> pendingMetadata; private Map<String, Object> pendingMetadata;
/** /**
* @param source A source from which samples containing metadata can be read. * @param source A source from which samples containing metadata can be read.
@ -185,7 +185,7 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback {
return true; return true;
} }
private void invokeRenderer(List<Metadata> metadata) { private void invokeRenderer(Map<String, Object> metadata) {
if (metadataHandler != null) { if (metadataHandler != null) {
metadataHandler.obtainMessage(MSG_INVOKE_RENDERER, metadata).sendToTarget(); metadataHandler.obtainMessage(MSG_INVOKE_RENDERER, metadata).sendToTarget();
} else { } else {
@ -198,13 +198,13 @@ public class MetadataTrackRenderer extends TrackRenderer implements Callback {
public boolean handleMessage(Message msg) { public boolean handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case MSG_INVOKE_RENDERER: case MSG_INVOKE_RENDERER:
invokeRendererInternal((List<Metadata>) msg.obj); invokeRendererInternal((Map<String, Object>) msg.obj);
return true; return true;
} }
return false; return false;
} }
private void invokeRendererInternal(List<Metadata> metadata) { private void invokeRendererInternal(Map<String, Object> metadata) {
metadataRenderer.onMetadata(metadata); metadataRenderer.onMetadata(metadata);
} }

View File

@ -16,15 +16,18 @@
package com.google.android.exoplayer.metadata; package com.google.android.exoplayer.metadata;
/** /**
* A metadata that contains textual data associated with time indices. * A metadata that contains parsed ID3 TXXX (User defined text information) frame data associated
* with time indices.
*/ */
public class Metadata { public class TxxxMetadata {
public final String key; public static final String TYPE = "TXXX";
public final String description;
public final String value; public final String value;
public Metadata(String key, String value) { public TxxxMetadata(String description, String value) {
this.key = key; this.description = description;
this.value = value; this.value = value;
} }