De-duplicate code for H264/H265 in MPEG-TS.
This commit is contained in:
parent
10efe7904d
commit
96c1e670c4
@ -18,7 +18,6 @@ package com.google.android.exoplayer.extractor.ts;
|
||||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
import com.google.android.exoplayer.util.NalUnitUtil;
|
||||
import com.google.android.exoplayer.util.ParsableBitArray;
|
||||
@ -46,26 +45,6 @@ import java.util.List;
|
||||
private static final int NAL_UNIT_TYPE_SPS = 7; // Sequence parameter set
|
||||
private static final int NAL_UNIT_TYPE_PPS = 8; // Picture parameter set
|
||||
private static final int NAL_UNIT_TYPE_AUD = 9; // Access unit delimiter
|
||||
private static final int EXTENDED_SAR = 0xFF;
|
||||
private static final float[] ASPECT_RATIO_IDC_VALUES = new float[] {
|
||||
1f /* Unspecified. Assume square */,
|
||||
1f,
|
||||
12f / 11f,
|
||||
10f / 11f,
|
||||
16f / 11f,
|
||||
40f / 33f,
|
||||
24f / 11f,
|
||||
20f / 11f,
|
||||
32f / 11f,
|
||||
80f / 33f,
|
||||
18f / 11f,
|
||||
15f / 11f,
|
||||
64f / 33f,
|
||||
160f / 99f,
|
||||
4f / 3f,
|
||||
3f / 2f,
|
||||
2f
|
||||
};
|
||||
|
||||
// State that should not be reset on seek.
|
||||
private boolean hasOutputFormat;
|
||||
@ -172,7 +151,7 @@ import java.util.List;
|
||||
// Notify the start of the next NAL unit.
|
||||
feedNalUnitTargetBuffersStart(nalUnitType);
|
||||
// Continue scanning the data.
|
||||
offset = nextNalUnitOffset + 4;
|
||||
offset = nextNalUnitOffset + 3;
|
||||
} else {
|
||||
feedNalUnitTargetBuffersData(dataArray, offset, limit);
|
||||
offset = limit;
|
||||
@ -312,14 +291,14 @@ import java.util.List;
|
||||
boolean aspectRatioInfoPresentFlag = bitArray.readBit();
|
||||
if (aspectRatioInfoPresentFlag) {
|
||||
int aspectRatioIdc = bitArray.readBits(8);
|
||||
if (aspectRatioIdc == EXTENDED_SAR) {
|
||||
if (aspectRatioIdc == NalUnitUtil.EXTENDED_SAR) {
|
||||
int sarWidth = bitArray.readBits(16);
|
||||
int sarHeight = bitArray.readBits(16);
|
||||
if (sarWidth != 0 && sarHeight != 0) {
|
||||
pixelWidthHeightRatio = (float) sarWidth / sarHeight;
|
||||
}
|
||||
} else if (aspectRatioIdc < ASPECT_RATIO_IDC_VALUES.length) {
|
||||
pixelWidthHeightRatio = ASPECT_RATIO_IDC_VALUES[aspectRatioIdc];
|
||||
} else if (aspectRatioIdc < NalUnitUtil.ASPECT_RATIO_IDC_VALUES.length) {
|
||||
pixelWidthHeightRatio = NalUnitUtil.ASPECT_RATIO_IDC_VALUES[aspectRatioIdc];
|
||||
} else {
|
||||
Log.w(TAG, "Unexpected aspect_ratio_idc value: " + aspectRatioIdc);
|
||||
}
|
||||
@ -394,96 +373,6 @@ import java.util.List;
|
||||
return limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A buffer that fills itself with data corresponding to a specific NAL unit, as it is
|
||||
* encountered in the stream.
|
||||
*/
|
||||
private static final class NalUnitTargetBuffer {
|
||||
|
||||
private final int targetType;
|
||||
|
||||
private boolean isFilling;
|
||||
private boolean isCompleted;
|
||||
|
||||
public byte[] nalData;
|
||||
public int nalLength;
|
||||
|
||||
public NalUnitTargetBuffer(int targetType, int initialCapacity) {
|
||||
this.targetType = targetType;
|
||||
// Initialize data, writing the known NAL prefix into the first four bytes.
|
||||
nalData = new byte[4 + initialCapacity];
|
||||
nalData[2] = 1;
|
||||
nalData[3] = (byte) targetType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffer, clearing any data that it holds.
|
||||
*/
|
||||
public void reset() {
|
||||
isFilling = false;
|
||||
isCompleted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the buffer currently holds a complete NAL unit of the target type.
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to indicate that a NAL unit has started.
|
||||
*
|
||||
* @param type The type of the NAL unit.
|
||||
*/
|
||||
public void startNalUnit(int type) {
|
||||
Assertions.checkState(!isFilling);
|
||||
isFilling = type == targetType;
|
||||
if (isFilling) {
|
||||
// Length is initially the length of the NAL prefix.
|
||||
nalLength = 4;
|
||||
isCompleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to pass stream data. The data passed should not include 4 byte NAL unit prefixes.
|
||||
*
|
||||
* @param data Holds the data being passed.
|
||||
* @param offset The offset of the data in {@code data}.
|
||||
* @param limit The limit (exclusive) of the data in {@code data}.
|
||||
*/
|
||||
public void appendToNalUnit(byte[] data, int offset, int limit) {
|
||||
if (!isFilling) {
|
||||
return;
|
||||
}
|
||||
int readLength = limit - offset;
|
||||
if (nalData.length < nalLength + readLength) {
|
||||
nalData = Arrays.copyOf(nalData, (nalLength + readLength) * 2);
|
||||
}
|
||||
System.arraycopy(data, offset, nalData, nalLength, readLength);
|
||||
nalLength += readLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to indicate that a NAL unit has ended.
|
||||
*
|
||||
* @param discardPadding The number of excess bytes that were passed to
|
||||
* {@link #appendToNalUnit(byte[], int, int)}, which should be discarded.
|
||||
* @return True if the ended NAL unit is of the target type. False otherwise.
|
||||
*/
|
||||
public boolean endNalUnit(int discardPadding) {
|
||||
if (!isFilling) {
|
||||
return false;
|
||||
}
|
||||
nalLength -= discardPadding;
|
||||
isFilling = false;
|
||||
isCompleted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A buffer specifically for IFR units that can be used to parse the IFR's slice type.
|
||||
*/
|
||||
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer.extractor.ts;
|
||||
import com.google.android.exoplayer.C;
|
||||
import com.google.android.exoplayer.MediaFormat;
|
||||
import com.google.android.exoplayer.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
import com.google.android.exoplayer.util.MimeTypes;
|
||||
import com.google.android.exoplayer.util.NalUnitUtil;
|
||||
import com.google.android.exoplayer.util.ParsableBitArray;
|
||||
@ -51,28 +50,6 @@ import java.util.Collections;
|
||||
private static final int PREFIX_SEI_NUT = 39;
|
||||
private static final int SUFFIX_SEI_NUT = 40;
|
||||
|
||||
// TODO: Deduplicate with H264Reader.
|
||||
private static final int EXTENDED_SAR = 0xFF;
|
||||
private static final float[] ASPECT_RATIO_IDC_VALUES = new float[] {
|
||||
1f /* Unspecified. Assume square */,
|
||||
1f,
|
||||
12f / 11f,
|
||||
10f / 11f,
|
||||
16f / 11f,
|
||||
40f / 33f,
|
||||
24f / 11f,
|
||||
20f / 11f,
|
||||
32f / 11f,
|
||||
80f / 33f,
|
||||
18f / 11f,
|
||||
15f / 11f,
|
||||
64f / 33f,
|
||||
160f / 99f,
|
||||
4f / 3f,
|
||||
3f / 2f,
|
||||
2f
|
||||
};
|
||||
|
||||
// State that should not be reset on seek.
|
||||
private boolean hasOutputFormat;
|
||||
|
||||
@ -321,14 +298,14 @@ import java.util.Collections;
|
||||
if (bitArray.readBit()) { // vui_parameters_present_flag
|
||||
if (bitArray.readBit()) { // aspect_ratio_info_present_flag
|
||||
int aspectRatioIdc = bitArray.readBits(8);
|
||||
if (aspectRatioIdc == EXTENDED_SAR) {
|
||||
if (aspectRatioIdc == NalUnitUtil.EXTENDED_SAR) {
|
||||
int sarWidth = bitArray.readBits(16);
|
||||
int sarHeight = bitArray.readBits(16);
|
||||
if (sarWidth != 0 && sarHeight != 0) {
|
||||
pixelWidthHeightRatio = (float) sarWidth / sarHeight;
|
||||
}
|
||||
} else if (aspectRatioIdc < ASPECT_RATIO_IDC_VALUES.length) {
|
||||
pixelWidthHeightRatio = ASPECT_RATIO_IDC_VALUES[aspectRatioIdc];
|
||||
} else if (aspectRatioIdc < NalUnitUtil.ASPECT_RATIO_IDC_VALUES.length) {
|
||||
pixelWidthHeightRatio = NalUnitUtil.ASPECT_RATIO_IDC_VALUES[aspectRatioIdc];
|
||||
} else {
|
||||
Log.w(TAG, "Unexpected aspect_ratio_idc value: " + aspectRatioIdc);
|
||||
}
|
||||
@ -464,92 +441,4 @@ import java.util.Collections;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Deduplicate with H264Reader.NalUnitTargetBuffer.
|
||||
/**
|
||||
* A buffer that fills itself with data corresponding to a specific NAL unit, as it is
|
||||
* encountered in the stream.
|
||||
*/
|
||||
private static final class NalUnitTargetBuffer {
|
||||
|
||||
private final int targetType;
|
||||
|
||||
private boolean isFilling;
|
||||
private boolean isCompleted;
|
||||
|
||||
public byte[] nalData;
|
||||
public int nalLength;
|
||||
|
||||
public NalUnitTargetBuffer(int targetType, int initialCapacity) {
|
||||
this.targetType = targetType;
|
||||
nalData = new byte[5 + initialCapacity];
|
||||
nalData[2] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffer, clearing any data that it holds.
|
||||
*/
|
||||
public void reset() {
|
||||
isFilling = false;
|
||||
isCompleted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the buffer currently holds a complete NAL unit of the target type.
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to indicate that a NAL unit has started.
|
||||
*
|
||||
* @param type The type of the NAL unit.
|
||||
*/
|
||||
public void startNalUnit(int type) {
|
||||
Assertions.checkState(!isFilling);
|
||||
isFilling = type == targetType;
|
||||
if (isFilling) {
|
||||
nalLength = 3;
|
||||
isCompleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to pass stream data. The data passed should not include 4 byte NAL unit prefixes.
|
||||
*
|
||||
* @param data Holds the data being passed.
|
||||
* @param offset The offset of the data in {@code data}.
|
||||
* @param limit The limit (exclusive) of the data in {@code data}.
|
||||
*/
|
||||
public void appendToNalUnit(byte[] data, int offset, int limit) {
|
||||
if (!isFilling) {
|
||||
return;
|
||||
}
|
||||
int readLength = limit - offset;
|
||||
if (nalData.length < nalLength + readLength) {
|
||||
nalData = Arrays.copyOf(nalData, (nalLength + readLength) * 2);
|
||||
}
|
||||
System.arraycopy(data, offset, nalData, nalLength, readLength);
|
||||
nalLength += readLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to indicate that a NAL unit has ended.
|
||||
*
|
||||
* @param discardPadding The number of excess bytes that were passed to
|
||||
* {@link #appendToNalUnit(byte[], int, int)}, which should be discarded.
|
||||
* @return True if the ended NAL unit is of the target type. False otherwise.
|
||||
*/
|
||||
public boolean endNalUnit(int discardPadding) {
|
||||
if (!isFilling) {
|
||||
return false;
|
||||
}
|
||||
nalLength -= discardPadding;
|
||||
isFilling = false;
|
||||
isCompleted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.ts;
|
||||
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A buffer that fills itself with data corresponding to a specific NAL unit, as it is
|
||||
* encountered in the stream.
|
||||
*/
|
||||
/* package */ final class NalUnitTargetBuffer {
|
||||
|
||||
private final int targetType;
|
||||
|
||||
private boolean isFilling;
|
||||
private boolean isCompleted;
|
||||
|
||||
public byte[] nalData;
|
||||
public int nalLength;
|
||||
|
||||
public NalUnitTargetBuffer(int targetType, int initialCapacity) {
|
||||
this.targetType = targetType;
|
||||
|
||||
// Initialize data with a start code in the first three bytes.
|
||||
nalData = new byte[3 + initialCapacity];
|
||||
nalData[2] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffer, clearing any data that it holds.
|
||||
*/
|
||||
public void reset() {
|
||||
isFilling = false;
|
||||
isCompleted = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the buffer currently holds a complete NAL unit of the target type.
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return isCompleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to indicate that a NAL unit has started.
|
||||
*
|
||||
* @param type The type of the NAL unit.
|
||||
*/
|
||||
public void startNalUnit(int type) {
|
||||
Assertions.checkState(!isFilling);
|
||||
isFilling = type == targetType;
|
||||
if (isFilling) {
|
||||
// Skip the three byte start code when writing data.
|
||||
nalLength = 3;
|
||||
isCompleted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to pass stream data. The data passed should not include the 3 byte start code.
|
||||
*
|
||||
* @param data Holds the data being passed.
|
||||
* @param offset The offset of the data in {@code data}.
|
||||
* @param limit The limit (exclusive) of the data in {@code data}.
|
||||
*/
|
||||
public void appendToNalUnit(byte[] data, int offset, int limit) {
|
||||
if (!isFilling) {
|
||||
return;
|
||||
}
|
||||
int readLength = limit - offset;
|
||||
if (nalData.length < nalLength + readLength) {
|
||||
nalData = Arrays.copyOf(nalData, (nalLength + readLength) * 2);
|
||||
}
|
||||
System.arraycopy(data, offset, nalData, nalLength, readLength);
|
||||
nalLength += readLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked to indicate that a NAL unit has ended.
|
||||
*
|
||||
* @param discardPadding The number of excess bytes that were passed to
|
||||
* {@link #appendToNalUnit(byte[], int, int)}, which should be discarded.
|
||||
* @return True if the ended NAL unit is of the target type. False otherwise.
|
||||
*/
|
||||
public boolean endNalUnit(int discardPadding) {
|
||||
if (!isFilling) {
|
||||
return false;
|
||||
}
|
||||
nalLength -= discardPadding;
|
||||
isFilling = false;
|
||||
isCompleted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -25,6 +25,29 @@ public final class NalUnitUtil {
|
||||
/** Four initial bytes that must prefix NAL units for decoding. */
|
||||
public static final byte[] NAL_START_CODE = new byte[] {0, 0, 0, 1};
|
||||
|
||||
/** Value for aspect_ratio_idc indicating an extended aspect ratio, in H.264 and H.265 SPSs. */
|
||||
public static final int EXTENDED_SAR = 0xFF;
|
||||
/** Aspect ratios indexed by aspect_ratio_idc, in H.264 and H.265 SPSs. */
|
||||
public static final float[] ASPECT_RATIO_IDC_VALUES = new float[] {
|
||||
1f /* Unspecified. Assume square */,
|
||||
1f,
|
||||
12f / 11f,
|
||||
10f / 11f,
|
||||
16f / 11f,
|
||||
40f / 33f,
|
||||
24f / 11f,
|
||||
20f / 11f,
|
||||
32f / 11f,
|
||||
80f / 33f,
|
||||
18f / 11f,
|
||||
15f / 11f,
|
||||
64f / 33f,
|
||||
160f / 99f,
|
||||
4f / 3f,
|
||||
3f / 2f,
|
||||
2f
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces length prefixes of NAL units in {@code buffer} with start code prefixes, within the
|
||||
* {@code size} bytes preceding the buffer's position.
|
||||
@ -79,7 +102,7 @@ public final class NalUnitUtil {
|
||||
/**
|
||||
* Finds the first NAL unit in {@code data}.
|
||||
* <p>
|
||||
* If {@code prefixFlags} is null then the first four bytes of a NAL unit must be entirely
|
||||
* If {@code prefixFlags} is null then the first three bytes of a NAL unit must be entirely
|
||||
* contained within the part of the array being searched in order for it to be found.
|
||||
* <p>
|
||||
* When {@code prefixFlags} is non-null, this method supports finding NAL units whose first four
|
||||
@ -121,9 +144,8 @@ public final class NalUnitUtil {
|
||||
}
|
||||
|
||||
int limit = endOffset - 1;
|
||||
// We're looking for the NAL unit start code prefix 0x000001, followed by a byte that matches
|
||||
// the specified type. The value of i tracks the index of the third byte in the four bytes
|
||||
// being examined.
|
||||
// We're looking for the NAL unit start code prefix 0x000001. The value of i tracks the index of
|
||||
// the third byte.
|
||||
for (int i = startOffset + 2; i < limit; i += 3) {
|
||||
if ((data[i] & 0xFE) != 0) {
|
||||
// There isn't a NAL prefix here, or at the next two positions. Do nothing and let the
|
||||
@ -146,10 +168,10 @@ public final class NalUnitUtil {
|
||||
? (data[endOffset - 3] == 0 && data[endOffset - 2] == 0 && data[endOffset - 1] == 1)
|
||||
: length == 2 ? (prefixFlags[2] && data[endOffset - 2] == 0 && data[endOffset - 1] == 1)
|
||||
: (prefixFlags[1] && data[endOffset - 1] == 1);
|
||||
// True if the last three bytes in the data seen so far are {0,0}.
|
||||
// True if the last two bytes in the data seen so far are {0,0}.
|
||||
prefixFlags[1] = length > 1 ? data[endOffset - 2] == 0 && data[endOffset - 1] == 0
|
||||
: prefixFlags[2] && data[endOffset - 1] == 0;
|
||||
// True if the last three bytes in the data seen so far are {0}.
|
||||
// True if the last byte in the data seen so far is {0}.
|
||||
prefixFlags[2] = data[endOffset - 1] == 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user