mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Refactor, remove dead code
This commit is contained in:
parent
8d90498f79
commit
d9afe5105b
8 changed files with 37 additions and 173 deletions
|
|
@ -26,8 +26,23 @@ import java.util.Map;
|
||||||
* https://docs.microsoft.com/en-us/windows/win32/directshow/avi-riff-file-reference
|
* https://docs.microsoft.com/en-us/windows/win32/directshow/avi-riff-file-reference
|
||||||
*/
|
*/
|
||||||
public class AviExtractor implements Extractor {
|
public class AviExtractor implements Extractor {
|
||||||
|
static final long UINT_MASK = 0xffffffffL;
|
||||||
|
|
||||||
|
static long getUInt(ByteBuffer byteBuffer) {
|
||||||
|
return byteBuffer.getInt() & UINT_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
static String toString(int tag) {
|
||||||
|
final StringBuilder sb = new StringBuilder(4);
|
||||||
|
for (int i=0;i<4;i++) {
|
||||||
|
sb.append((char)(tag & 0xff));
|
||||||
|
tag >>=8;
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
static final String TAG = "AviExtractor";
|
static final String TAG = "AviExtractor";
|
||||||
static final int KEY_FRAME_MASK = Integer.MIN_VALUE;
|
|
||||||
private static final int PEEK_BYTES = 28;
|
private static final int PEEK_BYTES = 28;
|
||||||
|
|
||||||
private static final int STATE_READ_TRACKS = 0;
|
private static final int STATE_READ_TRACKS = 0;
|
||||||
|
|
@ -39,8 +54,8 @@ public class AviExtractor implements Extractor {
|
||||||
private static final int AVIIF_KEYFRAME = 16;
|
private static final int AVIIF_KEYFRAME = 16;
|
||||||
|
|
||||||
|
|
||||||
static final int RIFF = AviUtil.toInt(new byte[]{'R','I','F','F'});
|
static final int RIFF = 'R' | ('I' << 8) | ('F' << 16) | ('F' << 24);
|
||||||
static final int AVI_ = AviUtil.toInt(new byte[]{'A','V','I',' '});
|
static final int AVI_ = 'A' | ('V' << 8) | ('I' << 16) | (' ' << 24);
|
||||||
//Stream List
|
//Stream List
|
||||||
static final int STRL = 's' | ('t' << 8) | ('r' << 16) | ('l' << 24);
|
static final int STRL = 's' | ('t' << 8) | ('r' << 16) | ('l' << 24);
|
||||||
//movie data box
|
//movie data box
|
||||||
|
|
@ -103,7 +118,7 @@ public class AviExtractor implements Extractor {
|
||||||
if (riff != AviExtractor.RIFF) {
|
if (riff != AviExtractor.RIFF) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
long reportedLen = AviUtil.getUInt(byteBuffer) + byteBuffer.position();
|
long reportedLen = getUInt(byteBuffer) + byteBuffer.position();
|
||||||
final long inputLen = input.getLength();
|
final long inputLen = input.getLength();
|
||||||
if (inputLen != C.LENGTH_UNSET && inputLen != reportedLen) {
|
if (inputLen != C.LENGTH_UNSET && inputLen != reportedLen) {
|
||||||
Log.w(TAG, "Header length doesn't match stream length");
|
Log.w(TAG, "Header length doesn't match stream length");
|
||||||
|
|
@ -136,7 +151,7 @@ public class AviExtractor implements Extractor {
|
||||||
if (riff != AviExtractor.RIFF) {
|
if (riff != AviExtractor.RIFF) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
long reportedLen = AviUtil.getUInt(byteBuffer) + byteBuffer.position();
|
long reportedLen = getUInt(byteBuffer) + byteBuffer.position();
|
||||||
final long inputLen = input.getLength();
|
final long inputLen = input.getLength();
|
||||||
if (inputLen != C.LENGTH_UNSET && inputLen != reportedLen) {
|
if (inputLen != C.LENGTH_UNSET && inputLen != reportedLen) {
|
||||||
Log.w(TAG, "Header length doesn't match stream length");
|
Log.w(TAG, "Header length doesn't match stream length");
|
||||||
|
|
@ -177,18 +192,15 @@ public class AviExtractor implements Extractor {
|
||||||
if (headerList == null) {
|
if (headerList == null) {
|
||||||
throw new IOException("AVI Header List not found");
|
throw new IOException("AVI Header List not found");
|
||||||
}
|
}
|
||||||
final List<Box> headerChildren = headerList.getChildren();
|
aviHeader = headerList.getChild(AviHeaderBox.class);
|
||||||
aviHeader = AviUtil.getBox(headerChildren, AviHeaderBox.class);
|
|
||||||
if (aviHeader == null) {
|
if (aviHeader == null) {
|
||||||
throw new IOException("AviHeader not found");
|
throw new IOException("AviHeader not found");
|
||||||
}
|
}
|
||||||
//This is usually wrong, so it will be overwritten by video if present
|
//This is usually wrong, so it will be overwritten by video if present
|
||||||
durationUs = aviHeader.getFrames() * (long)aviHeader.getMicroSecPerFrame();
|
durationUs = aviHeader.getFrames() * (long)aviHeader.getMicroSecPerFrame();
|
||||||
headerChildren.remove(aviHeader);
|
|
||||||
//headerChildren should only be Stream Lists now
|
|
||||||
|
|
||||||
int streamId = 0;
|
int streamId = 0;
|
||||||
for (Box box : headerChildren) {
|
for (Box box : headerList.getChildren()) {
|
||||||
if (box instanceof ListBox && ((ListBox) box).getListType() == STRL) {
|
if (box instanceof ListBox && ((ListBox) box).getListType() == STRL) {
|
||||||
final ListBox streamList = (ListBox) box;
|
final ListBox streamList = (ListBox) box;
|
||||||
final List<Box> streamChildren = streamList.getChildren();
|
final List<Box> streamChildren = streamList.getChildren();
|
||||||
|
|
@ -238,7 +250,6 @@ public class AviExtractor implements Extractor {
|
||||||
builder.setChannelCount(audioFormat.getChannels());
|
builder.setChannelCount(audioFormat.getChannels());
|
||||||
builder.setSampleRate(audioFormat.getSamplesPerSecond());
|
builder.setSampleRate(audioFormat.getSamplesPerSecond());
|
||||||
if (audioFormat.getFormatTag() == AudioFormat.WAVE_FORMAT_PCM) {
|
if (audioFormat.getFormatTag() == AudioFormat.WAVE_FORMAT_PCM) {
|
||||||
//TODO: Determine if this is LE or BE - Most likely LE
|
|
||||||
final short bps = audioFormat.getBitsPerSample();
|
final short bps = audioFormat.getBitsPerSample();
|
||||||
if (bps == 8) {
|
if (bps == 8) {
|
||||||
builder.setPcmEncoding(C.ENCODING_PCM_8BIT);
|
builder.setPcmEncoding(C.ENCODING_PCM_8BIT);
|
||||||
|
|
@ -268,7 +279,7 @@ public class AviExtractor implements Extractor {
|
||||||
ByteBuffer byteBuffer = allocate(12);
|
ByteBuffer byteBuffer = allocate(12);
|
||||||
input.readFully(byteBuffer.array(), 0,12);
|
input.readFully(byteBuffer.array(), 0,12);
|
||||||
final int tag = byteBuffer.getInt();
|
final int tag = byteBuffer.getInt();
|
||||||
final long size = byteBuffer.getInt() & AviUtil.UINT_MASK;
|
final long size = getUInt(byteBuffer);
|
||||||
final long position = input.getPosition();
|
final long position = input.getPosition();
|
||||||
//-4 because we over read for the LIST type
|
//-4 because we over read for the LIST type
|
||||||
long nextBox = position + size - 4;
|
long nextBox = position + size - 4;
|
||||||
|
|
@ -330,7 +341,7 @@ public class AviExtractor implements Extractor {
|
||||||
final AviTrack aviTrack = idTrackMap.get(id);
|
final AviTrack aviTrack = idTrackMap.get(id);
|
||||||
if (aviTrack == null) {
|
if (aviTrack == null) {
|
||||||
if (id != AviExtractor.REC_) {
|
if (id != AviExtractor.REC_) {
|
||||||
Log.w(TAG, "Unknown Track Type: " + AviUtil.toString(id));
|
Log.w(TAG, "Unknown Track Type: " + toString(id));
|
||||||
}
|
}
|
||||||
indexByteBuffer.position(indexByteBuffer.position() + 12);
|
indexByteBuffer.position(indexByteBuffer.position() + 12);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -413,7 +424,7 @@ public class AviExtractor implements Extractor {
|
||||||
} else {
|
} else {
|
||||||
seekPosition.position = input.getPosition() + sampleSize;
|
seekPosition.position = input.getPosition() + sampleSize;
|
||||||
if (id != JUNK) {
|
if (id != JUNK) {
|
||||||
Log.w(TAG, "Unknown tag=" + AviUtil.toString(id) + " pos=" + (input.getPosition() - 8)
|
Log.w(TAG, "Unknown tag=" + toString(id) + " pos=" + (input.getPosition() - 8)
|
||||||
+ " size=" + sampleSize + " moviEnd=" + moviEnd);
|
+ " size=" + sampleSize + " moviEnd=" + moviEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -470,7 +481,6 @@ public class AviExtractor implements Extractor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seek(long position, long timeUs) {
|
public void seek(long position, long timeUs) {
|
||||||
Log.d("Test", "Seek: pos=" + position + " us=" + timeUs);
|
|
||||||
if (position == 0) {
|
if (position == 0) {
|
||||||
if (moviOffset != 0) {
|
if (moviOffset != 0) {
|
||||||
resetFrames();
|
resetFrames();
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,6 @@ public class AviHeaderBox extends ResidentBox {
|
||||||
super(type, size, byteBuffer);
|
super(type, size, byteBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean assertType() {
|
|
||||||
return simpleAssert(AVIH);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasIndex() {
|
boolean hasIndex() {
|
||||||
return (getFlags() & AVIF_HASINDEX) > 0;
|
return (getFlags() & AVIF_HASINDEX) > 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package com.google.android.exoplayer2.extractor.avi;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AviUtil {
|
|
||||||
|
|
||||||
static final long UINT_MASK = 0xffffffffL;
|
|
||||||
|
|
||||||
static int toInt(byte[] bytes) {
|
|
||||||
int i = 0;
|
|
||||||
for (int b=bytes.length - 1;b>=0;b--) {
|
|
||||||
i <<=8;
|
|
||||||
i |= bytes[b];
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long getUInt(ByteBuffer byteBuffer) {
|
|
||||||
return byteBuffer.getInt() & UINT_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copy(ByteBuffer source, ByteBuffer dest, int bytes) {
|
|
||||||
final int inLimit = source.limit();
|
|
||||||
source.limit(source.position() + bytes);
|
|
||||||
dest.put(source);
|
|
||||||
source.limit(inLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ByteBuffer getByteBuffer(final ByteBuffer source, final int size,
|
|
||||||
final ExtractorInput input) throws IOException {
|
|
||||||
final ByteBuffer byteBuffer = AviExtractor.allocate(size);
|
|
||||||
if (size < source.remaining()) {
|
|
||||||
copy(source, byteBuffer, size);
|
|
||||||
} else {
|
|
||||||
final int copy = source.remaining();
|
|
||||||
copy(source, byteBuffer, copy);
|
|
||||||
int remaining = size - copy;
|
|
||||||
final int offset = byteBuffer.position() + byteBuffer.arrayOffset();
|
|
||||||
input.readFully(byteBuffer.array(), offset, remaining, false);
|
|
||||||
}
|
|
||||||
return byteBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
static String toString(int tag) {
|
|
||||||
final StringBuilder sb = new StringBuilder(4);
|
|
||||||
for (int i=0;i<4;i++) {
|
|
||||||
sb.append((char)(tag & 0xff));
|
|
||||||
tag >>=8;
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
static <T extends Box> T getBox(List<? extends Box> list, Class<T> clazz) {
|
|
||||||
for (Box box : list) {
|
|
||||||
if (box.getClass() == clazz) {
|
|
||||||
return (T)box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -13,11 +13,7 @@ public class Box {
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getSize() {
|
public long getSize() {
|
||||||
return size & AviUtil.UINT_MASK;
|
return size & AviExtractor.UINT_MASK;
|
||||||
}
|
|
||||||
|
|
||||||
public int getSizeInt() {
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
|
|
@ -28,8 +24,4 @@ public class Box {
|
||||||
return getType() == expected;
|
return getType() == expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean assertType() {
|
|
||||||
//Generic box, nothing to assert
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
package com.google.android.exoplayer2.extractor.avi;
|
package com.google.android.exoplayer2.extractor.avi;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
@ -16,25 +15,6 @@ public class BoxFactory {
|
||||||
return Arrays.binarySearch(types, type) < 0;
|
return Arrays.binarySearch(types, type) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ResidentBox createBox(final int type, final int size, final ByteBuffer byteBuffer) {
|
|
||||||
final ByteBuffer boxBuffer = AviExtractor.allocate(size);
|
|
||||||
AviUtil.copy(byteBuffer, boxBuffer, size);
|
|
||||||
//TODO: Deal with list
|
|
||||||
switch (type) {
|
|
||||||
case AviHeaderBox.AVIH:
|
|
||||||
return new AviHeaderBox(type, size, boxBuffer);
|
|
||||||
case StreamHeaderBox.STRH:
|
|
||||||
return new StreamHeaderBox(type, size, boxBuffer);
|
|
||||||
case StreamFormatBox.STRF:
|
|
||||||
return new StreamFormatBox(type, size, boxBuffer);
|
|
||||||
case StreamDataBox.STRD:
|
|
||||||
return new StreamDataBox(type, size, boxBuffer);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResidentBox createBoxImpl(final int type, final int size, final ByteBuffer boxBuffer) {
|
private ResidentBox createBoxImpl(final int type, final int size, final ByteBuffer boxBuffer) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AviHeaderBox.AVIH:
|
case AviHeaderBox.AVIH:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.google.android.exoplayer2.extractor.avi;
|
package com.google.android.exoplayer2.extractor.avi;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
@ -29,26 +30,20 @@ public class ListBox extends Box {
|
||||||
return listType;
|
return listType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
boolean assertType() {
|
|
||||||
return simpleAssert(LIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public List<Box> getChildren() {
|
public List<Box> getChildren() {
|
||||||
return new ArrayList<>(children);
|
return new ArrayList<>(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static List<ResidentBox> realizeChildren(final ByteBuffer byteBuffer, final BoxFactory boxFactory) {
|
@Nullable
|
||||||
// final List<ResidentBox> list = new ArrayList<>();
|
public <T extends Box> T getChild(Class<T> c) {
|
||||||
// while (byteBuffer.hasRemaining()) {
|
for (Box box : children) {
|
||||||
// final int type = byteBuffer.getInt();
|
if (box.getClass() == c) {
|
||||||
// final int size = byteBuffer.getInt();
|
return (T)box;
|
||||||
// final ResidentBox residentBox = boxFactory.createBox(type, size, byteBuffer);
|
}
|
||||||
// list.add(residentBox);
|
}
|
||||||
// }
|
return null;
|
||||||
// return list;
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assume the input is pointing to the list type
|
* Assume the input is pointing to the list type
|
||||||
|
|
|
||||||
|
|
@ -24,46 +24,6 @@ public class ResidentBox extends Box {
|
||||||
this.byteBuffer = byteBuffer;
|
this.byteBuffer = byteBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* List is not yet populated
|
|
||||||
* @param byteBuffer
|
|
||||||
* @return
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static <T extends ResidentBox> T getInstance(final ByteBuffer byteBuffer,
|
|
||||||
ExtractorInput input, Class<T> boxClass) throws IOException {
|
|
||||||
if (byteBuffer.remaining() < 8) {
|
|
||||||
//Should not happen
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
final int type = byteBuffer.getInt();
|
|
||||||
final long size = AviUtil.getUInt(byteBuffer);
|
|
||||||
if (size > MAX_RESIDENT) {
|
|
||||||
throw new BufferOverflowException();
|
|
||||||
}
|
|
||||||
final ByteBuffer boxBuffer = AviUtil.getByteBuffer(byteBuffer, (int)size, input);
|
|
||||||
return newInstance(type, (int)size, boxBuffer, boxClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static <T extends ResidentBox> T newInstance(int type, int size, ByteBuffer boxBuffer,
|
|
||||||
Class<T> boxClass) {
|
|
||||||
try {
|
|
||||||
final Constructor<T> constructor =
|
|
||||||
boxClass.getDeclaredConstructor(int.class, int.class, ByteBuffer.class);
|
|
||||||
T box = constructor.newInstance(type, size, boxBuffer);
|
|
||||||
if (!box.assertType()) {
|
|
||||||
Log.e(TAG, "Expected " + AviUtil.toString(type) + " got " + AviUtil.toString(box.getType()));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return box;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Create box failed " + AviUtil.toString(type));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns shallow copy of this ByteBuffer with the position at 0
|
* Returns shallow copy of this ByteBuffer with the position at 0
|
||||||
* @return
|
* @return
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ public class StreamHeaderBox extends ResidentBox {
|
||||||
return byteBuffer.getInt(28);
|
return byteBuffer.getInt(28);
|
||||||
}
|
}
|
||||||
public long getLength() {
|
public long getLength() {
|
||||||
return byteBuffer.getInt(32) & AviUtil.UINT_MASK;
|
return byteBuffer.getInt(32) & AviExtractor.UINT_MASK;
|
||||||
}
|
}
|
||||||
//36 - dwSuggestedBufferSize
|
//36 - dwSuggestedBufferSize
|
||||||
//40 - dwQuality
|
//40 - dwQuality
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue