diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java b/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java
index 98c8bb2066..8560216d8b 100644
--- a/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java
+++ b/demo/src/main/java/com/google/android/exoplayer/demo/Samples.java
@@ -145,9 +145,9 @@ import java.util.Locale;
"http://storage.googleapis.com/exoplayer-test-media-0/play.mp3", PlayerActivity.TYPE_OTHER),
new Sample("Google Glass (WebM Video with Vorbis Audio)",
"http://demos.webmproject.org/exoplayer/glass_vp9_vorbis.webm", PlayerActivity.TYPE_OTHER),
- new Sample("FLV Sample",
- "http://master255.org/res/%D0%9A%D0%BB%D0%B8%D0%BF%D1%8B/B/Black%20Eyed%20Peas/black%20ey"
- + "ed%20peas-My%20Humps.flv", PlayerActivity.TYPE_OTHER),
+ new Sample("Big Buck Bunny (FLV Video)",
+ "http://vod.leasewebcdn.com/bbb.flv?ri=1024&rs=150&start=0", PlayerActivity.TYPE_OTHER),
+
};
private Samples() {}
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java b/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java
index 982894e4b5..e13bb16422 100644
--- a/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java
+++ b/library/src/main/java/com/google/android/exoplayer/extractor/ExtractorSampleSource.java
@@ -58,9 +58,10 @@ import java.util.List;
*
MP3 ({@link com.google.android.exoplayer.extractor.mp3.Mp3Extractor})
* AAC ({@link com.google.android.exoplayer.extractor.ts.AdtsExtractor})
* MPEG TS ({@link com.google.android.exoplayer.extractor.ts.TsExtractor}
+ * FLV ({@link com.google.android.exoplayer.extractor.flv.FlvExtractor}
*
*
- * Seeking in AAC and MPEG TS streams is not supported.
+ *
Seeking in AAC, MPEG TS and FLV streams is not supported.
*
*
To override the default extractors, pass one or more {@link Extractor} instances to the
* constructor. When reading a new stream, the first {@link Extractor} that returns {@code true}
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/flv/AudioTagReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/flv/AudioTagPayloadReader.java
similarity index 52%
rename from library/src/main/java/com/google/android/exoplayer/extractor/flv/AudioTagReader.java
rename to library/src/main/java/com/google/android/exoplayer/extractor/flv/AudioTagPayloadReader.java
index bde1cbbdea..470a2eaf3f 100644
--- a/library/src/main/java/com/google/android/exoplayer/extractor/flv/AudioTagReader.java
+++ b/library/src/main/java/com/google/android/exoplayer/extractor/flv/AudioTagPayloadReader.java
@@ -1,8 +1,21 @@
+/*
+ * Copyright (C) 2014 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 com.google.android.exoplayer.extractor.flv;
-import android.util.Log;
import android.util.Pair;
-
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.extractor.TrackOutput;
@@ -14,48 +27,27 @@ import com.google.android.exoplayer.util.ParsableByteArray;
import java.util.Collections;
/**
- * Created by joliva on 9/27/15.
+ * Parses audio tags of from an FLV stream and extracts AAC frames.
*/
-public class AudioTagReader extends TagReader{
-
- private static final String TAG = "AudioTagReader";
-
+final class AudioTagPayloadReader extends TagPayloadReader {
// Sound format
- private static final int AUDIO_FORMAT_LINEAR_PCM_PLATFORM_ENDIAN = 0;
- private static final int AUDIO_FORMAT_ADPCM = 1;
- private static final int AUDIO_FORMAT_MP3 = 2;
- private static final int AUDIO_FORMAT_LINEAR_PCM_LITTLE_ENDIAN = 3;
- private static final int AUDIO_FORMAT_NELLYMOSER_16KHZ_MONO = 4;
- private static final int AUDIO_FORMAT_NELLYMOSER_8KHZ_MONO = 5;
- private static final int AUDIO_FORMAT_NELLYMOSER = 6;
- private static final int AUDIO_FORMAT_G711_A_LAW = 7;
- private static final int AUDIO_FORMAT_G711_MU_LAW = 8;
- private static final int AUDIO_FORMAT_RESERVED = 9;
private static final int AUDIO_FORMAT_AAC = 10;
- private static final int AUDIO_FORMAT_SPEEX = 11;
- private static final int AUDIO_FORMAT_MP3_8KHZ = 14;
- private static final int AUDIO_FORMAT_DEVICE_SPECIFIC = 15;
// AAC PACKET TYPE
private static final int AAC_PACKET_TYPE_SEQUENCE_HEADER = 0;
private static final int AAC_PACKET_TYPE_AAC_RAW = 1;
+ // SAMPLING RATES
private static final int[] AUDIO_SAMPLING_RATE_TABLE = new int[] {
5500, 11000, 22000, 44000
};
- private int format;
- private int sampleRate;
- private int bitsPerSample;
- private int channels;
-
- private boolean hasParsedAudioData;
+ // State variables
+ private boolean hasParsedAudioDataHeader;
private boolean hasOutputFormat;
- /**
- * @param output A {@link TrackOutput} to which samples should be written.
- */
- public AudioTagReader(TrackOutput output) {
+
+ public AudioTagPayloadReader(TrackOutput output) {
super(output);
}
@@ -65,8 +57,10 @@ public class AudioTagReader extends TagReader{
}
@Override
- protected void parseHeader(ParsableByteArray data) throws UnsupportedTrack {
- if (!hasParsedAudioData) {
+ protected boolean parseHeader(ParsableByteArray data) throws UnsupportedTrack {
+ // Parse audio data header, if it was not done, to extract information
+ // about the audio codec and audio configuration.
+ if (!hasParsedAudioDataHeader) {
int header = data.readUnsignedByte();
int soundFormat = (header >> 4) & 0x0F;
int sampleRateIndex = (header >> 2) & 0x03;
@@ -78,42 +72,29 @@ public class AudioTagReader extends TagReader{
}
if (!hasOutputFormat) {
- switch (soundFormat) {
- // raw audio data. Just creates media format
- case AUDIO_FORMAT_LINEAR_PCM_LITTLE_ENDIAN:
- output.format(MediaFormat.createAudioFormat(MimeTypes.AUDIO_RAW, MediaFormat.NO_VALUE,
- MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, channels,
- AUDIO_SAMPLING_RATE_TABLE[sampleRateIndex], null, null));
- hasOutputFormat = true;
- break;
-
- case AUDIO_FORMAT_AAC:
- break;
-
- case AUDIO_FORMAT_MP3:
- case AUDIO_FORMAT_MP3_8KHZ:
- case AUDIO_FORMAT_LINEAR_PCM_PLATFORM_ENDIAN:
- default:
- throw new UnsupportedTrack("Audio track not supported. Format: " + soundFormat +
- ", Sample rate: " + sampleRateIndex + ", bps: " + bitsPerSample + ", channels: " +
- channels);
+ // TODO: Adds support for MP3 and PCM
+ if (soundFormat != AUDIO_FORMAT_AAC) {
+ throw new UnsupportedTrack("Audio track not supported. Format: " + soundFormat +
+ ", Sample rate: " + sampleRateIndex + ", bps: " + bitsPerSample + ", channels: " +
+ channels);
}
}
- this.format = soundFormat;
- this.sampleRate = AUDIO_SAMPLING_RATE_TABLE[sampleRateIndex];
- this.bitsPerSample = bitsPerSample;
- this.channels = channels;
-
- hasParsedAudioData = true;
+ hasParsedAudioDataHeader = true;
} else {
+ // Skip header if it was parsed previously.
data.skipBytes(1);
}
+
+ // In all the cases we will be managing AAC format (otherwise an exception would be
+ // fired so we can just always return true
+ return true;
}
@Override
protected void parsePayload(ParsableByteArray data, long timeUs) {
int packetType = data.readUnsignedByte();
+ // Parse sequence header just in case it was not done before.
if (packetType == AAC_PACKET_TYPE_SEQUENCE_HEADER && !hasOutputFormat) {
ParsableBitArray adtsScratch = new ParsableBitArray(new byte[data.bytesLeft()]);
data.readBytes(adtsScratch.data, 0, data.bytesLeft());
@@ -134,17 +115,11 @@ public class AudioTagReader extends TagReader{
output.format(mediaFormat);
hasOutputFormat = true;
} else if (packetType == AAC_PACKET_TYPE_AAC_RAW) {
+ // Sample audio AAC frames
int bytesToWrite = data.bytesLeft();
output.sampleData(data, bytesToWrite);
output.sampleMetadata(timeUs, C.SAMPLE_FLAG_SYNC, bytesToWrite, 0, null);
-
- Log.d(TAG, "AAC TAG. Size: " + bytesToWrite + ", timeUs: " + timeUs);
}
}
- @Override
- protected boolean shouldParsePayload() {
- return (format == AUDIO_FORMAT_AAC);
- }
-
}
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/flv/FlvExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/flv/FlvExtractor.java
index e94be312b0..563361d97d 100644
--- a/library/src/main/java/com/google/android/exoplayer/extractor/flv/FlvExtractor.java
+++ b/library/src/main/java/com/google/android/exoplayer/extractor/flv/FlvExtractor.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2014 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 com.google.android.exoplayer.extractor.flv;
import com.google.android.exoplayer.C;
@@ -6,7 +21,6 @@ import com.google.android.exoplayer.extractor.ExtractorInput;
import com.google.android.exoplayer.extractor.ExtractorOutput;
import com.google.android.exoplayer.extractor.PositionHolder;
import com.google.android.exoplayer.extractor.SeekMap;
-import com.google.android.exoplayer.extractor.TrackOutput;
import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.ParsableByteArray;
import com.google.android.exoplayer.util.Util;
@@ -15,9 +29,9 @@ import java.io.EOFException;
import java.io.IOException;
/**
- * Created by joliva on 9/26/15.
+ * Facilitates the extraction of data from the FLV container format.
*/
-public final class FlvExtractor implements Extractor {
+public final class FlvExtractor implements Extractor, SeekMap {
// Header sizes
private static final int FLV_MIN_HEADER_SIZE = 9;
private static final int FLV_TAG_HEADER_SIZE = 11;
@@ -31,8 +45,10 @@ public final class FlvExtractor implements Extractor {
private static final int TAG_TYPE_VIDEO = 9;
private static final int TAG_TYPE_SCRIPT_DATA = 18;
+ // FLV container identifier
private static final int FLV_TAG = Util.getIntegerCodeForString("FLV");
+ // Temporary buffers
private final ParsableByteArray scratch;
private final ParsableByteArray headerBuffer;
private final ParsableByteArray tagHeaderBuffer;
@@ -40,36 +56,28 @@ public final class FlvExtractor implements Extractor {
// Extractor outputs.
private ExtractorOutput extractorOutput;
- private TrackOutput trackOutput;
-
- private boolean hasAudio;
- private boolean hasVideo;
- private int dataOffset;
+ // State variables.
private int parserState;
+ private int dataOffset;
private TagHeader currentTagHeader;
- private AudioTagReader audioReader;
- private VideoTagReader videoReader;
- private MetadataReader metadataReader;
+ // Tags readers
+ private AudioTagPayloadReader audioReader;
+ private VideoTagPayloadReader videoReader;
+ private ScriptTagPayloadReader metadataReader;
public FlvExtractor() {
scratch = new ParsableByteArray(4);
headerBuffer = new ParsableByteArray(FLV_MIN_HEADER_SIZE);
tagHeaderBuffer = new ParsableByteArray(FLV_TAG_HEADER_SIZE);
dataOffset = 0;
- hasAudio = false;
- hasVideo = false;
currentTagHeader = new TagHeader();
}
@Override
public void init(ExtractorOutput output) {
this.extractorOutput = output;
- trackOutput = extractorOutput.track(0);
- extractorOutput.endTracks();
-
- output.seekMap(SeekMap.UNSEEKABLE);
}
@Override
@@ -80,7 +88,6 @@ public final class FlvExtractor implements Extractor {
if (scratch.readUnsignedInt24() != FLV_TAG) {
return false;
}
-/*
// Checking reserved flags are set to 0
input.peekFully(scratch.data, 0, 2);
@@ -98,13 +105,10 @@ public final class FlvExtractor implements Extractor {
input.advancePeekPosition(dataOffset);
// Checking first "previous tag size" is set to 0
- input.peekFully(scratch.data, 0, 1);
+ input.peekFully(scratch.data, 0, 4);
scratch.setPosition(0);
- if (scratch.readInt() != 0) {
- return false;
- }
-*/
- return true;
+
+ return scratch.readInt() == 0;
}
@Override
@@ -117,21 +121,17 @@ public final class FlvExtractor implements Extractor {
try {
while (true) {
- switch (parserState) {
- case STATE_READING_TAG_HEADER:
- if (!readTagHeader(input)) {
- return RESULT_END_OF_INPUT;
- }
- break;
-
- default:
- return readSample(input, seekPosition);
+ if (parserState == STATE_READING_TAG_HEADER) {
+ if (!readTagHeader(input)) {
+ return RESULT_END_OF_INPUT;
+ }
+ } else {
+ return readSample(input);
}
}
- } catch (AudioTagReader.UnsupportedTrack unsupportedTrack) {
+ } catch (AudioTagPayloadReader.UnsupportedTrack unsupportedTrack) {
unsupportedTrack.printStackTrace();
- return RESULT_END_OF_INPUT;
-
+ return RESULT_END_OF_INPUT;
}
}
@@ -140,23 +140,35 @@ public final class FlvExtractor implements Extractor {
dataOffset = 0;
}
+ /**
+ * Reads FLV container header from the provided {@link ExtractorInput}.
+ * @param input The {@link ExtractorInput} from which to read.
+ * @return True if header was read successfully. Otherwise, false.
+ * @throws IOException If an error occurred reading from the source.
+ * @throws InterruptedException If the thread was interrupted.
+ */
private boolean readHeader(ExtractorInput input) throws IOException, InterruptedException {
try {
input.readFully(headerBuffer.data, 0, FLV_MIN_HEADER_SIZE);
headerBuffer.setPosition(0);
headerBuffer.skipBytes(4);
int flags = headerBuffer.readUnsignedByte();
- hasAudio = (flags & 0x04) != 0;
- hasVideo = (flags & 0x01) != 0;
+ boolean hasAudio = (flags & 0x04) != 0;
+ boolean hasVideo = (flags & 0x01) != 0;
- if (hasAudio) {
- audioReader = new AudioTagReader(trackOutput);
+ if (hasAudio && audioReader == null) {
+ audioReader = new AudioTagPayloadReader(extractorOutput.track(TAG_TYPE_AUDIO));
}
- if (hasVideo) {
- //videoReader = new VideoTagReader(trackOutput);
+ if (hasVideo && videoReader == null) {
+ videoReader = new VideoTagPayloadReader(extractorOutput.track(TAG_TYPE_VIDEO));
}
- metadataReader = new MetadataReader(trackOutput);
+ if (metadataReader == null) {
+ metadataReader = new ScriptTagPayloadReader(null);
+ }
+ extractorOutput.endTracks();
+ extractorOutput.seekMap(this);
+ // Store payload start position and start extended header (if there is one)
dataOffset = headerBuffer.readInt();
input.skipFully(dataOffset - FLV_MIN_HEADER_SIZE);
@@ -168,14 +180,25 @@ public final class FlvExtractor implements Extractor {
return true;
}
+ /**
+ * Reads a tag header from the provided {@link ExtractorInput}.
+ * @param input The {@link ExtractorInput} from which to read.
+ * @return True if tag header was read successfully. Otherwise, false.
+ * @throws IOException If an error occurred reading from the source.
+ * @throws InterruptedException If the thread was interrupted.
+ * @throws TagPayloadReader.UnsupportedTrack If payload of the tag is using a codec non
+ * supported codec.
+ */
private boolean readTagHeader(ExtractorInput input) throws IOException, InterruptedException,
- TagReader.UnsupportedTrack {
+ TagPayloadReader.UnsupportedTrack {
try {
+ // skipping previous tag size field
input.skipFully(4);
+
+ // Read the tag header from the input.
input.readFully(tagHeaderBuffer.data, 0, FLV_TAG_HEADER_SIZE);
tagHeaderBuffer.setPosition(0);
- // skipping previous tag size field.
int type = tagHeaderBuffer.readUnsignedByte();
int dataSize = tagHeaderBuffer.readUnsignedInt24();
long timestamp = tagHeaderBuffer.readUnsignedInt24();
@@ -187,8 +210,16 @@ public final class FlvExtractor implements Extractor {
currentTagHeader.timestamp = timestamp * 1000;
currentTagHeader.streamId = streamId;
- Assertions.checkState(dataSize <= Integer.MAX_VALUE);
- tagData = new ParsableByteArray((int) dataSize);
+ // Sanity checks.
+ Assertions.checkState(type == TAG_TYPE_AUDIO || type == TAG_TYPE_VIDEO
+ || type == TAG_TYPE_SCRIPT_DATA);
+ // Reuse tagData buffer to avoid lot of memory allocation (performance penalty).
+ if (tagData == null || dataSize > tagData.capacity()) {
+ tagData = new ParsableByteArray(dataSize);
+ } else {
+ tagData.setPosition(0);
+ }
+ tagData.setLimit(dataSize);
parserState = STATE_READING_SAMPLE;
} catch (EOFException eof) {
@@ -198,8 +229,17 @@ public final class FlvExtractor implements Extractor {
return true;
}
- private int readSample(ExtractorInput input, PositionHolder seekPosition) throws IOException,
- InterruptedException, AudioTagReader.UnsupportedTrack {
+ /**
+ * Reads payload of an FLV tag from the provided {@link ExtractorInput}.
+ * @param input The {@link ExtractorInput} from which to read.
+ * @return One of {@link Extractor#RESULT_CONTINUE} and {@link Extractor#RESULT_END_OF_INPUT}.
+ * @throws IOException If an error occurred reading from the source.
+ * @throws InterruptedException If the thread was interrupted.
+ * @throws TagPayloadReader.UnsupportedTrack If payload of the tag is using a codec non
+ * supported codec.
+ */
+ private int readSample(ExtractorInput input) throws IOException,
+ InterruptedException, AudioTagPayloadReader.UnsupportedTrack {
if (tagData != null) {
if (!input.readFully(tagData.data, 0, currentTagHeader.dataSize, true)) {
return RESULT_END_OF_INPUT;
@@ -210,18 +250,19 @@ public final class FlvExtractor implements Extractor {
return RESULT_CONTINUE;
}
+ // Pass payload to the right payload reader.
if (currentTagHeader.type == TAG_TYPE_AUDIO && audioReader != null) {
audioReader.consume(tagData, currentTagHeader.timestamp);
} else if (currentTagHeader.type == TAG_TYPE_VIDEO && videoReader != null) {
videoReader.consume(tagData, currentTagHeader.timestamp);
} else if (currentTagHeader.type == TAG_TYPE_SCRIPT_DATA && metadataReader != null) {
metadataReader.consume(tagData, currentTagHeader.timestamp);
- if (metadataReader.durationUs != C.UNKNOWN_TIME_US) {
+ if (metadataReader.getDurationUs() != C.UNKNOWN_TIME_US) {
if (audioReader != null) {
- audioReader.durationUs = metadataReader.durationUs;
+ audioReader.setDurationUs(metadataReader.getDurationUs());
}
if (videoReader != null) {
- videoReader.durationUs = metadataReader.durationUs;
+ videoReader.setDurationUs(metadataReader.getDurationUs());
}
}
} else {
@@ -233,4 +274,28 @@ public final class FlvExtractor implements Extractor {
return RESULT_CONTINUE;
}
+ // SeekMap implementation.
+ // TODO: Add seeking support
+ @Override
+ public boolean isSeekable() {
+ return false;
+ }
+
+ @Override
+ public long getPosition(long timeUs) {
+ return 0;
+ }
+
+
+ /**
+ * Defines header of a FLV tag
+ */
+ final class TagHeader {
+ public int type;
+ public int dataSize;
+ public long timestamp;
+ public int streamId;
+ }
+
+
}
diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/flv/MetadataReader.java b/library/src/main/java/com/google/android/exoplayer/extractor/flv/MetadataReader.java
deleted file mode 100644
index aac3ff6a4c..0000000000
--- a/library/src/main/java/com/google/android/exoplayer/extractor/flv/MetadataReader.java
+++ /dev/null
@@ -1,203 +0,0 @@
-package com.google.android.exoplayer.extractor.flv;
-
-import android.util.Log;
-
-import com.google.android.exoplayer.C;
-import com.google.android.exoplayer.extractor.TrackOutput;
-import com.google.android.exoplayer.util.ParsableBitArray;
-import com.google.android.exoplayer.util.ParsableByteArray;
-
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Created by joliva on 9/28/15.
- */
-public class MetadataReader extends TagReader{
-
- private static final int METADATA_TYPE_UNKNOWN = -1;
- private static final int METADATA_TYPE_NUMBER = 0;
- private static final int METADATA_TYPE_BOOLEAN = 1;
- private static final int METADATA_TYPE_STRING = 2;
- private static final int METADATA_TYPE_OBJECT = 3;
- private static final int METADATA_TYPE_MOVIE_CLIP = 4;
- private static final int METADATA_TYPE_NULL = 5;
- private static final int METADATA_TYPE_UNDEFINED = 6;
- private static final int METADATA_TYPE_REFERENCE = 7;
- private static final int METADATA_TYPE_ECMA_ARRAY = 8;
- private static final int METADATA_TYPE_STRICT_ARRAY = 10;
- private static final int METADATA_TYPE_DATE = 11;
- private static final int METADATA_TYPE_LONG_STRING = 12;
-
- public long startTime = C.UNKNOWN_TIME_US;
- public float frameRate;
- public float videoDataRate;
- public float audioDataRate;
- public int height;
- public int width;
- public boolean canSeekOnTime;
- public String httpHostHeader;
-
- /**
- * @param output A {@link TrackOutput} to which samples should be written.
- */
- public MetadataReader(TrackOutput output) {
- super(output);
- }
-
- @Override
- public void seek() {
-
- }
-
- @Override
- protected void parseHeader(ParsableByteArray data) throws UnsupportedTrack {
-
- }
-
- @Override
- protected void parsePayload(ParsableByteArray data, long timeUs) {
- Object messageName = readAMFData(data, METADATA_TYPE_UNKNOWN);
- Object obj = readAMFData(data, METADATA_TYPE_UNKNOWN);
-
- if(obj instanceof Map) {
- Map extractedMetadata = (Map) obj;
- for (Map.Entry entry : extractedMetadata.entrySet()) {
- if (entry.getValue() == null) {
- continue;
- }
- Log.d("Metadata", "Key: " + entry.getKey() + ", Value: " + entry.getValue().toString());
-
- switch (entry.getKey()) {
- case "totalduration":
- this.durationUs = (long)(C.MICROS_PER_SECOND * (Double)(entry.getValue()));
- break;
-
- case "starttime":
- this.startTime = (long)(C.MICROS_PER_SECOND * (Double)(entry.getValue()));
- break;
-
- case "videodatarate":
- this.videoDataRate = ((Double)entry.getValue()).floatValue();
- break;
-
- case "audiodatarate":
- this.audioDataRate = ((Double)entry.getValue()).floatValue();
- break;
-
- case "framerate":
- this.frameRate = ((Double)entry.getValue()).floatValue();
- break;
-
- case "width":
- this.width = Math.round(((Double) entry.getValue()).floatValue());
- break;
-
- case "height":
- this.height = Math.round(((Double) entry.getValue()).floatValue());
- break;
-
- case "canseekontime":
- this.canSeekOnTime = (boolean) entry.getValue();
- break;
-
- case "httphostheader":
- this.httpHostHeader = (String) entry.getValue();
- break;
-
- default:
- break;
- }
- }
- }
- }
-
- @Override
- protected boolean shouldParsePayload() {
- return true;
- }
-
- private Object readAMFData(ParsableByteArray data, int type) {
- if (type == METADATA_TYPE_UNKNOWN) {
- type = data.readUnsignedByte();
- }
- byte [] b;
- switch (type) {
- case METADATA_TYPE_NUMBER:
- return readAMFDouble(data);
- case METADATA_TYPE_BOOLEAN:
- return readAMFBoolean(data);
- case METADATA_TYPE_STRING:
- return readAMFString(data);
- case METADATA_TYPE_OBJECT:
- return readAMFObject(data);
- case METADATA_TYPE_ECMA_ARRAY:
- return readAMFEcmaArray(data);
- case METADATA_TYPE_STRICT_ARRAY:
- return readAMFStrictArray(data);
- case METADATA_TYPE_DATE:
- return readAMFDouble(data);
- default:
- return null;
- }
- }
-
- private Boolean readAMFBoolean(ParsableByteArray data) {
- return Boolean.valueOf(data.readUnsignedByte() == 1);
- }
-
- private Double readAMFDouble(ParsableByteArray data) {
- byte []b = new byte[8];
- data.readBytes(b, 0, b.length);
- return ByteBuffer.wrap(b).getDouble();
- }
-
- private String readAMFString(ParsableByteArray data) {
- int size = data.readUnsignedShort();
- byte []b = new byte[size];
- data.readBytes(b, 0, b.length);
- return new String(b);
- }
-
- private Object readAMFStrictArray(ParsableByteArray data) {
- long count = data.readUnsignedInt();
- ArrayList