Purely stylistic changes to FLV extractor

This commit is contained in:
Oliver Woodman 2015-10-26 10:44:19 +00:00
parent fb75b65a70
commit 950cc70003
5 changed files with 75 additions and 74 deletions

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);