Purely stylistic changes to FLV extractor
This commit is contained in:
parent
fb75b65a70
commit
950cc70003
@ -30,8 +30,9 @@ import java.util.Collections;
|
||||
/**
|
||||
* Parses audio tags of from an FLV stream and extracts AAC frames.
|
||||
*/
|
||||
final class AudioTagPayloadReader extends TagPayloadReader {
|
||||
// Sound format
|
||||
/* package */ final class AudioTagPayloadReader extends TagPayloadReader {
|
||||
|
||||
// Audio format
|
||||
private static final int AUDIO_FORMAT_AAC = 10;
|
||||
|
||||
// AAC PACKET TYPE
|
||||
@ -47,48 +48,40 @@ final class AudioTagPayloadReader extends TagPayloadReader {
|
||||
private boolean hasParsedAudioDataHeader;
|
||||
private boolean hasOutputFormat;
|
||||
|
||||
|
||||
public AudioTagPayloadReader(TrackOutput output) {
|
||||
super(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
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.
|
||||
protected boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException {
|
||||
// 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 audioFormat = (header >> 4) & 0x0F;
|
||||
int sampleRateIndex = (header >> 2) & 0x03;
|
||||
int bitsPerSample = (header & 0x02) == 0x02 ? 16 : 8;
|
||||
int channels = (header & 0x01) + 1;
|
||||
|
||||
if (sampleRateIndex < 0 || sampleRateIndex >= AUDIO_SAMPLING_RATE_TABLE.length) {
|
||||
throw new UnsupportedTrack("Invalid sample rate for the audio track");
|
||||
throw new UnsupportedFormatException("Invalid sample rate for the audio track");
|
||||
}
|
||||
|
||||
if (!hasOutputFormat) {
|
||||
if (audioFormat != AUDIO_FORMAT_AAC) {
|
||||
// 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);
|
||||
if (audioFormat != AUDIO_FORMAT_AAC) {
|
||||
throw new UnsupportedFormatException("Audio format not supported: " + audioFormat);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -110,10 +103,9 @@ final class AudioTagPayloadReader extends TagPayloadReader {
|
||||
audioSpecificConfig);
|
||||
|
||||
MediaFormat mediaFormat = MediaFormat.createAudioFormat(MediaFormat.NO_VALUE,
|
||||
MimeTypes.AUDIO_AAC, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs,
|
||||
MimeTypes.AUDIO_AAC, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, getDurationUs(),
|
||||
audioParams.second, audioParams.first, Collections.singletonList(audioSpecificConfig),
|
||||
null);
|
||||
|
||||
output.format(mediaFormat);
|
||||
hasOutputFormat = true;
|
||||
} else if (packetType == AAC_PACKET_TYPE_AAC_RAW) {
|
||||
|
@ -129,7 +129,7 @@ public final class FlvExtractor implements Extractor, SeekMap {
|
||||
return readSample(input);
|
||||
}
|
||||
}
|
||||
} catch (AudioTagPayloadReader.UnsupportedTrack unsupportedTrack) {
|
||||
} catch (AudioTagPayloadReader.UnsupportedFormatException unsupportedTrack) {
|
||||
unsupportedTrack.printStackTrace();
|
||||
return RESULT_END_OF_INPUT;
|
||||
}
|
||||
@ -186,11 +186,11 @@ public final class FlvExtractor implements Extractor, SeekMap {
|
||||
* @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
|
||||
* @throws TagPayloadReader.UnsupportedFormatException If payload of the tag is using a codec non
|
||||
* supported codec.
|
||||
*/
|
||||
private boolean readTagHeader(ExtractorInput input) throws IOException, InterruptedException,
|
||||
TagPayloadReader.UnsupportedTrack {
|
||||
TagPayloadReader.UnsupportedFormatException {
|
||||
try {
|
||||
// skipping previous tag size field
|
||||
input.skipFully(4);
|
||||
@ -235,11 +235,11 @@ public final class FlvExtractor implements Extractor, SeekMap {
|
||||
* @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
|
||||
* @throws TagPayloadReader.UnsupportedFormatException If payload of the tag is using a codec non
|
||||
* supported codec.
|
||||
*/
|
||||
private int readSample(ExtractorInput input) throws IOException,
|
||||
InterruptedException, AudioTagPayloadReader.UnsupportedTrack {
|
||||
InterruptedException, AudioTagPayloadReader.UnsupportedFormatException {
|
||||
if (tagData != null) {
|
||||
if (!input.readFully(tagData.data, 0, currentTagHeader.dataSize, true)) {
|
||||
return RESULT_END_OF_INPUT;
|
||||
|
@ -28,7 +28,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Parses Script Data tags from an FLV stream and extracts metadata information.
|
||||
*/
|
||||
final class ScriptTagPayloadReader extends TagPayloadReader {
|
||||
/* package */ final class ScriptTagPayloadReader extends TagPayloadReader {
|
||||
|
||||
// AMF object types
|
||||
private static final int AMF_TYPE_UNKNOWN = -1;
|
||||
@ -50,19 +50,20 @@ final class ScriptTagPayloadReader extends TagPayloadReader {
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean parseHeader(ParsableByteArray data) throws UnsupportedTrack {
|
||||
protected boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void parsePayload(ParsableByteArray data, long timeUs) {
|
||||
// Read message name (don't storing it as we are not going to give it any use)
|
||||
// Read message name (don't store it because we don't yet have a use for it).
|
||||
readAMFData(data, AMF_TYPE_UNKNOWN);
|
||||
// Read message data.
|
||||
Object obj = readAMFData(data, AMF_TYPE_UNKNOWN);
|
||||
|
||||
if (obj instanceof Map) {
|
||||
@ -74,7 +75,7 @@ final class ScriptTagPayloadReader extends TagPayloadReader {
|
||||
|
||||
switch (entry.getKey()) {
|
||||
case "duration":
|
||||
this.durationUs = (long)(C.MICROS_PER_SECOND * (Double)(entry.getValue()));
|
||||
setDurationUs((long) (C.MICROS_PER_SECOND * (Double)(entry.getValue())));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -198,4 +199,5 @@ final class ScriptTagPayloadReader extends TagPayloadReader {
|
||||
data.readUnsignedShort();
|
||||
return date;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,10 +24,20 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
||||
*/
|
||||
/* package */ abstract class TagPayloadReader {
|
||||
|
||||
/**
|
||||
* Thrown when the format is not supported.
|
||||
*/
|
||||
public static final class UnsupportedFormatException extends Exception {
|
||||
|
||||
public UnsupportedFormatException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected final TrackOutput output;
|
||||
|
||||
// Duration of the track
|
||||
protected long durationUs;
|
||||
private long durationUs;
|
||||
|
||||
/**
|
||||
* @param output A {@link TrackOutput} to which samples should be written.
|
||||
@ -37,6 +47,24 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
||||
this.durationUs = C.UNKNOWN_TIME_US;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets duration in microseconds.
|
||||
*
|
||||
* @param durationUs duration in microseconds.
|
||||
*/
|
||||
public final void setDurationUs(long durationUs) {
|
||||
this.durationUs = durationUs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration in microseconds.
|
||||
*
|
||||
* @return The duration in microseconds.
|
||||
*/
|
||||
public final long getDurationUs() {
|
||||
return durationUs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the reader that a seek has occurred.
|
||||
* <p>
|
||||
@ -46,53 +74,34 @@ import com.google.android.exoplayer.util.ParsableByteArray;
|
||||
*/
|
||||
public abstract void seek();
|
||||
|
||||
/**
|
||||
* Parses tag header
|
||||
* @param data Buffer where the tag header is stored
|
||||
* @return True if header was parsed successfully and then payload should be read;
|
||||
* Otherwise, false
|
||||
* @throws UnsupportedTrack
|
||||
*/
|
||||
protected abstract boolean parseHeader(ParsableByteArray data) throws UnsupportedTrack;
|
||||
|
||||
/**
|
||||
* Parses tag payload
|
||||
* @param data Buffer where tag payload is stored
|
||||
* @param timeUs Time position of the frame
|
||||
*/
|
||||
protected abstract void parsePayload(ParsableByteArray data, long timeUs);
|
||||
|
||||
/**
|
||||
* Consumes payload data.
|
||||
*
|
||||
* @param data The payload data to consume.
|
||||
* @param timeUs The timestamp associated with the payload.
|
||||
*/
|
||||
public void consume(ParsableByteArray data, long timeUs) throws UnsupportedTrack {
|
||||
public final void consume(ParsableByteArray data, long timeUs) throws UnsupportedFormatException {
|
||||
if (parseHeader(data)) {
|
||||
parsePayload(data, timeUs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets duration in microseconds
|
||||
* @param durationUs duration in microseconds
|
||||
* Parses tag header.
|
||||
*
|
||||
* @param data Buffer where the tag header is stored.
|
||||
* @return True if the header was parsed successfully and the payload should be read. False
|
||||
* otherwise.
|
||||
* @throws UnsupportedFormatException
|
||||
*/
|
||||
public void setDurationUs(long durationUs) {
|
||||
this.durationUs = durationUs;
|
||||
}
|
||||
protected abstract boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException;
|
||||
|
||||
public long getDurationUs() {
|
||||
return durationUs;
|
||||
}
|
||||
/**
|
||||
* Thrown when format described in the AudioTrack is not supported
|
||||
* Parses tag payload.
|
||||
*
|
||||
* @param data Buffer where tag payload is stored
|
||||
* @param timeUs Time position of the frame
|
||||
*/
|
||||
public static final class UnsupportedTrack extends Exception {
|
||||
protected abstract void parsePayload(ParsableByteArray data, long timeUs);
|
||||
|
||||
public UnsupportedTrack(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ import java.util.List;
|
||||
/**
|
||||
* Parses video tags from an FLV stream and extracts H.264 nal units.
|
||||
*/
|
||||
final class VideoTagPayloadReader extends TagPayloadReader {
|
||||
/* package */ final class VideoTagPayloadReader extends TagPayloadReader {
|
||||
private static final String TAG = "VideoTagPayloadReader";
|
||||
|
||||
// Video codec
|
||||
@ -63,25 +63,23 @@ final class VideoTagPayloadReader extends TagPayloadReader {
|
||||
*/
|
||||
public VideoTagPayloadReader(TrackOutput output) {
|
||||
super(output);
|
||||
|
||||
nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE);
|
||||
nalLength = new ParsableByteArray(4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean parseHeader(ParsableByteArray data) throws UnsupportedTrack {
|
||||
protected boolean parseHeader(ParsableByteArray data) throws UnsupportedFormatException {
|
||||
int header = data.readUnsignedByte();
|
||||
int frameType = (header >> 4) & 0x0F;
|
||||
int videoCodec = (header & 0x0F);
|
||||
|
||||
// Support just H.264 encoded content.
|
||||
if (videoCodec != VIDEO_CODEC_AVC) {
|
||||
throw new UnsupportedTrack("Video codec not supported. Codec: " + videoCodec);
|
||||
throw new UnsupportedFormatException("Video format not supported: " + videoCodec);
|
||||
}
|
||||
this.frameType = frameType;
|
||||
return (frameType != VIDEO_FRAME_VIDEO_INFO);
|
||||
@ -113,7 +111,7 @@ final class VideoTagPayloadReader extends TagPayloadReader {
|
||||
|
||||
// Construct and output the format.
|
||||
MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.NO_VALUE,
|
||||
MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, durationUs,
|
||||
MimeTypes.VIDEO_H264, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, getDurationUs(),
|
||||
avcData.width, avcData.height, avcData.initializationData, MediaFormat.NO_VALUE,
|
||||
avcData.pixelWidthAspectRatio);
|
||||
output.format(mediaFormat);
|
||||
|
Loading…
x
Reference in New Issue
Block a user