Simplify AviTrack

This commit is contained in:
Dustin 2022-02-03 18:07:51 -07:00
parent 1528b8b5ee
commit aee15f6c70
4 changed files with 30 additions and 39 deletions

View File

@ -258,7 +258,7 @@ public class AviExtractor implements Extractor {
builder.setSampleMimeType(mimeType); builder.setSampleMimeType(mimeType);
final LinearClock clock = new LinearClock(durationUs, length); final LinearClock clock = new LinearClock(durationUs, length);
aviTrack = new AviTrack(streamId, C.TRACK_TYPE_VIDEO, clock, trackOutput); aviTrack = new AviTrack(streamId, AviTrack.CHUNK_TYPE_VIDEO, clock, trackOutput);
if (MimeTypes.VIDEO_H264.equals(mimeType)) { if (MimeTypes.VIDEO_H264.equals(mimeType)) {
final AvcChunkPeeker avcChunkPeeker = new AvcChunkPeeker(builder, trackOutput, clock); final AvcChunkPeeker avcChunkPeeker = new AvcChunkPeeker(builder, trackOutput, clock);
@ -294,7 +294,7 @@ public class AviExtractor implements Extractor {
builder.setInitializationData(Collections.singletonList(audioFormat.getCodecData())); builder.setInitializationData(Collections.singletonList(audioFormat.getCodecData()));
} }
trackOutput.format(builder.build()); trackOutput.format(builder.build());
aviTrack = new AviTrack(streamId, C.TRACK_TYPE_AUDIO, aviTrack = new AviTrack(streamId, AviTrack.CHUNK_TYPE_AUDIO,
new LinearClock(durationUs, length), trackOutput); new LinearClock(durationUs, length), trackOutput);
aviTrack.setKeyFrames(AviTrack.ALL_KEY_FRAMES); aviTrack.setKeyFrames(AviTrack.ALL_KEY_FRAMES);
}else { }else {
@ -370,18 +370,18 @@ public class AviExtractor implements Extractor {
if (aviTrack != null) { if (aviTrack != null) {
if (aviTrack.isAudio()) { if (aviTrack.isAudio()) {
final long durationUs = aviTrack.getClock().durationUs; final long durationUs = aviTrack.getClock().durationUs;
i("Audio #" + aviTrack.id + " chunks: " + aviTrack.chunks + " us=" + durationUs + i("Audio #" + aviTrack.getId() + " chunks: " + aviTrack.chunks + " us=" + durationUs +
" size=" + aviTrack.size); " size=" + aviTrack.size);
final LinearClock linearClock = aviTrack.getClock(); final LinearClock linearClock = aviTrack.getClock();
//If the audio track duration is off from the video by >5 % recalc using video //If the audio track duration is off from the video by >5 % recalc using video
if ((durationUs - videoDuration) / (float)videoDuration > .05f) { if ((durationUs - videoDuration) / (float)videoDuration > .05f) {
w("Audio #" + aviTrack.id + " duration is off using videoDuration"); w("Audio #" + aviTrack.getId() + " duration is off using videoDuration");
linearClock.setDuration(videoDuration); linearClock.setDuration(videoDuration);
} }
linearClock.setLength(aviTrack.chunks); linearClock.setLength(aviTrack.chunks);
if (aviTrack.chunks != keyFrameCounts[aviTrack.id]) { if (aviTrack.chunks != keyFrameCounts[aviTrack.getId()]) {
w("Audio is not all key frames chunks=" + aviTrack.chunks + " keyFrames=" + w("Audio is not all key frames chunks=" + aviTrack.chunks + " keyFrames=" +
keyFrameCounts[aviTrack.id]); keyFrameCounts[aviTrack.getId()]);
} }
} }
} }
@ -406,7 +406,7 @@ public class AviExtractor implements Extractor {
final ByteBuffer firstEntry = AviExtractor.allocate(16); final ByteBuffer firstEntry = AviExtractor.allocate(16);
input.peekFully(firstEntry.array(), 0, 16); input.peekFully(firstEntry.array(), 0, 16);
final int videoId = videoTrack.id; final int videoId = videoTrack.getId();
final ByteBuffer indexByteBuffer = allocate(Math.min(remaining, 64 * 1024)); final ByteBuffer indexByteBuffer = allocate(Math.min(remaining, 64 * 1024));
final byte[] bytes = indexByteBuffer.array(); final byte[] bytes = indexByteBuffer.array();
@ -453,19 +453,19 @@ public class AviExtractor implements Extractor {
keyFrameOffsetsDiv2.add(offset / 2); keyFrameOffsetsDiv2.add(offset / 2);
for (AviTrack seekTrack : aviTracks) { for (AviTrack seekTrack : aviTracks) {
if (seekTrack != null) { if (seekTrack != null) {
seekIndexes[seekTrack.id].add(seekTrack.chunks); seekIndexes[seekTrack.getId()].add(seekTrack.chunks);
} }
} }
} }
} }
keyFrameCounts[aviTrack.id]++; keyFrameCounts[aviTrack.getId()]++;
} }
aviTrack.chunks++; aviTrack.chunks++;
aviTrack.size+=size; aviTrack.size+=size;
} }
indexByteBuffer.compact(); indexByteBuffer.compact();
} }
if (videoTrack.chunks == keyFrameCounts[videoTrack.id]) { if (videoTrack.chunks == keyFrameCounts[videoTrack.getId()]) {
videoTrack.setKeyFrames(AviTrack.ALL_KEY_FRAMES); videoTrack.setKeyFrames(AviTrack.ALL_KEY_FRAMES);
} else { } else {
videoTrack.setKeyFrames(seekIndexes[videoId].getArray()); videoTrack.setKeyFrames(seekIndexes[videoId].getArray());

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.extractor.avi;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
@ -29,10 +30,8 @@ import java.util.Arrays;
*/ */
public class AviTrack { public class AviTrack {
public static final int[] ALL_KEY_FRAMES = new int[0]; public static final int[] ALL_KEY_FRAMES = new int[0];
public static int CHUNK_TYPE_VIDEO = ('d' << 16) | ('c' << 24);
final int id; public static int CHUNK_TYPE_AUDIO = ('w' << 16) | ('b' << 24);
final @C.TrackType int trackType;
@NonNull @NonNull
LinearClock clock; LinearClock clock;
@ -57,34 +56,22 @@ public class AviTrack {
transient int chunkSize; transient int chunkSize;
transient int chunkRemaining; transient int chunkRemaining;
private static int getChunkIdLower(int id) { @VisibleForTesting
static int getChunkIdLower(int id) {
int tens = id / 10; int tens = id / 10;
int ones = id % 10; int ones = id % 10;
return ('0' + tens) | (('0' + ones) << 8); return ('0' + tens) | (('0' + ones) << 8);
} }
public static int getVideoChunkId(int id) { AviTrack(int id, int chunkType, @NonNull LinearClock clock,
return getChunkIdLower(id) | ('d' << 16) | ('c' << 24);
}
public static int getAudioChunkId(int id) {
return getChunkIdLower(id) | ('w' << 16) | ('b' << 24);
}
AviTrack(int id, @C.TrackType int trackType, @NonNull LinearClock clock,
@NonNull TrackOutput trackOutput) { @NonNull TrackOutput trackOutput) {
this.id = id; this.chunkId = getChunkIdLower(id) | chunkType;
this.clock = clock; this.clock = clock;
this.trackType = trackType;
this.trackOutput = trackOutput; this.trackOutput = trackOutput;
if (isVideo()) { if (isVideo()) {
chunkId = getVideoChunkId(id);
chunkIdAlt = getChunkIdLower(id) | ('d' << 16) | ('b' << 24); chunkIdAlt = getChunkIdLower(id) | ('d' << 16) | ('b' << 24);
} else if (isAudio()) {
chunkId = getAudioChunkId(id);
chunkIdAlt = 0xffff;
} else { } else {
throw new IllegalArgumentException("Unknown Track Type: " + trackType); chunkIdAlt = -1;
} }
} }
@ -118,11 +105,11 @@ public class AviTrack {
} }
public boolean isVideo() { public boolean isVideo() {
return trackType == C.TRACK_TYPE_VIDEO; return (chunkId & CHUNK_TYPE_VIDEO) == CHUNK_TYPE_VIDEO;
} }
public boolean isAudio() { public boolean isAudio() {
return trackType == C.TRACK_TYPE_AUDIO; return (chunkId & CHUNK_TYPE_AUDIO) == CHUNK_TYPE_AUDIO;
} }
public boolean newChunk(int tag, int size, ExtractorInput input) throws IOException { public boolean newChunk(int tag, int size, ExtractorInput input) throws IOException {
@ -169,4 +156,8 @@ public class AviTrack {
//Log.d(AviExtractor.TAG, "Frame: " + (isVideo()? 'V' : 'A') + " us=" + clock.getUs() + " size=" + size + " frame=" + clock.getIndex() + " key=" + isKeyFrame()); //Log.d(AviExtractor.TAG, "Frame: " + (isVideo()? 'V' : 'A') + " us=" + clock.getUs() + " size=" + size + " frame=" + clock.getIndex() + " key=" + isKeyFrame());
clock.advance(); clock.advance();
} }
public int getId() {
return ((chunkId >> 8) & 0xf) + ( chunkId & 0xf) * 10;
}
} }

View File

@ -473,7 +473,7 @@ public class AviExtractorTest {
final AviTrack aviTrack = aviExtractor.getVideoTrack(); final AviTrack aviTrack = aviExtractor.getVideoTrack();
final long position = DataHelper.MOVI_OFFSET + aviSeekMap.keyFrameOffsetsDiv2[1] * 2L; final long position = DataHelper.MOVI_OFFSET + aviSeekMap.keyFrameOffsetsDiv2[1] * 2L;
aviExtractor.seek(position, 0L); aviExtractor.seek(position, 0L);
Assert.assertEquals(aviSeekMap.seekIndexes[aviTrack.id][1], aviTrack.getClock().getIndex()); Assert.assertEquals(aviSeekMap.seekIndexes[aviTrack.getId()][1], aviTrack.getClock().getIndex());
} }
@Test @Test

View File

@ -76,7 +76,7 @@ public class DataHelper {
final ArrayList<Box> list = new ArrayList<>(2); final ArrayList<Box> list = new ArrayList<>(2);
list.add(streamHeaderBox); list.add(streamHeaderBox);
list.add(streamFormatBox); list.add(streamFormatBox);
return new ListBox((int)(streamHeaderBox.getSize() + streamFormatBox.getSize()), return new ListBox(streamHeaderBox.getSize() + streamFormatBox.getSize(),
ListBox.TYPE_STRL, list); ListBox.TYPE_STRL, list);
} }
@ -106,14 +106,14 @@ public class DataHelper {
public static AviTrack getVideoAviTrack(int sec) { public static AviTrack getVideoAviTrack(int sec) {
final FakeTrackOutput fakeTrackOutput = new FakeTrackOutput(false); final FakeTrackOutput fakeTrackOutput = new FakeTrackOutput(false);
return new AviTrack(0, C.TRACK_TYPE_VIDEO, return new AviTrack(0, AviTrack.CHUNK_TYPE_VIDEO,
new LinearClock(sec * 1_000_000L, sec * FPS), new LinearClock(sec * 1_000_000L, sec * FPS),
fakeTrackOutput); fakeTrackOutput);
} }
public static AviTrack getAudioAviTrack(int sec) { public static AviTrack getAudioAviTrack(int sec) {
final FakeTrackOutput fakeTrackOutput = new FakeTrackOutput(false); final FakeTrackOutput fakeTrackOutput = new FakeTrackOutput(false);
return new AviTrack(AUDIO_ID, C.TRACK_TYPE_AUDIO, return new AviTrack(AUDIO_ID, AviTrack.CHUNK_TYPE_AUDIO,
new LinearClock(sec * 1_000_000L, sec * FPS * AUDIO_PER_VIDEO), new LinearClock(sec * 1_000_000L, sec * FPS * AUDIO_PER_VIDEO),
fakeTrackOutput); fakeTrackOutput);
} }
@ -153,8 +153,8 @@ public class DataHelper {
*/ */
public static ByteBuffer getIndex(final int secs, final int keyFrameRate, int offset) { public static ByteBuffer getIndex(final int secs, final int keyFrameRate, int offset) {
final int videoFrames = secs * FPS; final int videoFrames = secs * FPS;
final int videoChunkId = AviTrack.getVideoChunkId(0); final int videoChunkId = AviTrack.CHUNK_TYPE_VIDEO | AviTrack.getChunkIdLower(0);
final int audioChunkId = AviTrack.getAudioChunkId(1); final int audioChunkId = AviTrack.CHUNK_TYPE_AUDIO | AviTrack.getChunkIdLower(1);
final ByteBuffer byteBuffer = AviExtractor.allocate((videoFrames + videoFrames*AUDIO_PER_VIDEO) * 16); final ByteBuffer byteBuffer = AviExtractor.allocate((videoFrames + videoFrames*AUDIO_PER_VIDEO) * 16);
for (int v=0;v<videoFrames;v++) { for (int v=0;v<videoFrames;v++) {